aboutsummaryrefslogtreecommitdiffhomepage
path: root/inc/3rdparty
diff options
context:
space:
mode:
authorThomas Citharel <tcit@tcit.fr>2015-02-18 19:17:31 +0100
committerThomas Citharel <tcit@tcit.fr>2015-02-18 19:17:31 +0100
commit4b1fa4c2febc7abbc6da3d65e4e760949a55843c (patch)
treea93ec906dbb03ec70e9cdc5dc876392c6d758e97 /inc/3rdparty
parent364953ede585b75fb29dc94b1c5f853053eaed0b (diff)
parentdf89c6f71adebfdb754ec3eb2fd775d8efbdb280 (diff)
downloadwallabag-4b1fa4c2febc7abbc6da3d65e4e760949a55843c.tar.gz
wallabag-4b1fa4c2febc7abbc6da3d65e4e760949a55843c.tar.zst
wallabag-4b1fa4c2febc7abbc6da3d65e4e760949a55843c.zip
Merge pull request #1081 from wallabag/dev1.9
Version 1.9.0
Diffstat (limited to 'inc/3rdparty')
-rw-r--r--inc/3rdparty/libraries/MOBIClass/CharacterEntities.php413
-rw-r--r--inc/3rdparty/libraries/MOBIClass/ContentProvider.php22
-rw-r--r--inc/3rdparty/libraries/MOBIClass/EXTHHelper.php132
-rw-r--r--inc/3rdparty/libraries/MOBIClass/FileByte.php41
-rw-r--r--inc/3rdparty/libraries/MOBIClass/FileDate.php40
-rw-r--r--inc/3rdparty/libraries/MOBIClass/FileElement.php89
-rw-r--r--inc/3rdparty/libraries/MOBIClass/FileInt.php40
-rw-r--r--inc/3rdparty/libraries/MOBIClass/FileObject.php168
-rw-r--r--inc/3rdparty/libraries/MOBIClass/FileRecord.php46
-rw-r--r--inc/3rdparty/libraries/MOBIClass/FileShort.php41
-rw-r--r--inc/3rdparty/libraries/MOBIClass/FileString.php83
-rw-r--r--inc/3rdparty/libraries/MOBIClass/FileTri.php41
-rw-r--r--inc/3rdparty/libraries/MOBIClass/Http.php171
-rw-r--r--inc/3rdparty/libraries/MOBIClass/ImageHandler.php40
-rw-r--r--inc/3rdparty/libraries/MOBIClass/MOBI.php192
-rw-r--r--inc/3rdparty/libraries/MOBIClass/MOBIFile.php157
-rw-r--r--inc/3rdparty/libraries/MOBIClass/MultipleFileHandler.php136
-rw-r--r--inc/3rdparty/libraries/MOBIClass/OnlineArticle.php116
-rw-r--r--inc/3rdparty/libraries/MOBIClass/PalmRecord.php136
-rw-r--r--inc/3rdparty/libraries/MOBIClass/Prc.php97
-rw-r--r--inc/3rdparty/libraries/MOBIClass/PreprocessedArticle.php89
-rw-r--r--inc/3rdparty/libraries/MOBIClass/RecognizeURL.php16
-rw-r--r--inc/3rdparty/libraries/MOBIClass/Record.php96
-rw-r--r--inc/3rdparty/libraries/MOBIClass/RecordFactory.php115
-rw-r--r--inc/3rdparty/libraries/MOBIClass/Settings.php97
-rw-r--r--inc/3rdparty/libraries/MOBIClass/constants.php11
-rw-r--r--inc/3rdparty/libraries/MOBIClass/downloaders/FanFictionNet.php125
-rw-r--r--inc/3rdparty/libraries/MOBIClass/http_build_url.php94
-rwxr-xr-xinc/3rdparty/libraries/readability/Readability.php5
-rw-r--r--inc/3rdparty/libraries/tcpdf/CHANGELOG.TXT2860
-rw-r--r--inc/3rdparty/libraries/tcpdf/LICENSE.TXT858
-rw-r--r--inc/3rdparty/libraries/tcpdf/README.TXT115
-rw-r--r--inc/3rdparty/libraries/tcpdf/composer.json40
-rw-r--r--inc/3rdparty/libraries/tcpdf/config/tcpdf_config.php227
-rw-r--r--inc/3rdparty/libraries/tcpdf/fonts/courier.php12
-rw-r--r--inc/3rdparty/libraries/tcpdf/fonts/courierb.php12
-rw-r--r--inc/3rdparty/libraries/tcpdf/fonts/courierbi.php12
-rw-r--r--inc/3rdparty/libraries/tcpdf/fonts/courieri.php12
-rw-r--r--inc/3rdparty/libraries/tcpdf/fonts/helvetica.php13
-rw-r--r--inc/3rdparty/libraries/tcpdf/fonts/helveticab.php12
-rw-r--r--inc/3rdparty/libraries/tcpdf/fonts/helveticabi.php12
-rw-r--r--inc/3rdparty/libraries/tcpdf/fonts/helveticai.php12
-rw-r--r--inc/3rdparty/libraries/tcpdf/fonts/symbol.php12
-rw-r--r--inc/3rdparty/libraries/tcpdf/fonts/times.php12
-rw-r--r--inc/3rdparty/libraries/tcpdf/fonts/timesb.php12
-rw-r--r--inc/3rdparty/libraries/tcpdf/fonts/timesbi.php12
-rw-r--r--inc/3rdparty/libraries/tcpdf/fonts/timesi.php12
-rw-r--r--inc/3rdparty/libraries/tcpdf/fonts/zapfdingbats.php12
-rw-r--r--inc/3rdparty/libraries/tcpdf/include/barcodes/datamatrix.php1176
-rw-r--r--inc/3rdparty/libraries/tcpdf/include/barcodes/pdf417.php996
-rw-r--r--inc/3rdparty/libraries/tcpdf/include/barcodes/qrcode.php2866
-rw-r--r--inc/3rdparty/libraries/tcpdf/include/sRGB.iccbin0 -> 6922 bytes
-rw-r--r--inc/3rdparty/libraries/tcpdf/include/tcpdf_colors.php462
-rw-r--r--inc/3rdparty/libraries/tcpdf/include/tcpdf_filters.php481
-rw-r--r--inc/3rdparty/libraries/tcpdf/include/tcpdf_font_data.php18447
-rw-r--r--inc/3rdparty/libraries/tcpdf/include/tcpdf_fonts.php2583
-rw-r--r--inc/3rdparty/libraries/tcpdf/include/tcpdf_images.php355
-rw-r--r--inc/3rdparty/libraries/tcpdf/include/tcpdf_static.php2851
-rw-r--r--inc/3rdparty/libraries/tcpdf/tcpdf.php24579
-rw-r--r--inc/3rdparty/libraries/tcpdf/tcpdf_autoconfig.php242
-rw-r--r--inc/3rdparty/libraries/tcpdf/tcpdf_barcodes_1d.php2303
-rw-r--r--inc/3rdparty/libraries/tcpdf/tcpdf_barcodes_2d.php349
-rw-r--r--inc/3rdparty/libraries/tcpdf/tcpdf_import.php104
-rw-r--r--inc/3rdparty/libraries/tcpdf/tcpdf_parser.php811
-rw-r--r--inc/3rdparty/libraries/tcpdf/tools/.htaccess1
-rw-r--r--inc/3rdparty/libraries/tcpdf/tools/convert_fonts_examples.txt28
-rwxr-xr-xinc/3rdparty/libraries/tcpdf/tools/tcpdf_addfont.php269
-rwxr-xr-xinc/3rdparty/makefulltextfeed.php2
-rwxr-xr-xinc/3rdparty/site_config/standard/gist.github.com.txt8
-rw-r--r--inc/3rdparty/site_config/standard/jungle-world.com.txt3
-rwxr-xr-xinc/3rdparty/site_config/standard/toolinux.com.txt5
71 files changed, 66032 insertions, 7 deletions
diff --git a/inc/3rdparty/libraries/MOBIClass/CharacterEntities.php b/inc/3rdparty/libraries/MOBIClass/CharacterEntities.php
new file mode 100644
index 00000000..de896f87
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/CharacterEntities.php
@@ -0,0 +1,413 @@
1<?php
2
3/**
4 * Description of CharacterEntities
5 *
6 * @author Sander
7 */
8class CharacterEntities {
9 public static function convert($str){
10 //Assume the encoding is UTF-8 -> output is UTF-8
11 return $str;
12 //return utf8_encode($str);
13 //Convert to CP1252
14 list($from, $to) = CharacterEntities::generateTables();
15 return str_replace($from, $to, $str);
16 }
17
18 private static function generateTables(){
19 $from = array();
20 $to = array();
21
22 for($i = 0; $i < 256; $i++){
23 $from[$i] = $to[$i] = chr($i);
24 }
25
26 $from[0x80] = "€";
27 $from[0x82] = "‚";
28 $from[0x83] = "ƒ";
29 $from[0x84] = "„";
30 $from[0x85] = "…";
31 $from[0x86] = "†";
32 $from[0x87] = "‡";
33 $from[0x88] = "ˆ";
34 $from[0x89] = "‰";
35 $from[0x8A] = "Š";
36 $from[0x8B] = "‹";
37 $from[0x8C] = "Œ";
38 $from[0x8E] = "Ž";
39
40 $from[0x91] = "‘";
41 $from[0x92] = "’";
42 $from[0x93] = "“";
43 $from[0x94] = "”";
44 $from[0x95] = "•";
45 $from[0x96] = "–";
46 $from[0x97] = "—";
47 $from[0x98] = "˜";
48 $from[0x99] = "™";
49 $from[0x9A] = "š";
50 $from[0x9B] = "›";
51 $from[0x9C] = "œ";
52 $from[0x9E] = "ž";
53 $from[0x9F] = "Ÿ";
54
55 $from[0xA1] = "¡";
56 $from[0xA2] = "¢";
57 $from[0xA3] = "£";
58 $from[0xA4] = "¤";
59 $from[0xA5] = "¥";
60 $from[0xA6] = "¦";
61 $from[0xA7] = "§";
62 $from[0xA8] = "¨";
63 $from[0xA9] = "©";
64 $from[0xAA] = "ª";
65 $from[0xAB] = "«";
66 $from[0xAC] = "¬";
67 $from[0xAE] = "®";
68 $from[0xAF] = "¯";
69
70 $from[0xB0] = "°";
71 $from[0xB1] = "±";
72 $from[0xB2] = "²";
73 $from[0xB3] = "³";
74 $from[0xB4] = "´";
75 $from[0xB5] = "µ";
76 $from[0xB6] = "¶";
77 $from[0xB7] = "·";
78 $from[0xB8] = "¸";
79 $from[0xB9] = "¹";
80 $from[0xBA] = "º";
81 $from[0xBB] = "»";
82 $from[0xBC] = "¼";
83 $from[0xBD] = "½";
84 $from[0xBE] = "¾";
85 $from[0xBF] = "¿";
86
87 $from[0xC0] = "À";
88 $from[0xC1] = "Á";
89 $from[0xC2] = "Â";
90 $from[0xC3] = "Ã";
91 $from[0xC4] = "Ä";
92 $from[0xC5] = "Å";
93 $from[0xC6] = "Æ";
94 $from[0xC7] = "Ç";
95 $from[0xC8] = "È";
96 $from[0xC9] = "É";
97 $from[0xCA] = "Ê";
98 $from[0xCB] = "Ë";
99 $from[0xCC] = "Ì";
100 $from[0xCD] = "Í";
101 $from[0xCE] = "Î";
102 $from[0xCF] = "Ï";
103
104 $from[0xD0] = "Ð";
105 $from[0xD1] = "Ñ";
106 $from[0xD2] = "Ò";
107 $from[0xD3] = "Ó";
108 $from[0xD4] = "Ô";
109 $from[0xD5] = "Õ";
110 $from[0xD6] = "Ö";
111 $from[0xD7] = "×";
112 $from[0xD8] = "Ø";
113 $from[0xD9] = "Ù";
114 $from[0xDA] = "Ú";
115 $from[0xDB] = "Û";
116 $from[0xDC] = "Ü";
117 $from[0xDD] = "Ý";
118 $from[0xDE] = "Þ";
119 $from[0xDF] = "ß";
120
121 $from[0xE0] = "à";
122 $from[0xE1] = "á";
123 $from[0xE2] = "â";
124 $from[0xE3] = "ã";
125 $from[0xE4] = "ä";
126 $from[0xE5] = "å";
127 $from[0xE6] = "æ";
128 $from[0xE7] = "ç";
129 $from[0xE8] = "è";
130 $from[0xE9] = "é";
131 $from[0xEA] = "ê";
132 $from[0xEB] = "ë";
133 $from[0xEC] = "ì";
134 $from[0xED] = "í";
135 $from[0xEE] = "î";
136 $from[0xEF] = "ï";
137
138 $from[0xF0] = "ð";
139 $from[0xF1] = "ñ";
140 $from[0xF2] = "ò";
141 $from[0xF3] = "ó";
142 $from[0xF4] = "ô";
143 $from[0xF5] = "õ";
144 $from[0xF6] = "ö";
145 $from[0xF7] = "÷";
146 $from[0xF8] = "ø";
147 $from[0xF9] = "ù";
148 $from[0xFA] = "ú";
149 $from[0xFB] = "û";
150 $from[0xFC] = "ü";
151 $from[0xFD] = "ý";
152 $from[0xFE] = "þ";
153 $from[0xFF] = "ÿ";
154
155
156 return array($from, $to);
157 }
158 /*
159 00 = U+0000 : NULL
16001 = U+0001 : START OF HEADING
16102 = U+0002 : START OF TEXT
16203 = U+0003 : END OF TEXT
16304 = U+0004 : END OF TRANSMISSION
16405 = U+0005 : ENQUIRY
16506 = U+0006 : ACKNOWLEDGE
16607 = U+0007 : BELL
16708 = U+0008 : BACKSPACE
16809 = U+0009 : HORIZONTAL TABULATION
1690A = U+000A : LINE FEED
1700B = U+000B : VERTICAL TABULATION
1710C = U+000C : FORM FEED
1720D = U+000D : CARRIAGE RETURN
1730E = U+000E : SHIFT OUT
1740F = U+000F : SHIFT IN
17510 = U+0010 : DATA LINK ESCAPE
17611 = U+0011 : DEVICE CONTROL ONE
17712 = U+0012 : DEVICE CONTROL TWO
17813 = U+0013 : DEVICE CONTROL THREE
17914 = U+0014 : DEVICE CONTROL FOUR
18015 = U+0015 : NEGATIVE ACKNOWLEDGE
18116 = U+0016 : SYNCHRONOUS IDLE
18217 = U+0017 : END OF TRANSMISSION BLOCK
18318 = U+0018 : CANCEL
18419 = U+0019 : END OF MEDIUM
1851A = U+001A : SUBSTITUTE
1861B = U+001B : ESCAPE
1871C = U+001C : FILE SEPARATOR
1881D = U+001D : GROUP SEPARATOR
1891E = U+001E : RECORD SEPARATOR
1901F = U+001F : UNIT SEPARATOR
19120 = U+0020 : SPACE
19221 = U+0021 : EXCLAMATION MARK
19322 = U+0022 : QUOTATION MARK
19423 = U+0023 : NUMBER SIGN
19524 = U+0024 : DOLLAR SIGN
19625 = U+0025 : PERCENT SIGN
19726 = U+0026 : AMPERSAND
19827 = U+0027 : APOSTROPHE
19928 = U+0028 : LEFT PARENTHESIS
20029 = U+0029 : RIGHT PARENTHESIS
2012A = U+002A : ASTERISK
2022B = U+002B : PLUS SIGN
2032C = U+002C : COMMA
2042D = U+002D : HYPHEN-MINUS
2052E = U+002E : FULL STOP
2062F = U+002F : SOLIDUS
20730 = U+0030 : DIGIT ZERO
20831 = U+0031 : DIGIT ONE
20932 = U+0032 : DIGIT TWO
21033 = U+0033 : DIGIT THREE
21134 = U+0034 : DIGIT FOUR
21235 = U+0035 : DIGIT FIVE
21336 = U+0036 : DIGIT SIX
21437 = U+0037 : DIGIT SEVEN
21538 = U+0038 : DIGIT EIGHT
21639 = U+0039 : DIGIT NINE
2173A = U+003A : COLON
2183B = U+003B : SEMICOLON
2193C = U+003C : LESS-THAN SIGN
2203D = U+003D : EQUALS SIGN
2213E = U+003E : GREATER-THAN SIGN
2223F = U+003F : QUESTION MARK
22340 = U+0040 : COMMERCIAL AT
22441 = U+0041 : LATIN CAPITAL LETTER A
22542 = U+0042 : LATIN CAPITAL LETTER B
22643 = U+0043 : LATIN CAPITAL LETTER C
22744 = U+0044 : LATIN CAPITAL LETTER D
22845 = U+0045 : LATIN CAPITAL LETTER E
22946 = U+0046 : LATIN CAPITAL LETTER F
23047 = U+0047 : LATIN CAPITAL LETTER G
23148 = U+0048 : LATIN CAPITAL LETTER H
23249 = U+0049 : LATIN CAPITAL LETTER I
2334A = U+004A : LATIN CAPITAL LETTER J
2344B = U+004B : LATIN CAPITAL LETTER K
2354C = U+004C : LATIN CAPITAL LETTER L
2364D = U+004D : LATIN CAPITAL LETTER M
2374E = U+004E : LATIN CAPITAL LETTER N
2384F = U+004F : LATIN CAPITAL LETTER O
23950 = U+0050 : LATIN CAPITAL LETTER P
24051 = U+0051 : LATIN CAPITAL LETTER Q
24152 = U+0052 : LATIN CAPITAL LETTER R
24253 = U+0053 : LATIN CAPITAL LETTER S
24354 = U+0054 : LATIN CAPITAL LETTER T
24455 = U+0055 : LATIN CAPITAL LETTER U
24556 = U+0056 : LATIN CAPITAL LETTER V
24657 = U+0057 : LATIN CAPITAL LETTER W
24758 = U+0058 : LATIN CAPITAL LETTER X
24859 = U+0059 : LATIN CAPITAL LETTER Y
2495A = U+005A : LATIN CAPITAL LETTER Z
2505B = U+005B : LEFT SQUARE BRACKET
2515C = U+005C : REVERSE SOLIDUS
2525D = U+005D : RIGHT SQUARE BRACKET
2535E = U+005E : CIRCUMFLEX ACCENT
2545F = U+005F : LOW LINE
25560 = U+0060 : GRAVE ACCENT
25661 = U+0061 : LATIN SMALL LETTER A
25762 = U+0062 : LATIN SMALL LETTER B
25863 = U+0063 : LATIN SMALL LETTER C
25964 = U+0064 : LATIN SMALL LETTER D
26065 = U+0065 : LATIN SMALL LETTER E
26166 = U+0066 : LATIN SMALL LETTER F
26267 = U+0067 : LATIN SMALL LETTER G
26368 = U+0068 : LATIN SMALL LETTER H
26469 = U+0069 : LATIN SMALL LETTER I
2656A = U+006A : LATIN SMALL LETTER J
2666B = U+006B : LATIN SMALL LETTER K
2676C = U+006C : LATIN SMALL LETTER L
2686D = U+006D : LATIN SMALL LETTER M
2696E = U+006E : LATIN SMALL LETTER N
2706F = U+006F : LATIN SMALL LETTER O
27170 = U+0070 : LATIN SMALL LETTER P
27271 = U+0071 : LATIN SMALL LETTER Q
27372 = U+0072 : LATIN SMALL LETTER R
27473 = U+0073 : LATIN SMALL LETTER S
27574 = U+0074 : LATIN SMALL LETTER T
27675 = U+0075 : LATIN SMALL LETTER U
27776 = U+0076 : LATIN SMALL LETTER V
27877 = U+0077 : LATIN SMALL LETTER W
27978 = U+0078 : LATIN SMALL LETTER X
28079 = U+0079 : LATIN SMALL LETTER Y
2817A = U+007A : LATIN SMALL LETTER Z
2827B = U+007B : LEFT CURLY BRACKET
2837C = U+007C : VERTICAL LINE
2847D = U+007D : RIGHT CURLY BRACKET
2857E = U+007E : TILDE
2867F = U+007F : DELETE
28780 = U+20AC : EURO SIGN
28882 = U+201A : SINGLE LOW-9 QUOTATION MARK
28983 = U+0192 : LATIN SMALL LETTER F WITH HOOK
29084 = U+201E : DOUBLE LOW-9 QUOTATION MARK
29185 = U+2026 : HORIZONTAL ELLIPSIS
29286 = U+2020 : DAGGER
29387 = U+2021 : DOUBLE DAGGER
29488 = U+02C6 : MODIFIER LETTER CIRCUMFLEX ACCENT
29589 = U+2030 : PER MILLE SIGN
2968A = U+0160 : LATIN CAPITAL LETTER S WITH CARON
2978B = U+2039 : SINGLE LEFT-POINTING ANGLE QUOTATION MARK
2988C = U+0152 : LATIN CAPITAL LIGATURE OE
2998E = U+017D : LATIN CAPITAL LETTER Z WITH CARON
30091 = U+2018 : LEFT SINGLE QUOTATION MARK
30192 = U+2019 : RIGHT SINGLE QUOTATION MARK
30293 = U+201C : LEFT DOUBLE QUOTATION MARK
30394 = U+201D : RIGHT DOUBLE QUOTATION MARK
30495 = U+2022 : BULLET
30596 = U+2013 : EN DASH
30697 = U+2014 : EM DASH
30798 = U+02DC : SMALL TILDE
30899 = U+2122 : TRADE MARK SIGN
3099A = U+0161 : LATIN SMALL LETTER S WITH CARON
3109B = U+203A : SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
3119C = U+0153 : LATIN SMALL LIGATURE OE
3129E = U+017E : LATIN SMALL LETTER Z WITH CARON
3139F = U+0178 : LATIN CAPITAL LETTER Y WITH DIAERESIS
314A0 = U+00A0 : NO-BREAK SPACE
315A1 = U+00A1 : INVERTED EXCLAMATION MARK
316A2 = U+00A2 : CENT SIGN
317A3 = U+00A3 : POUND SIGN
318A4 = U+00A4 : CURRENCY SIGN
319A5 = U+00A5 : YEN SIGN
320A6 = U+00A6 : BROKEN BAR
321A7 = U+00A7 : SECTION SIGN
322A8 = U+00A8 : DIAERESIS
323A9 = U+00A9 : COPYRIGHT SIGN
324AA = U+00AA : FEMININE ORDINAL INDICATOR
325AB = U+00AB : LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
326AC = U+00AC : NOT SIGN
327AD = U+00AD : SOFT HYPHEN
328AE = U+00AE : REGISTERED SIGN
329AF = U+00AF : MACRON
330B0 = U+00B0 : DEGREE SIGN
331B1 = U+00B1 : PLUS-MINUS SIGN
332B2 = U+00B2 : SUPERSCRIPT TWO
333B3 = U+00B3 : SUPERSCRIPT THREE
334B4 = U+00B4 : ACUTE ACCENT
335B5 = U+00B5 : MICRO SIGN
336B6 = U+00B6 : PILCROW SIGN
337B7 = U+00B7 : MIDDLE DOT
338B8 = U+00B8 : CEDILLA
339B9 = U+00B9 : SUPERSCRIPT ONE
340BA = U+00BA : MASCULINE ORDINAL INDICATOR
341BB = U+00BB : RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
342BC = U+00BC : VULGAR FRACTION ONE QUARTER
343BD = U+00BD : VULGAR FRACTION ONE HALF
344BE = U+00BE : VULGAR FRACTION THREE QUARTERS
345BF = U+00BF : INVERTED QUESTION MARK
346C0 = U+00C0 : LATIN CAPITAL LETTER A WITH GRAVE
347C1 = U+00C1 : LATIN CAPITAL LETTER A WITH ACUTE
348C2 = U+00C2 : LATIN CAPITAL LETTER A WITH CIRCUMFLEX
349C3 = U+00C3 : LATIN CAPITAL LETTER A WITH TILDE
350C4 = U+00C4 : LATIN CAPITAL LETTER A WITH DIAERESIS
351C5 = U+00C5 : LATIN CAPITAL LETTER A WITH RING ABOVE
352C6 = U+00C6 : LATIN CAPITAL LETTER AE
353C7 = U+00C7 : LATIN CAPITAL LETTER C WITH CEDILLA
354C8 = U+00C8 : LATIN CAPITAL LETTER E WITH GRAVE
355C9 = U+00C9 : LATIN CAPITAL LETTER E WITH ACUTE
356CA = U+00CA : LATIN CAPITAL LETTER E WITH CIRCUMFLEX
357CB = U+00CB : LATIN CAPITAL LETTER E WITH DIAERESIS
358CC = U+00CC : LATIN CAPITAL LETTER I WITH GRAVE
359CD = U+00CD : LATIN CAPITAL LETTER I WITH ACUTE
360CE = U+00CE : LATIN CAPITAL LETTER I WITH CIRCUMFLEX
361CF = U+00CF : LATIN CAPITAL LETTER I WITH DIAERESIS
362D0 = U+00D0 : LATIN CAPITAL LETTER ETH
363D1 = U+00D1 : LATIN CAPITAL LETTER N WITH TILDE
364D2 = U+00D2 : LATIN CAPITAL LETTER O WITH GRAVE
365D3 = U+00D3 : LATIN CAPITAL LETTER O WITH ACUTE
366D4 = U+00D4 : LATIN CAPITAL LETTER O WITH CIRCUMFLEX
367D5 = U+00D5 : LATIN CAPITAL LETTER O WITH TILDE
368D6 = U+00D6 : LATIN CAPITAL LETTER O WITH DIAERESIS
369D7 = U+00D7 : MULTIPLICATION SIGN
370D8 = U+00D8 : LATIN CAPITAL LETTER O WITH STROKE
371D9 = U+00D9 : LATIN CAPITAL LETTER U WITH GRAVE
372DA = U+00DA : LATIN CAPITAL LETTER U WITH ACUTE
373DB = U+00DB : LATIN CAPITAL LETTER U WITH CIRCUMFLEX
374DC = U+00DC : LATIN CAPITAL LETTER U WITH DIAERESIS
375DD = U+00DD : LATIN CAPITAL LETTER Y WITH ACUTE
376DE = U+00DE : LATIN CAPITAL LETTER THORN
377DF = U+00DF : LATIN SMALL LETTER SHARP S
378E0 = U+00E0 : LATIN SMALL LETTER A WITH GRAVE
379E1 = U+00E1 : LATIN SMALL LETTER A WITH ACUTE
380E2 = U+00E2 : LATIN SMALL LETTER A WITH CIRCUMFLEX
381E3 = U+00E3 : LATIN SMALL LETTER A WITH TILDE
382E4 = U+00E4 : LATIN SMALL LETTER A WITH DIAERESIS
383E5 = U+00E5 : LATIN SMALL LETTER A WITH RING ABOVE
384E6 = U+00E6 : LATIN SMALL LETTER AE
385E7 = U+00E7 : LATIN SMALL LETTER C WITH CEDILLA
386E8 = U+00E8 : LATIN SMALL LETTER E WITH GRAVE
387E9 = U+00E9 : LATIN SMALL LETTER E WITH ACUTE
388EA = U+00EA : LATIN SMALL LETTER E WITH CIRCUMFLEX
389EB = U+00EB : LATIN SMALL LETTER E WITH DIAERESIS
390EC = U+00EC : LATIN SMALL LETTER I WITH GRAVE
391ED = U+00ED : LATIN SMALL LETTER I WITH ACUTE
392EE = U+00EE : LATIN SMALL LETTER I WITH CIRCUMFLEX
393EF = U+00EF : LATIN SMALL LETTER I WITH DIAERESIS
394F0 = U+00F0 : LATIN SMALL LETTER ETH
395F1 = U+00F1 : LATIN SMALL LETTER N WITH TILDE
396F2 = U+00F2 : LATIN SMALL LETTER O WITH GRAVE
397F3 = U+00F3 : LATIN SMALL LETTER O WITH ACUTE
398F4 = U+00F4 : LATIN SMALL LETTER O WITH CIRCUMFLEX
399F5 = U+00F5 : LATIN SMALL LETTER O WITH TILDE
400F6 = U+00F6 : LATIN SMALL LETTER O WITH DIAERESIS
401F7 = U+00F7 : DIVISION SIGN
402F8 = U+00F8 : LATIN SMALL LETTER O WITH STROKE
403F9 = U+00F9 : LATIN SMALL LETTER U WITH GRAVE
404FA = U+00FA : LATIN SMALL LETTER U WITH ACUTE
405FB = U+00FB : LATIN SMALL LETTER U WITH CIRCUMFLEX
406FC = U+00FC : LATIN SMALL LETTER U WITH DIAERESIS
407FD = U+00FD : LATIN SMALL LETTER Y WITH ACUTE
408FE = U+00FE : LATIN SMALL LETTER THORN
409FF = U+00FF : LATIN SMALL LETTER Y WITH DIAERESIS
410 *
411 */
412}
413?>
diff --git a/inc/3rdparty/libraries/MOBIClass/ContentProvider.php b/inc/3rdparty/libraries/MOBIClass/ContentProvider.php
new file mode 100644
index 00000000..dcf9c4de
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/ContentProvider.php
@@ -0,0 +1,22 @@
1<?php
2
3abstract class ContentProvider{
4 /**
5 * Get the text data to be integrated in the MOBI file
6 * @return string
7 */
8 public abstract function getTextData();
9 /**
10 * Get the images (an array containing the jpeg data). Array entry 0 will
11 * correspond to image record 0.
12 * @return array
13 */
14 public abstract function getImages();
15 /**
16 * Get the metadata in the form of a hashtable (for example, title or author).
17 * @return array
18 */
19 public abstract function getMetaData();
20}
21
22?>
diff --git a/inc/3rdparty/libraries/MOBIClass/EXTHHelper.php b/inc/3rdparty/libraries/MOBIClass/EXTHHelper.php
new file mode 100644
index 00000000..275142bf
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/EXTHHelper.php
@@ -0,0 +1,132 @@
1<?php
2//Reference: http://wiki.mobileread.com/wiki/MOBI
3
4class EXTHHelper{
5 static function typeToText($type){
6 $types = self::$types;
7 if(isset($types[$type])){
8 return $types[$type];
9 }
10 return $type;
11 }
12 static function textToType($text){
13 $text = strtolower($text);
14 if(isset(self::$flippedTypes[$text])){
15 return self::$flippedTypes[$text];
16 }
17 return false;
18 }
19
20 static function convert($n, $size){
21 $mask = 0xFF;
22 $out = "";
23 for($i = 0; $i < $size; $i++){
24 $out = chr(($n & $mask) >> (8*$i)).$out;
25 $mask = $mask << 8;
26 }
27 return $out;
28 }
29
30 static function getRightRepresentation($type, $value){
31 if($type >= 100 && $type < 200){
32 return $value;
33 }else{
34 return self::toHex($value);
35 }
36 }
37
38 static function toHex($value){
39 $out = "";
40 for($i = 0, $len = strlen($value); $i < $len; $i++){
41 if($i > 0) $out .= " ";
42 $hex = dechex(ord($value[$i]));
43 if(strlen($hex) < 2) $hex = "0".$hex;
44 $out .= $hex;
45 }
46 return $out;
47 }
48
49
50 static private $types = array(
51 1 => "drm server id",
52 2 => "drm commerce id",
53 3 => "drm ebookbase book id",
54 100 => "author",
55 101 => "publisher",
56 102 => "imprint",
57 103 => "description",
58 104 => "isbn",
59 105 => "subject",
60 106 => "publishingdate",
61 107 => "review",
62 108 => "contributor",
63 109 => "rights",
64 110 => "subjectcode",
65 111 => "type",
66 112 => "source",
67 113 => "asin",
68 114 => "versionnumber",
69 115 => "sample",
70 116 => "startreading",
71 118 => "retail price",
72 119 => "retail price currency",
73 201 => "coveroffset",
74 202 => "thumboffset",
75 203 => "hasfakecover",
76 204 => "Creator Software",
77 205 => "Creator Major Version",
78 206 => "Creator Minor Version",
79 207 => "Creator Build Number",
80 208 => "watermark",
81 209 => "tamper proof keys",
82 300 => "fontsignature",
83 401 => "clippinglimit",
84 402 => "publisherlimit",
85 403 => "403",
86 404 => "ttsflag",
87 501 => "cdetype",
88 502 => "lastupdatetime",
89 503 => "updatedtitle"
90 );
91 static private $flippedTypes = array(
92 "drm server id" => 1,
93 "drm commerce id" => 2,
94 "drm ebookbase book id" => 3,
95 "author" => 100,
96 "publisher" => 101,
97 "imprint" => 102,
98 "description" => 103,
99 "isbn" => 104,
100 "subject" => 105,
101 "publishingdate" => 106,
102 "review" => 107,
103 "contributor" => 108,
104 "rights" => 109,
105 "subjectcode" => 110,
106 "type" => 111,
107 "source" => 112,
108 "asin" => 113,
109 "versionnumber" => 114,
110 "sample" => 115,
111 "startreading" => 116,
112 "retail price" => 118,
113 "retail price currency" => 119,
114 "coveroffset" => 201,
115 "thumboffset" => 202,
116 "hasfakecover" => 203,
117 "Creator Software" => 204,
118 "Creator Major Version" => 205,
119 "Creator Minor Version" => 206,
120 "Creator Build Number" => 207,
121 "watermark" => 208,
122 "tamper proof keys" => 209,
123 "fontsignature" => 300,
124 "clippinglimit" => 401,
125 "publisherlimit" => 402,
126 "403" => 403,
127 "ttsflag" => 404,
128 "cdetype" => 501,
129 "lastupdatetime" => 502,
130 "updatedtitle" => 503
131 );
132} \ No newline at end of file
diff --git a/inc/3rdparty/libraries/MOBIClass/FileByte.php b/inc/3rdparty/libraries/MOBIClass/FileByte.php
new file mode 100644
index 00000000..05fc7d04
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/FileByte.php
@@ -0,0 +1,41 @@
1<?php
2
3/**
4 * Description of FileByte
5 *
6 * @author Sander
7 */
8class FileByte extends FileObject {
9 private $data;
10
11 /**
12 * Make a short to be stored in a file
13 * @param short $n
14 */
15 public function __construct($n = 0){
16 parent::__construct(1);
17 $this->set($n);
18 }
19
20 public function get(){
21 return $this->data;
22 }
23
24 public function set($value){
25 $this->data = intval($value) & 0xFF;
26 }
27
28 public function serialize() {
29 return $this->byteToString($this->data);
30 }
31
32 public function unserialize($data) {
33 __construct($this->toInt($data));
34 }
35
36
37 public function __toString(){
38 return "FileByte: {".$this->byteAsString($this->data)."}";
39 }
40}
41?>
diff --git a/inc/3rdparty/libraries/MOBIClass/FileDate.php b/inc/3rdparty/libraries/MOBIClass/FileDate.php
new file mode 100644
index 00000000..2284eba2
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/FileDate.php
@@ -0,0 +1,40 @@
1<?php
2
3/**
4 * Description of FileDate
5 *
6 * @author Sander
7 */
8class FileDate extends FileObject {
9 private $data;
10
11 /**
12 * Make an integer to be stored in a file
13 * @param int $n
14 */
15 public function __construct($n = 0){
16 parent::__construct(4);
17 $this->set($n);
18 }
19
20 public function get(){
21 return $this->data;
22 }
23
24 public function set($value){
25 $this->data = intval($value);
26 }
27
28 public function serialize() {
29 return $this->intToString($this->data);
30 }
31
32 public function unserialize($data) {
33 __construct($this->toInt($data));
34 }
35
36 public function __toString(){
37 return "FileDate: {".(date("r", $this->data-94694400))."}";
38 }
39}
40?>
diff --git a/inc/3rdparty/libraries/MOBIClass/FileElement.php b/inc/3rdparty/libraries/MOBIClass/FileElement.php
new file mode 100644
index 00000000..552d04a8
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/FileElement.php
@@ -0,0 +1,89 @@
1<?php
2
3/**
4 * Description of FileElement
5 *
6 * @author Sander
7 */
8class FileElement {
9 /**
10 * @var FileObject
11 */
12 public $elements;
13
14 /**
15 * Make a record to be stored in a file
16 * @param Record $record
17 */
18 public function __construct($elements = array()){
19 $this->elements = $elements;
20 }
21
22 public function getByteLength(){
23 return $this->getLength();
24 }
25
26 public function getLength(){
27 $total = 0;
28 foreach($this->elements as $val){
29 $total += $val->getByteLength();
30 }
31 return $total;
32 }
33
34 public function offsetToEntry($name){
35 $pos = 0;
36 foreach($this->elements as $key=>$value){
37 if($name == $key){
38 break;
39 }
40 $pos += $value->getByteLength();
41 }
42 return $pos;
43 }
44
45 public function exists($key){
46 return isset($this->elements[$key]);
47 }
48 /**
49 * @param string $key
50 * @return FileObject
51 */
52 public function get($key){
53 return $this->elements[$key];
54 }
55
56 /**
57 * @param string $key
58 * @param FileObject $value
59 */
60 public function set($key, $value){
61 $this->elements[$key] = $value;
62 }
63
64 public function add($key, $value){
65 $this->elements[$key] = $value;
66 }
67
68 public function serialize() {
69 $result = "";
70 foreach($this->elements as $val){
71 $result .= $val->serialize();
72 }
73 return $result;
74 }
75
76 public function unserialize($data) {
77 //TODO: If reading is needed -> way more complex
78 }
79
80 public function __toString(){
81 $output = "FileElement (".$this->getByteLength()." bytes): {\n";
82 foreach($this->elements as $key=>$value){
83 $output .= "\t".$key.": ".$value."\n";
84 }
85 $output .= "}";
86 return $output;
87 }
88}
89?>
diff --git a/inc/3rdparty/libraries/MOBIClass/FileInt.php b/inc/3rdparty/libraries/MOBIClass/FileInt.php
new file mode 100644
index 00000000..ebe86f86
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/FileInt.php
@@ -0,0 +1,40 @@
1<?php
2
3/**
4 * Description of FileInt
5 *
6 * @author Sander
7 */
8class FileInt extends FileObject {
9 private $data;
10
11 /**
12 * Make an integer to be stored in a file
13 * @param int $n
14 */
15 public function __construct($n = 0){
16 parent::__construct(4);
17 $this->set($n);
18 }
19
20 public function get(){
21 return $this->data;
22 }
23
24 public function set($value){
25 $this->data = intval($value);
26 }
27
28 public function serialize() {
29 return $this->intToString($this->data);
30 }
31
32 public function unserialize($data) {
33 __construct($this->toInt($data));
34 }
35
36 public function __toString(){
37 return "FileInt: {".$this->intAsString($this->data)."}";
38 }
39}
40?>
diff --git a/inc/3rdparty/libraries/MOBIClass/FileObject.php b/inc/3rdparty/libraries/MOBIClass/FileObject.php
new file mode 100644
index 00000000..0df17df1
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/FileObject.php
@@ -0,0 +1,168 @@
1<?php
2
3/**
4 * Description of FileObject
5 *
6 * @author Sander
7 */
8abstract class FileObject {
9 private $byteLength = -1;
10
11 public function __construct($byteLength = -1){
12 $this->byteLength = $byteLength;
13 }
14
15 public function getByteLength(){
16 if($this->byteLength >= 0){
17 return $this->byteLength;
18 }
19 return $this->getLength();
20 }
21
22 public function getLength(){
23 throw new Exception("Sub-class needs to implement this if it doesn't have a fixed length");
24 }
25
26 /**
27 * Convert a string to byte format (maximum 4 bytes)
28 * @param string $string Input string
29 * @return int Output integer
30 */
31 public function toInt($string){
32 $out = 0;
33 for($i = 0, $len = min(4, strlen($string)); $i < $len; $i++){
34 $out = $out | (ord($string[$i]) << (($len-$i-1)*8));
35 }
36 return $out;
37 }
38
39 /**
40 * Convert a byte (stored in an integer) to a string
41 * @param byte $int
42 * @return string
43 */
44 public function byteToString($int){
45 return $this->toString($int, 1);
46 }
47
48 /**
49 * Convert a byte (stored in an integer) to a string
50 * @param byte $int
51 * @return string
52 */
53 public function byteAsString($int){
54 return $this->asString($int, 1);
55 }
56
57 /**
58 * Convert a short (stored in an integer) to a string
59 * @param short $int
60 * @return string
61 */
62 public function shortToString($int){
63 return $this->toString($int, 2);
64 }
65
66 /**
67 * Convert a short (stored in an integer) to a string
68 * @param short $int
69 * @return string
70 */
71 public function shortAsString($int){
72 return $this->asString($int, 2);
73 }
74
75 /**
76 * Convert a tri-byte (stored in an integer) to a string
77 * @param tri-byte $int
78 * @return string
79 */
80 public function triToString($int){
81 return $this->toString($int, 3);
82 }
83
84 /**
85 * Convert a tri-byte (stored in an integer) to a string
86 * @param tri-byte $int
87 * @return string
88 */
89 public function triAsString($int){
90 return $this->asString($int, 3);
91 }
92
93 /**
94 * Convert an integer to a string
95 * @param int $int
96 * @return string
97 */
98 public function intToString($int){
99 return $this->toString($int, 4);
100 }
101
102 /**
103 * Convert an integer to a string
104 * @param int $int
105 * @return string
106 */
107 public function intAsString($int){
108 return $this->asString($int, 4);
109 }
110
111 /**
112 * Convert a number of n bytes to a string
113 * @param int $int Number that should be converted
114 * @param int $size Number of bytes to convert
115 * @return string Output string
116 */
117 private function toString($int, $size){
118 $out = "";
119 for($i = 0; $i < $size; $i++){
120 $out = chr($int & 0xFF).$out;
121 $int = $int >> 8;
122 }
123 return $out;
124 }
125
126 /**
127 * Convert a number of n bytes to a string
128 * @param int $int Number that should be converted
129 * @param int $size Number of bytes to convert
130 * @return string Output string
131 */
132 private function asString($int, $size){
133 $out = "";
134 for($i = 0; $i < $size; $i++){
135 if($i > 0) $out = " ".$out;
136 $byte = dechex($int & 0xFF);
137 if(strlen($byte) == 1) $byte = "0".$byte;
138 $out = $byte.$out;
139 $int = $int >> 8;
140 }
141 return $out;
142 }
143
144 /**
145 * Get the value
146 * @return mixed Value to get
147 */
148 abstract public function get();
149
150 /**
151 * Set the value
152 * @return mixed Value to set
153 */
154 abstract public function set($value);
155
156 /**
157 * Serialize the object
158 * @return string String representation
159 */
160 abstract public function serialize();
161
162 /**
163 * Unserialize the object
164 * @param string $data String representation
165 */
166 abstract public function unserialize($data);
167}
168?>
diff --git a/inc/3rdparty/libraries/MOBIClass/FileRecord.php b/inc/3rdparty/libraries/MOBIClass/FileRecord.php
new file mode 100644
index 00000000..494a72e4
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/FileRecord.php
@@ -0,0 +1,46 @@
1<?php
2
3/**
4 * Description of FileRecord
5 *
6 * @author Sander
7 */
8class FileRecord extends FileObject {
9 /**
10 * @var Record
11 */
12 private $record;
13
14 /**
15 * Make a record to be stored in a file
16 * @param Record $record
17 */
18 public function __construct($record){
19 $this->record = $record;
20 }
21
22 public function getByteLength(){
23 return $this->getLength();
24 }
25
26 public function getLength(){
27 return $this->record->getLength();
28 }
29
30 public function get(){
31 return $this->record;
32 }
33
34 public function set($record){
35 $this->record = $record;
36 }
37
38 public function serialize() {
39 return $this->record->serialize();
40 }
41
42 public function unserialize($data) {
43 __construct($this->record->unserialize($data));
44 }
45}
46?>
diff --git a/inc/3rdparty/libraries/MOBIClass/FileShort.php b/inc/3rdparty/libraries/MOBIClass/FileShort.php
new file mode 100644
index 00000000..9921ea82
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/FileShort.php
@@ -0,0 +1,41 @@
1<?php
2
3/**
4 * Description of FileShort
5 *
6 * @author Sander
7 */
8class FileShort extends FileObject {
9 private $data;
10
11 /**
12 * Make a short to be stored in a file
13 * @param short $n
14 */
15 public function __construct($n = 0){
16 parent::__construct(2);
17 $this->set($n);
18 }
19
20 public function get(){
21 return $this->data;
22 }
23
24 public function set($value){
25 $this->data = intval($value) & 0xFFFF;
26 }
27
28 public function serialize() {
29 return $this->shortToString($this->data);
30 }
31
32 public function unserialize($data) {
33 __construct($this->toInt($data));
34 }
35
36
37 public function __toString(){
38 return "FileShort: {".$this->shortAsString($this->data)."}";
39 }
40}
41?>
diff --git a/inc/3rdparty/libraries/MOBIClass/FileString.php b/inc/3rdparty/libraries/MOBIClass/FileString.php
new file mode 100644
index 00000000..16e906a6
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/FileString.php
@@ -0,0 +1,83 @@
1<?php
2
3/**
4 * Description of FileString
5 *
6 * @author Sander
7 */
8class FileString extends FileObject {
9 private $forcedLength;
10 private $data;
11
12 /**
13 * Make a string to be stored in a file
14 * @param string|int $first Optional, if it is a string, it will be the contents,
15 * if it is a number, it will set the forced length.
16 * @param int $second Optional, will set the forced length. Can only be used when the
17 * first argument is contents.
18 */
19 public function __construct($first = null, $second = null){
20 $this->forcedLength = -1;
21 $this->data = "";
22
23 if($second != null){
24 $this->data = $first;
25 $this->forcedLength = $second;
26 }else if($first != null){
27 if(is_string($first)){
28 $this->data = $first;
29 }else{
30 $this->forcedLength = $first;
31 }
32 }
33 }
34
35 public function getByteLength(){
36 return $this->getLength();
37 }
38
39 public function getLength(){
40 if($this->forcedLength >= 0){
41 return $this->forcedLength;
42 }
43 return strlen($this->data);
44 }
45
46 public function get(){
47 return $this->data;
48 }
49
50 public function set($value){
51 $this->data = $value;
52 }
53
54 public function serialize() {
55 $output = $this->data;
56 $curLength = strlen($output);
57
58 if($this->forcedLength >= 0){
59 if($this->forcedLength > $curLength){
60 return str_pad($output, $this->forcedLength, "\0", STR_PAD_RIGHT);
61 }elseif($this->forcedLength == $curLength){
62 return $output;
63 }else{
64 return substr($output, 0, $this->forcedLength);
65 }
66 }
67 return $output;
68 }
69
70 public function unserialize($data) {
71 __construct($data);
72 }
73
74 public function __toString(){
75 $out = "FileString";
76 if($this->forcedLength >= 0){
77 $out .= " ".$this->forcedLength;
78 }
79 $out .= ": {\"".str_replace(array(" ", "\0"), "&nbsp;", $this->serialize())."\"}";
80 return $out;
81 }
82}
83?>
diff --git a/inc/3rdparty/libraries/MOBIClass/FileTri.php b/inc/3rdparty/libraries/MOBIClass/FileTri.php
new file mode 100644
index 00000000..6cacc0b0
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/FileTri.php
@@ -0,0 +1,41 @@
1<?php
2
3/**
4 * Description of FileTri
5 *
6 * @author Sander
7 */
8class FileTri extends FileObject {
9 private $data;
10
11 /**
12 * Make a tri-byte to be stored in a file
13 * @param tri-byte $n
14 */
15 public function __construct($n = 0){
16 parent::__construct(3);
17 $this->set($n);
18 }
19
20 public function get(){
21 return $this->data;
22 }
23
24 public function set($value){
25 $this->data = intval($value) & 0xFFFFFF;
26 }
27
28 public function serialize() {
29 return $this->triToString($this->data);
30 }
31
32 public function unserialize($data) {
33 __construct($this->toInt($data));
34 }
35
36
37 public function __toString(){
38 return "FileTri: {".$this->triAsString($this->data)."}";
39 }
40}
41?>
diff --git a/inc/3rdparty/libraries/MOBIClass/Http.php b/inc/3rdparty/libraries/MOBIClass/Http.php
new file mode 100644
index 00000000..9e5852e3
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/Http.php
@@ -0,0 +1,171 @@
1<?php
2class Http{
3 private static $cache = false;
4
5 public static function Request($url){
6 $url_parts = parse_url($url);
7 $url_parts["port"] = isset($url_parts["port"]) ? $url_parts["port"] : 80;
8 $url_parts["path"] = isset($url_parts["path"]) ? $url_parts["path"] : "/";
9
10 return self::FullRequest("GET", $url_parts["host"], $url_parts["port"], $url_parts["path"]);
11 }
12
13 public static function FullRequest(
14 $verb = 'GET', /* HTTP Request Method (GET and POST supported) */
15 $ip, /* Target IP/Hostname */
16 $port = 80, /* Target TCP port */
17 $uri = '/', /* Target URI */
18 $getdata = array(), /* HTTP GET Data ie. array('var1' => 'val1', 'var2' => 'val2') */
19 $postdata = array(), /* HTTP POST Data ie. array('var1' => 'val1', 'var2' => 'val2') */
20 $cookie = array(), /* HTTP Cookie Data ie. array('var1' => 'val1', 'var2' => 'val2') */
21 $custom_headers = array(), /* Custom HTTP headers ie. array('Referer: http://localhost/ */
22 $timeout = 1000, /* Socket timeout in milliseconds */
23 $req_hdr = false, /* Include HTTP request headers */
24 $res_hdr = false, /* Include HTTP response headers */
25 $depth = 4 /* Depth of the iteration left (to avoid redirection loops) */
26 )
27 {
28 if(self::$cache){
29 $cacheFile = "cache/".$ip."/".str_replace("/", "...", $uri);
30
31 if(is_file($cacheFile)){
32 $data = file_get_contents($cacheFile);
33
34 return self::resolveTruncated($data);
35 }
36 }
37 $ret = '';
38 $verb = strtoupper($verb);
39 $cookie_str = '';
40 $getdata_str = count($getdata) ? '?' : '';
41 $postdata_str = '';
42
43 foreach ($getdata as $k => $v)
44 $getdata_str .= urlencode($k) .'='. urlencode($v);
45
46 foreach ($postdata as $k => $v)
47 $postdata_str .= urlencode($k) .'='. urlencode($v) .'&';
48
49 foreach ($cookie as $k => $v)
50 $cookie_str .= urlencode($k) .'='. urlencode($v) .'; ';
51
52 $crlf = "\r\n";
53 $req = $verb .' '. $uri . $getdata_str .' HTTP/1.1' . $crlf;
54 $req .= 'Host: '. $ip . $crlf;
55 $req .= 'User-Agent: Mozilla/5.0 Firefox/3.6.12' . $crlf;
56 $req .= 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' . $crlf;
57 $req .= 'Accept-Language: en-us,en;q=0.5' . $crlf;
58 $req .= 'Accept-Encoding: deflate' . $crlf;
59 $req .= 'Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7' . $crlf;
60
61
62 foreach ($custom_headers as $k => $v)
63 $req .= $k .': '. $v . $crlf;
64
65 if (!empty($cookie_str))
66 $req .= 'Cookie: '. substr($cookie_str, 0, -2) . $crlf;
67
68 if ($verb == 'POST' && !empty($postdata_str))
69 {
70 $postdata_str = substr($postdata_str, 0, -1);
71 $req .= 'Content-Type: application/x-www-form-urlencoded' . $crlf;
72 $req .= 'Content-Length: '. strlen($postdata_str) . $crlf . $crlf;
73 $req .= $postdata_str;
74 }
75 else $req .= $crlf;
76
77 if ($req_hdr)
78 $ret .= $req;
79
80 if (($fp = @fsockopen($ip, $port, $errno, $errstr)) == false)
81 return "Error $errno: $errstr\n";
82
83 stream_set_timeout($fp, 0, $timeout * 1000);
84
85 fputs($fp, $req);
86 $ret .= stream_get_contents($fp);
87 fclose($fp);
88
89 $headerSplit = strpos($ret, "\r\n\r\n");
90 $header = substr($ret, 0, $headerSplit);
91
92 $redirectURL = self::CheckForRedirect($header);
93
94 if($redirectURL !== false){
95 if($depth > 0){
96 $url_parts = parse_url($redirectURL);
97 $url_parts["port"] = isset($url_parts["port"]) ? $url_parts["port"] : 80;
98 $url_parts["path"] = isset($url_parts["path"]) ? $url_parts["path"] : "/";
99
100 return self::FullRequest($verb, $url_parts["host"], $url_parts["port"], $url_parts["path"], $getdata, $postdata, $cookie, $custom_headers, $timeout, $req_hdr, $res_hdr, $depth-1);
101 }else{
102 return "Redirect loop, stopping...";
103 }
104 }
105
106 $truncated = false;
107 $headerLines = explode("\r\n", $header);
108 foreach($headerLines as $line){
109 list($name, $value) = explode(":", $line);
110 $name = trim($name);
111 $value = trim($value);
112
113 if(strtolower($name) == "transfer-encoding" && strtolower($value) == "chunked"){ //TODO: Put right values!
114 $truncated = true;
115 }
116 }
117
118 if (!$res_hdr)
119 $ret = substr($ret, $headerSplit + 4);
120
121 if($truncated){
122 $ret = self::resolveTruncated($ret);
123 }
124 if(self::$cache){
125 if(!is_dir("cache")){
126 mkdir("cache");
127 }
128 if(!is_dir("cache/".$ip)){
129 mkdir("cache/".$ip);
130 }
131 if(!is_file("cache/".$ip."/".str_replace("/", "...", $uri))){
132 $h = fopen("cache/".$ip."/".str_replace("/", "...", $uri), "w");
133 fwrite($h, $ret);
134 fclose($h);
135 }
136 }
137
138 return $ret;
139 }
140
141 private static function resolveTruncated($data){
142 $pos = 0;
143 $end = strlen($data);
144 $out = "";
145
146 while($pos < $end){
147 $endVal = strpos($data, "\r\n", $pos);
148 $value = hexdec(substr($data, $pos, $endVal-$pos));
149 $out .= substr($data, $endVal+2, $value);
150 $pos = $endVal+2+$value;
151 }
152
153 return $out;
154 }
155
156 private static function CheckForRedirect($header){
157 $firstLine = substr($header, 0, strpos($header, "\r\n"));
158 list($httpVersion, $statusCode, $message) = explode(" ", $firstLine);
159
160 if(substr($statusCode, 0, 1) == "3"){
161 $part = substr($header, strpos(strtolower($header), "location: ")+strlen("location: "));
162 $location = trim(substr($part, 0, strpos($part, "\r\n")));
163
164 if(strlen($location) > 0){
165 return $location;
166 }
167 }
168 return false;
169 }
170}
171?> \ No newline at end of file
diff --git a/inc/3rdparty/libraries/MOBIClass/ImageHandler.php b/inc/3rdparty/libraries/MOBIClass/ImageHandler.php
new file mode 100644
index 00000000..bcb48e9f
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/ImageHandler.php
@@ -0,0 +1,40 @@
1<?php
2
3class ImageHandler {
4 /**
5 * Download an image
6 * @param string $url Url to the image
7 * @return false|string False if failed, else the data of the image (converted to grayscale jpeg)
8 */
9 public static function DownloadImage($url){
10 $data = Http::Request($url);
11 $imgFile = @imagecreatefromstring($data);
12
13 if($imgFile !== false){
14 $result = self::CreateImage($imgFile);
15 imagedestroy($imgFile);
16 return $result;
17 }
18 return false;
19 }
20 /**
21 * Create an image
22 * @param resource $img Create an image created with createimagetruecolor
23 * @return false|string False if failed, else the data of the image (converted to grayscale jpeg)
24 */
25 public static function CreateImage($img){
26 try{
27 imagefilter($img, IMG_FILTER_GRAYSCALE);
28
29 ob_start();
30 imagejpeg($img);
31 $image = ob_get_contents();
32 ob_end_clean();
33
34 return $image;
35 }catch(Exception $e){
36 return false;
37 }
38 }
39}
40?>
diff --git a/inc/3rdparty/libraries/MOBIClass/MOBI.php b/inc/3rdparty/libraries/MOBIClass/MOBI.php
new file mode 100644
index 00000000..df4826b0
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/MOBI.php
@@ -0,0 +1,192 @@
1<?php
2require_once(dirname(__FILE__)."/../readability/Readability.php");
3require_once(dirname(__FILE__).'/CharacterEntities.php');
4require_once(dirname(__FILE__).'/constants.php');
5require_once(dirname(__FILE__).'/ContentProvider.php');
6require_once(dirname(__FILE__).'/MultipleFileHandler.php');
7require_once(dirname(__FILE__)."/downloaders/FanFictionNet.php");
8require_once(dirname(__FILE__).'/EXTHHelper.php');
9require_once(dirname(__FILE__).'/FileObject.php');
10require_once(dirname(__FILE__).'/FileByte.php');
11require_once(dirname(__FILE__).'/FileDate.php');
12require_once(dirname(__FILE__).'/FileElement.php');
13require_once(dirname(__FILE__).'/FileInt.php');
14require_once(dirname(__FILE__).'/FileRecord.php');
15require_once(dirname(__FILE__).'/FileShort.php');
16require_once(dirname(__FILE__).'/FileString.php');
17require_once(dirname(__FILE__).'/FileTri.php');
18require_once(dirname(__FILE__).'/Http.php');
19require_once(dirname(__FILE__).'/http_build_url.php');
20require_once(dirname(__FILE__).'/ImageHandler.php');
21require_once(dirname(__FILE__).'/MOBIFile.php');
22require_once(dirname(__FILE__).'/OnlineArticle.php');
23require_once(dirname(__FILE__).'/PalmRecord.php');
24require_once(dirname(__FILE__).'/Prc.php');
25require_once(dirname(__FILE__).'/PreprocessedArticle.php');
26require_once(dirname(__FILE__).'/RecognizeURL.php');
27require_once(dirname(__FILE__).'/Record.php');
28require_once(dirname(__FILE__).'/RecordFactory.php');
29require_once(dirname(__FILE__).'/Settings.php');
30
31/**
32 * Description of MOBI.
33 *
34 * Usage:
35 * include("MOBIClass/MOBI.php");
36 *
37 * $mobi = new MOBI();
38 *
39 * //Then use one of the following ways to prepare information (it should be in the form of valid html)
40 * $mobi->setInternetSource($url); //Load URL, the result will be cleaned using a Readability port
41 * $mobi->setFileSource($file); //Load a local file without any extra changes
42 * $mobi->setData($data); //Load data
43 *
44 * //If you want, you can set some optional settings (see Settings.php for all recognized settings)
45 * $options = array(
46 * "title"=>"Insert title here",
47 * "author"=>"Author"
48 * );
49 * $mobi->setOptions($options);
50 *
51 * //Then there are two ways to output it:
52 * $mobi->save($file); //Save the file locally
53 * $mobi->download($name); //Let the client download the file, make sure the page
54 * //that calls it doesn't output anything, otherwise it might
55 * //conflict with the download. $name contains the file name,
56 * //usually something like "title.mobi" (where the title should
57 * //be cleaned so as not to contain illegal characters).
58 *
59 *
60 * @author Sander Kromwijk
61 */
62class MOBI {
63 private $source = false;
64 private $images = array();
65 private $optional = array();
66 private $imgCounter = 0;
67 private $debug = false;
68 private $prc = false;
69
70 public function __construct(){
71
72 }
73
74 public function getTitle(){
75 if(isset($this->optional["title"])){
76 return $this->optional["title"];
77 }
78 return false;
79 }
80
81 /**
82 * Set a content provider as source
83 * @param ContentProvider $content Content Provider to use
84 */
85 public function setContentProvider($content){
86 $this->setOptions($content->getMetaData());
87 $this->setImages($content->getImages());
88 $this->setData($content->getTextData());
89 }
90
91 /**
92 * Set a local file as source
93 * @param string $file Path to the file
94 */
95 public function setFileSource($file){
96 $this->setData(file_get_contents($file));
97 }
98
99 /**
100 * Set the data to use
101 * @param string $data Data to put in the file
102 */
103 public function setData($data){
104 //$data = utf8_encode($data);
105 $data = CharacterEntities::convert($data);
106 //$data = utf8_decode($data);
107 //$this->source = iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $data);
108 $this->source = $data;
109 $this->prc = false;
110 }
111
112 /**
113 * Set the images to use
114 * @param array $data Data to put in the file
115 */
116 public function setImages($data){
117 $this->images = $data;
118 $this->prc = false;
119 }
120
121 /**
122 * Set options, usually for things like titles, authors, etc...
123 * @param array $options Options to set
124 */
125 public function setOptions($options){
126 $this->optional = $options;
127 $this->prc = false;
128 }
129
130 /**
131 * Prepare the prc file
132 * @return Prc The file that can be used to be saved/downloaded
133 */
134 private function preparePRC(){
135 if($this->source === false){
136 throw new Exception("No data set");
137 }
138 if($this->prc !== false) return $this->prc;
139
140 $data = $this->source;
141 $len = strlen($data);
142
143 $settings = new Settings($this->optional);
144 $rec = new RecordFactory($settings);
145 $dataRecords = $rec->createRecords($data);
146 $nRecords = sizeof($dataRecords);
147 $mobiHeader = new PalmRecord($settings, $dataRecords, $nRecords, $len, sizeof($this->images));
148 array_unshift($dataRecords, $mobiHeader);
149 $dataRecords = array_merge($dataRecords, $this->images);
150 $dataRecords[] = $rec->createFLISRecord();
151 $dataRecords[] = $rec->createFCISRecord($len);
152 $dataRecords[] = $rec->createEOFRecord();
153 $this->prc = new Prc($settings, $dataRecords);
154 return $this->prc;
155 }
156
157 /**
158 * Save the file locally
159 * @param string $filename Path to save the file
160 */
161 public function save($filename){
162 $prc = $this->preparePRC();
163 $prc->save($filename);
164 }
165
166 /**
167 * Let the client download the file. Warning! No data should be
168 * outputted before or after.
169 * @param string $name Name used for download, usually "title.mobi"
170 */
171 public function download($name){
172 $prc = $this->preparePRC();
173 $data = $prc->serialize();
174 $length = strlen($data);
175
176 if($this->debug) return; //In debug mode, don't start the download
177
178 header("Content-Type: application/x-mobipocket-ebook");
179 header("Content-Disposition: attachment; filename=\"".$name."\"");
180 header("Content-Transfer-Encoding: binary");
181 header("Accept-Ranges: bytes");
182 header("Cache-control: private");
183 header('Pragma: private');
184 header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
185 header("Content-Length: ".$length);
186
187 echo $data;
188 //Finished!
189 }
190
191}
192?>
diff --git a/inc/3rdparty/libraries/MOBIClass/MOBIFile.php b/inc/3rdparty/libraries/MOBIClass/MOBIFile.php
new file mode 100644
index 00000000..349227ae
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/MOBIFile.php
@@ -0,0 +1,157 @@
1<?php
2/**
3 * This is the way MOBI files should be created if you want all features (TOC, images).
4 *
5 * File modified by Dawson for use in eBook Creator
6 * Added pagebreaks and a setting to remove table of contents.
7 */
8
9class MOBIFile extends ContentProvider {
10 const PARAGRAPH = 0;
11 const H2 = 1;
12 const H3 = 2;
13 const IMAGE = 3;
14 const PAGEBREAK = 4;
15
16 private $settings = array("title" => "Unknown Title", "toc" => true);
17 private $parts = array();
18 private $images = array();
19
20 /**
21 * Get the text data (the "html" code)
22 */
23 public function getTextData(){
24 $prefix = "<html><head><guide><reference title='CONTENT' type='toc' filepos=0000000000 /></guide></head><body>";
25
26 $title = "<h1>".$this->settings["title"]."</h1>";
27
28 list($text, $entries) = $this->generateText();
29
30 if($this->settings["toc"]) {
31 $toc = $this->generateTOC($entries); //Generate TOC to get the right length
32 $toc = $this->generateTOC($entries, strlen($prefix)+strlen($toc)+strlen($title)); //Generate the real TOC
33 }
34
35 $suffix = "</body></html>";
36
37 return $prefix.$toc.$title.$text.$suffix;
38 }
39
40 /**
41 * Generate the body's text and the chapter entries
42 * @return array($string, $entries) $string is the html data, $entries
43 * contains the level, the title and the position of the titles.
44 */
45 public function generateText(){
46 $str = "";
47 $entries = array();
48
49 for($i = 0; $i < sizeof($this->parts); $i++){
50 list($type, $data) = $this->parts[$i];
51 $id = "title_".$i;
52 switch($type){
53 case self::PARAGRAPH:
54 $str .= "<p>".$data."</p>";
55 break;
56 case self::PAGEBREAK:
57 $str .= '<mbp:pagebreak/>';
58 break;
59 case self::H2:
60 $entries[] = array("level" => 2, "position" => strlen($str), "title" => $data, "id" => $id);
61 $str .= "<h2 id='" . $id . "'>".$data."</h2>";
62 break;
63 case self::H3:
64 $entries[] = array("level" => 3, "position" => strlen($str), "title" => $data, "id" => $id);
65 $str .= "<h3 id='" . $id . "'>".$data."</h3>";
66 break;
67 case self::IMAGE:
68 $str .= "<img recindex=".str_pad($data+1, 10, "0", STR_PAD_LEFT)." />";
69 break;
70 }
71 }
72 return array($str, $entries);
73 }
74
75 /**
76 * Generate a TOC
77 * @param $entries The entries array generated by generateText
78 * @param $base The zero position
79 */
80 public function generateTOC($entries, $base = 0){
81 $toc = "<h2>Contents</h2>";
82 $toc .= "<blockquote><table summary='Table of Contents'><col/><tbody>";
83 for($i = 0, $len = sizeof($entries); $i < $len; $i++){
84 $entry = $entries[$i];
85 $pos = str_pad($entry["position"]+$base, 10, "0", STR_PAD_LEFT);
86 $toc .= "<tr><td><a href='#".$entry["id"]."' filepos='".$pos."'>".$entry["title"]."</a></td></tr>";
87 }
88 return $toc."</tbody></b></table></blockquote><mbp:pagebreak/>";
89 }
90
91 /**
92 * Get the file records of the images
93 */
94 public function getImages(){
95 return $this->images;
96 }
97
98 /**
99 * Get the metadata
100 */
101 public function getMetaData(){
102 return $this->settings;
103 }
104
105 /**
106 * Change the file's settings. For example set("author", "John Doe") or set("title", "The adventures of John Doe").
107 * @param $key Key of the setting to insert.
108 */
109 public function set($key, $value){
110 $this->settings[$key] = $value;
111 }
112
113 /**
114 * Get the file's settings.
115 */
116 public function get($key){
117 return $this->settings[$key];
118 }
119
120 /**
121 * Append a paragraph of text to the file.
122 * @param string $text The text to insert.
123 */
124 public function appendParagraph($text){
125 $this->parts[] = array(self::PARAGRAPH, $text);
126 }
127
128 /**
129 * Append a chapter title (H2)
130 * @param string $title The title to insert.
131 */
132 public function appendChapterTitle($title){
133 $this->parts[] = array(self::H2, $title);
134 }
135
136 /**
137 * Append a section title (H3)
138 * @param string $title The title to insert.
139 */
140 public function appendSectionTitle($title){
141 $this->parts[] = array(self::H3, $title);
142 }
143
144 public function appendPageBreak() {
145 $this->parts[] = array(self::PAGEBREAK, null);
146 }
147
148 /**
149 * Append an image.
150 * @param resource $img An image file (for example, created by `imagecreate`)
151 */
152 public function appendImage($img){
153 $imgIndex = sizeof($this->images);
154 $this->images[] = new FileRecord(new Record(ImageHandler::CreateImage($img)));
155 $this->parts[] = array(self::IMAGE, $imgIndex);
156 }
157} \ No newline at end of file
diff --git a/inc/3rdparty/libraries/MOBIClass/MultipleFileHandler.php b/inc/3rdparty/libraries/MOBIClass/MultipleFileHandler.php
new file mode 100644
index 00000000..e9792816
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/MultipleFileHandler.php
@@ -0,0 +1,136 @@
1<?php
2
3/**
4 * Description of MultipleFileHandler
5 *
6 * @author Sander
7 */
8abstract class MultipleFileHandler extends ContentProvider {
9 /**
10 * @var array
11 */
12 private $files = array();
13 /**
14 * @var array
15 */
16 private $images = array();
17 /**
18 * @var array
19 */
20 private $metadata = array();
21
22 private $toc = array();
23
24 /**
25 * Add a page to the file
26 * @param string $contents Contents of the chapter/page
27 * @param string $title Optional, title of the chapter/page. Will automatically add a h2
28 * before the contents
29 */
30 public function addPage($contents, $title = ""){
31 if($title != ""){
32 //TODO: Add in TOC (and add a way of generating it
33 $contents = "<h2>".$title."</h2>".$contents."<mbp:pagebreak>";
34 }
35 $pos = 0;
36
37 if(sizeof($this->toc) > 0){
38 $lastToc = $this->toc[sizeof($this->toc)-1];
39 $lastFile = $this->files[sizeof($this->files)-1];
40 $pos = $lastToc["pos"] + strlen($lastFile) + 1;
41 }
42
43 $this->files[] = $contents;
44 $this->toc[] = array("title"=>$title, "pos"=>$pos);
45 }
46
47 /**
48 * Add an image to the file
49 * @param string $imageContents Data string containing the binary data of the image
50 * @return int The reference of the image
51 */
52 public function addImage($imageContents){
53 $this->images[] = $imageContents;
54 return sizeof($this->images)-1;
55 }
56
57 /**
58 * Add an image to the file
59 * @param string $url Url to the image
60 * @return int The reference of the image, false if the image couldn't be downloaded
61 */
62 public function addImageFromUrl($url){
63 $image = ImageHandler::DownloadImage($url);
64
65 if($image === false) return false;
66 return $this->addImage($image);
67 }
68
69 /**
70 * Set the metadata
71 * @param string $key Key
72 * @param string $value Value
73 */
74 public function setMetadata($key, $value){
75 $this->metadata[$key] = $value;
76 }
77
78 /**
79 * Get the text data to be integrated in the MOBI file
80 * @return string
81 */
82 public function getTextData(){
83 $data = implode("\n", $this->files);
84 $begin = "<html><head><guide><reference title='CONTENT' type='toc' filepos=0000000000 /></guide></head><body>";
85 $beforeTOC = $begin.$data;
86
87 $tocPos = strlen($beforeTOC);
88
89 $toc = $this->generateTOC(strlen($begin));
90
91 $customBegin = "<html><head><guide><reference title='CONTENT' type='toc' filepos=".$this->forceLength($tocPos, 10)." /></guide></head><body>";
92 $data = $customBegin.$data.$toc."</body></html>";
93 return $data;
94 }
95
96 public function forceLength($n, $l){
97 $str = $n."";
98 $cur = strlen($str);
99 while($cur < $l){
100 $str = "0".$str;
101 $cur++;
102 }
103 return $str;
104 }
105
106 public function generateTOC($base = 0){
107 $toc = "<h2>Contents</h2>";
108 $toc .= "<blockquote><table summary='Table of Contents'><b><col/><col/><tbody>";
109 for($i = 0, $len = sizeof($this->toc); $i < $len; $i++){
110 $entry = $this->toc[$i];
111 $position = $entry["pos"]+$base;
112 $toc .= "<tr><td>".($i+1).".</td><td><a filepos=".$position.">".$entry["title"]."</a></td></tr>";
113 }
114 $toc .= "</tbody></b></table></blockquote>";
115
116 return $toc;
117 }
118 /**
119 * Get the images (an array containing the jpeg data). Array entry 0 will
120 * correspond to image record 0.
121 * @return array
122 */
123 public function getImages(){
124 return $this->images;
125 }
126
127 /**
128 * Get the metadata in the form of a hashtable (for example, title or author).
129 * @return array
130 */
131 public function getMetaData(){
132 return $this->metadata;
133 }
134
135}
136?>
diff --git a/inc/3rdparty/libraries/MOBIClass/OnlineArticle.php b/inc/3rdparty/libraries/MOBIClass/OnlineArticle.php
new file mode 100644
index 00000000..ec3182fe
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/OnlineArticle.php
@@ -0,0 +1,116 @@
1<?php
2
3/**
4 * Description of OnlineArticle
5 *
6 * @author Sander
7 */
8class OnlineArticle extends ContentProvider {
9 private $text;
10 private $images;
11 private $metadata = array();
12 private $imgCounter = 0;
13
14 public function __construct($url) {
15 if (!preg_match('!^https?://!i', $url)) $url = 'http://'.$url;
16
17 $data = Http::Request($url);
18 //$enc = mb_detect_encoding($str, "UTF-8,ISO-8859-1,ASCII");
19 $html = mb_convert_encoding($data, "UTF-8", "UTF-8,ISO-8859-1,ASCII");
20 //$html = utf8_encode($html);
21 $r = new Readability($html, $url);
22 $r->init();
23 if(!isset($this->metadata["title"])){
24 $this->metadata["title"] = CharacterEntities::convert(strip_tags($r->getTitle()->innerHTML));
25 }
26 if(!isset($this->metadata["author"])){
27 $parts = parse_url($url);
28 $this->metadata["author"] = $parts["host"];
29 }
30
31 $article = $r->getContent()->innerHTML;
32 if(substr($article, 0, 5) == "<body"){
33 $article = "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'/></head>".$article."</html>";
34 }else{
35 $article = "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'/></head><body>".$article."</body></html>";
36 }
37 $doc = new DOMDocument();
38 @$doc->loadHTML($article) or die($article);
39 $doc->normalizeDocument();
40
41 $this->images = $this->handleImages($doc, $url);
42 $this->text = $doc->saveHTML();
43 }
44
45 /**
46 * Get the text data to be integrated in the MOBI file
47 * @return string
48 */
49 public function getTextData(){
50 return $this->text;
51 }
52 /**
53 * Get the images (an array containing the jpeg data). Array entry 0 will
54 * correspond to image record 0.
55 * @return array
56 */
57 public function getImages(){
58 return $this->images;
59 }
60 /**
61 * Get the metadata in the form of a hashtable (for example, title or author).
62 * @return array
63 */
64 public function getMetaData(){
65 return $this->metadata;
66 }
67 /**
68 *
69 * @param DOMElement $dom
70 * @return array
71 */
72 private function handleImages($dom, $url){
73 $images = array();
74
75 $parts = parse_url($url);
76
77 $savedImages = array();
78
79 $imgElements = $dom->getElementsByTagName('img');
80 foreach($imgElements as $img) {
81 $src = $img->getAttribute("src");
82
83 $is_root = false;
84 if(substr($src, 0, 1) == "/"){
85 $is_root = true;
86 }
87
88 $parsed = parse_url($src);
89
90 if(!isset($parsed["host"])){
91 if($is_root){
92 $src = http_build_url($url, $parsed, HTTP_URL_REPLACE);
93 }else{
94 $src = http_build_url($url, $parsed, HTTP_URL_JOIN_PATH);
95 }
96 }
97 $img->setAttribute("src", "");
98 if(isset($savedImages[$src])){
99 $img->setAttribute("recindex", $savedImages[$src]);
100 }else{
101 $image = ImageHandler::DownloadImage($src);
102
103 if($image !== false){
104 $images[$this->imgCounter] = new FileRecord(new Record($image));
105
106 $img->setAttribute("recindex", $this->imgCounter);
107 $savedImages[$src] = $this->imgCounter;
108 $this->imgCounter++;
109 }
110 }
111 }
112
113 return $images;
114 }
115}
116?>
diff --git a/inc/3rdparty/libraries/MOBIClass/PalmRecord.php b/inc/3rdparty/libraries/MOBIClass/PalmRecord.php
new file mode 100644
index 00000000..d0de8dfe
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/PalmRecord.php
@@ -0,0 +1,136 @@
1<?php
2/**
3 * A Record of a PDB file
4 *
5 * @author Sander
6 */
7class PalmRecord extends FileObject {
8 /**
9 * @var FileElement
10 */
11 private $elements;
12
13 public function __construct($settings, $records, $textRecords, $textLength, $images){
14 $this->elements = new FileElement(array(
15 "compression"=>new FileShort(),
16 "unused"=>new FileShort(),
17 "textLength"=>new FileInt(),
18 "recordCount"=>new FileShort(),
19 "recordSize"=>new FileShort(),
20 "encryptionType"=>new FileShort(),
21 "unused2"=>new FileShort(),
22 //MOBI Header
23 "mobiIdentifier"=>new FileString("MOBI", 4),
24 "mobiHeaderLength"=>new FileInt(),
25 "mobiType"=>new FileInt(),
26 "textEncoding"=>new FileInt(),
27 "uniqueID"=>new FileInt(),
28 "fileVersion"=>new FileInt(),
29 "reserved"=>new FileString(40),
30 "firstNonBookIndex"=>new FileInt(),
31 "fullNameOffset"=>new FileInt(),
32 "fullNameLength"=>new FileInt(),
33 "locale"=>new FileInt(),
34 "inputLanguage"=>new FileInt(),
35 "outputLanguage"=>new FileInt(),
36 "minimumVersion"=>new FileInt(),
37 "firstImageIndex"=>new FileInt(),
38 "huffmanRecordOffset"=>new FileInt(),
39 "huffmanRecordCount"=>new FileInt(),
40 "unused3"=>new FileString(8),
41 "exthFlags"=>new FileInt(0x40),
42 "unknown"=>new FileString(32),
43 "drmOffset"=>new FileInt(0xFFFFFFFF),
44 "drmCount"=>new FileShort(0xFFFFFFFF),
45 "drmSize"=>new FileShort(),
46 "drmFlags"=>new FileInt(),
47 "mobiFiller"=>new FileString(72),
48 //EXTH Header
49 "exthIdentifier"=>new FileString("EXTH", 4),
50 "exthHeaderLength"=>new FileInt(),
51 "exthRecordCount"=>new FileInt(),
52 "exthRecords"=>new FileElement(),
53 "exthPadding"=>new FileString(),
54 //"fullNamePadding"=>new FileString(100),
55 "fullName"=>new FileString()
56 ));
57
58 //Set values from the info block
59 foreach($settings->values as $name => $val){
60 //echo $name.", ";
61 if($this->elements->exists($name)){
62 $this->elements->get($name)->set($settings->get($name));
63 }
64 }
65
66 $els = $settings->values;
67
68 $exthElems = new FileElement();
69 $i = 0;
70 $l = 0;
71 foreach($els as $name=>$val){
72 $type = EXTHHelper::textToType($name);
73 if($type !== false){
74 $type = new FileInt($type);
75 $length = new FileInt(8+strlen($val));
76 $data = new FileString($val);
77 $l += 8+strlen($val);
78 $exthElems->add("type".$i, $type);
79 $exthElems->add("length".$i, $length);
80 $exthElems->add("data".$i, $data);
81 $i++;
82 }
83 }
84
85 if($images > 0){
86 $this->elements->get("firstImageIndex")->set($textRecords+1);
87 }
88 $this->elements->get("firstNonBookIndex")->set($textRecords+2+$images);
89 $this->elements->get("reserved")->set(str_pad("", 40, chr(255), STR_PAD_RIGHT));
90 $this->elements->get("exthRecordCount")->set($i);
91 $this->elements->set("exthRecords", $exthElems);
92 $pad = $l%4;
93 $pad = (4-$pad)%4;
94 $this->elements->get("exthPadding")->set(str_pad("", $pad, "\0", STR_PAD_RIGHT));
95 $this->elements->get("exthHeaderLength")->set(12+$l+$pad);
96
97
98 $this->elements->get("recordCount")->set($textRecords);
99
100 $this->elements->get("fullNameOffset")->set($this->elements->offsetToEntry("fullName"));
101 $this->elements->get("fullNameLength")->set(strlen($settings->get("title")));
102 $this->elements->get("fullName")->set($settings->get("title"));
103 $this->elements->get("textLength")->set($textLength);
104 }
105
106 public function getByteLength(){
107 return $this->getLength();
108 }
109
110 public function getLength(){
111 return $this->elements->getByteLength();
112 }
113
114 public function get(){
115 return $this;
116 }
117
118 public function set($elements){
119 throw new Exception("Unallowed set");
120 }
121
122 public function serialize() {
123 return $this->elements->serialize();
124 }
125
126 public function unserialize($data) {
127 $this->elements->unserialize($data);
128 }
129
130 public function __toString(){
131 $output = "PalmDoc Record (".$this->getByteLength()." bytes):\n";
132 $output .= $this->elements;
133 return $output;
134 }
135}
136?>
diff --git a/inc/3rdparty/libraries/MOBIClass/Prc.php b/inc/3rdparty/libraries/MOBIClass/Prc.php
new file mode 100644
index 00000000..c40b5805
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/Prc.php
@@ -0,0 +1,97 @@
1<?php
2
3/**
4 * Description of Prc
5 *
6 * @author Sander
7 */
8class Prc extends FileElement {
9 public function __construct($settings, $records){
10 parent::__construct(array(
11 "title"=>new FileString(32),
12 "attributes"=>new FileShort(),
13 "version"=>new FileShort(),
14 "creationTime"=>new FileDate(),
15 "modificationTime"=>new FileDate(),
16 "backupTime"=>new FileDate(),
17 "modificationNumber"=>new FileInt(),
18 "appInfoID"=>new FileInt(),
19 "sortInfoID"=>new FileInt(),
20 "prcType"=>new FileString(4),
21 "creator"=>new FileString(4),
22 "uniqueIDSeed"=>new FileInt(),
23 "nextRecordListID"=>new FileInt(),
24 "numberRecords"=>new FileShort(),
25 "recordList"=>new FileElement(),
26 "filler"=>new FileShort(),
27 "records"=>new FileElement()
28 ));
29
30 //Set values from the info block
31 foreach($this->elements as $name => $val){
32 if($settings->exists($name)){
33 $this->get($name)->set($settings->get($name));
34 }
35 }
36
37 $this->get("numberRecords")->set(sizeof($records));
38
39 $i = 0;
40 foreach($records as $record){
41 $offset = new FileInt();
42 $attr = new FileByte();
43 $uniqueID = new FileTri($i);
44
45 $this->elements["recordList"]->add("Rec".$i, new FileElement(array(
46 "offset"=>$offset,
47 "attribute"=>$attr,
48 "uniqueID"=>$uniqueID
49 )));
50
51 $this->elements["records"]->add("Rec".$i, $record);
52 $i++;
53 }
54
55 $this->updateOffsets($records);
56 }
57
58 public function getByteLength(){
59 throw new Exception("Test");
60 }
61
62 public function updateOffsets($records){
63 $base = $this->offsetToEntry("records");
64
65 $i = 0;
66
67 foreach($records as $record){
68 $el = $this->elements["recordList"]->get("Rec".$i);
69
70 $local = $this->elements["records"]->offsetToEntry("Rec".$i);
71
72 $el->get("offset")->set($base+$local);
73
74 $i++;
75 }
76 }
77
78 public function save($file){
79 $handle = fopen($file, "w");
80 fwrite($handle, $this->serialize());
81 fclose($handle);
82 }
83
84 public function output(){
85 echo $this->serialize();
86 }
87
88 public function __toString(){
89 $output = "Prc (".$this->getByteLength()." bytes): {\n";
90 foreach($this->elements as $key=>$value){
91 $output .= "\t".$key.": ".$value."\n";
92 }
93 $output .= "}";
94 return $output;
95 }
96}
97?>
diff --git a/inc/3rdparty/libraries/MOBIClass/PreprocessedArticle.php b/inc/3rdparty/libraries/MOBIClass/PreprocessedArticle.php
new file mode 100644
index 00000000..2e992404
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/PreprocessedArticle.php
@@ -0,0 +1,89 @@
1<?php
2
3/**
4 * Description of OnlineArticle
5 *
6 * @author Sander
7 */
8class PreprocessedArticle extends ContentProvider {
9 private $text;
10 private $images;
11 private $metadata = array();
12 private $imgCounter = 0;
13
14 public function __construct($textData, $imageLinks, $metadata) {
15 $this->text = $textData;
16 $this->metadata = $metadata;
17
18 $this->images = $this->downloadImages($imageLinks);
19 }
20
21 /**
22 * Create a Preprocessed article from a json string
23 * @param string $json JSON data. Should be of the following format:
24 * {"text": "TEXT", "images: ["imageURL1", "imageURL2"], "metadata": {"key": "value"}}
25 *
26 * Note: Any image tags should have the recindex attribute set to the appropriate index (the
27 * same index as the image in the array)
28 * @return PreprocessedArticle The generated preprocessed array
29 */
30 static public function CreateFromJson($json){
31 $data = json_decode($json);
32 return new PreprocessedArticle($data["text"], $data["images"], $data["metadata"]);
33 }
34
35 /**
36 * Get the text data to be integrated in the MOBI file
37 * @return string
38 */
39 public function getTextData(){
40 return $this->text;
41 }
42 /**
43 * Get the images (an array containing the jpeg data). Array entry 0 will
44 * correspond to image record 0.
45 * @return array
46 */
47 public function getImages(){
48 return $this->images;
49 }
50 /**
51 * Get the metadata in the form of a hashtable (for example, title or author).
52 * @return array
53 */
54 public function getMetaData(){
55 return $this->metadata;
56 }
57 /**
58 *
59 * @param DOMElement $dom
60 * @return array
61 */
62 private function downloadImages($links){
63 $images = array();
64 foreach($links as $link) {
65 $imgFile = @imagecreatefromstring(Http::Request($link));
66
67 if($imgFile === false){
68 $imgFile = @imagecreate(1, 1);
69 $black = @imagecolorallocate($imgFile, 255, 255, 255);
70 }
71 if($imgFile !== false){
72 @imagefilter($imgFile, IMG_FILTER_GRAYSCALE);
73
74 ob_start();
75 @imagejpeg($imgFile);
76 $image = ob_get_contents();
77 ob_end_clean();
78
79 $images[$this->imgCounter] = new FileRecord(new Record($image));
80 imagedestroy($imgFile);
81
82 $this->imgCounter++;
83 }
84 }
85
86 return $images;
87 }
88}
89?>
diff --git a/inc/3rdparty/libraries/MOBIClass/RecognizeURL.php b/inc/3rdparty/libraries/MOBIClass/RecognizeURL.php
new file mode 100644
index 00000000..6319ed57
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/RecognizeURL.php
@@ -0,0 +1,16 @@
1<?php
2
3/**
4 * Description of RecognizeURL
5 *
6 * @author Sander
7 */
8class RecognizeURL {
9 public static function GetContentHandler($url){
10 if(FanFictionNet::Matches($url)){
11 return new FanFictionNet($url);
12 }
13 return null;
14 }
15}
16?>
diff --git a/inc/3rdparty/libraries/MOBIClass/Record.php b/inc/3rdparty/libraries/MOBIClass/Record.php
new file mode 100644
index 00000000..3cb39582
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/Record.php
@@ -0,0 +1,96 @@
1<?php
2/**
3 * A Record of a PDB file
4 *
5 * @author Sander
6 */
7class Record extends FileObject {
8 /**
9 * Data in the record
10 * @var string
11 */
12 private $data;
13 /**
14 * Length of the record
15 * @var int
16 */
17 private $length;
18
19 /**
20 * Create a record
21 * @param string $data Data contained in the record
22 * @param int $length Length of the record (if set to -1,
23 * the length of $data will be taken)
24 */
25 public function __construct($data = "", $length = -1){
26 $this->data = $data;
27 if($length >= 0){
28 $this->length = $length;
29 }else{
30 $this->length = strlen($data);
31 }
32 }
33
34 public function compress($compression_method){
35 switch($compression_method){
36 case NO_COMPRESSION:
37 //Finished!
38 break;
39 case PALMDOC_COMPRESSION:
40 throw new Exception("Not implemented yet");
41 break;
42 case HUFF:
43 throw new Exception("Not implemented yet");
44 break;
45 default:
46 throw new Exception("Invalid argument");
47 }
48 }
49
50 public function getByteLength(){
51 return $this->getLength();
52 }
53
54 /**
55 * Get the length of the record
56 * @return int Length of the data
57 */
58 public function getLength(){
59 return $this->length;
60 }
61
62 /**
63 * Get the data contained in the record
64 * @return string Data contained in the record
65 */
66 public function get(){
67 return $this->data;
68 }
69
70 /**
71 * Set the data contained in the record
72 * @param string $value Data contained in the record
73 */
74 public function set($value){
75 $this->data = $value;
76 }
77
78 public function serialize(){
79 return $this->data;
80 }
81 public function unserialize($data){
82 __construct($data);
83 }
84
85 public function __toString() {
86 $toShow = $this->data;
87 if(strlen($this->data) > 103){
88 $toShow = substr($this->data, 0, 100)."...";
89 }
90 $out = "Record: {\n";
91 $out .= "\t".htmlspecialchars($toShow)."\n";
92 $out .= "}";
93 return $out;
94 }
95}
96?>
diff --git a/inc/3rdparty/libraries/MOBIClass/RecordFactory.php b/inc/3rdparty/libraries/MOBIClass/RecordFactory.php
new file mode 100644
index 00000000..12806fe3
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/RecordFactory.php
@@ -0,0 +1,115 @@
1<?php
2
3/**
4 * Helper class to help with creating records from a
5 * long data stream
6 *
7 * @author Sander
8 */
9class RecordFactory {
10 /**
11 * Settings for the record factory
12 * @var Settings
13 */
14 private $settings;
15
16 /**
17 * Create the helper class
18 * @param Settings $settings The Settings to be used for the records
19 */
20 public function __construct($settings){
21 $this->settings = $settings;
22 }
23
24 /**
25 * Create records from a data string
26 * @param string $data
27 * @return array(Record)
28 */
29 public function createRecords($data){
30 $records = array();
31 $size = $this->settings->get("recordSize");
32 $compression = $this->settings->get("compression");
33
34 $dataEntries = mb_str_split($data, $size);
35
36 for($i = 0, $len = sizeof($dataEntries); $i < $len; $i++){
37 $records[$i] = new Record($dataEntries[$i]);
38 $records[$i]->compress($compression);
39 }
40
41 return $records;
42 }
43
44 public function createEOFRecord(){
45 return new Record(0xe98e0d0a);
46 }
47
48 public function createFCISRecord($textLength){
49 $r = "FCIS";
50 $r .= $this->asString(20, 4);
51 $r .= $this->asString(16, 4);
52 $r .= $this->asString(1, 4);
53 $r .= $this->asString(0, 4);
54 $r .= $this->asString($textLength, 4);
55 $r .= $this->asString(0, 4);
56 $r .= $this->asString(32, 4);
57 $r .= $this->asString(8, 4);
58 $r .= $this->asString(1, 2);
59 $r .= $this->asString(1, 2);
60 $r .= $this->asString(0, 4);
61 return new Record($r);
62 }
63
64 public function createFLISRecord(){
65 $r = "FLIS";
66 $r .= $this->asString(8, 4);
67 $r .= $this->asString(65, 2);
68 $r .= $this->asString(0, 2);
69 $r .= $this->asString(0, 4);
70 $r .= $this->asString(-1, 4);
71 $r .= $this->asString(1, 2);
72 $r .= $this->asString(3, 2);
73 $r .= $this->asString(3, 4);
74 $r .= $this->asString(1, 4);
75 $r .= $this->asString(-1, 4);
76 return new Record($r);
77 }
78
79 private function asString($int, $size){
80 $out = "";
81 for($i = 0; $i < $size; $i++){
82 if($i > 0) $out = " ".$out;
83 $byte = dechex($int & 0xFF);
84 if(strlen($byte) == 1) $byte = "0".$byte;
85 $out = $byte.$out;
86 $int = $int >> 8;
87 }
88 return $out;
89 }
90
91 public function __toString() {
92 $out = "Record Factory: {\n";
93 $out .= "\tRecord Size: ".$this->settings->get("recordSize")."\n";
94 $out .= "\tCompression: ".$this->settings->get("compression")."\n";
95 $out .= "}";
96 return $out;
97 }
98}
99function mb_str_split($string, $split_length = 1){
100 mb_internal_encoding('UTF-8');
101 mb_regex_encoding('UTF-8');
102
103 $split_length = ($split_length <= 0) ? 1 : $split_length;
104
105 $mb_strlen = mb_strlen($string, 'utf-8');
106
107 $array = array();
108
109 for($i = 0; $i < $mb_strlen; $i += $split_length){
110 $array[] = mb_substr($string, $i, $split_length);
111 }
112
113 return $array;
114}
115?>
diff --git a/inc/3rdparty/libraries/MOBIClass/Settings.php b/inc/3rdparty/libraries/MOBIClass/Settings.php
new file mode 100644
index 00000000..ddcf2054
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/Settings.php
@@ -0,0 +1,97 @@
1<?php
2
3/**
4 * Description of Settings
5 *
6 * @author Sander
7 */
8class Settings {
9 /**
10 * Values of the settings
11 * @var array
12 */
13 public $values;
14
15 /**
16 * Construct a Settings object with the default settings. If necessary,
17 * those settings can be extended with additional settings
18 * @param array $additionalSettings Additional settings to add (should
19 * be added with a key/value pair format.
20 */
21 public function __construct($additionalSettings = array()) {
22 // Most values shouldn't be changed (the result will be an invalid file)
23 $this->values = array(
24 "attributes"=>0,
25 "version"=>0,
26 "creationTime"=>time()+94694400,
27 "modificationTime"=>time()+94694400,
28 "backupTime"=>0,
29 "modificationNumber"=>0,
30 "appInfoID"=>0,
31 "sortInfoID"=>0,
32 "prcType"=>"BOOK",
33 "creator"=>"MOBI",
34 "uniqueIDSeed"=>rand(),
35 "nextRecordListID"=>0,
36 "recordAttributes"=>0,
37 "compression"=>NO_COMPRESSION,
38 "recordSize"=>RECORD_SIZE,
39 "encryptionType"=>NO_ENCRYPTION,
40 "mobiIdentifier"=>"MOBI",
41 "mobiHeaderLength"=>0xe8,
42 "mobiType"=>MOBIPOCKET_BOOK,
43 "textEncoding"=>UTF8,
44 "uniqueID"=>rand(),
45 "fileVersion"=>6,
46 "locale"=>0x09,
47 "inputLanguage"=>0,
48 "outputLanguage"=>0,
49 "minimumVersion"=>6,
50 "huffmanRecordOffset"=>0,
51 "huffmanRecordCount"=>0,
52 "exthFlags"=>0x40,
53 "drmOffset"=>0xFFFFFFFF,
54 "drmCount"=>0,
55 "drmSize"=>0,
56 "drmFlags"=>0,
57 "extraDataFlags"=>0,
58 "exthIdentifier"=>"EXTH",
59 // These can be changed without any risk
60 "title"=>"Unknown title",
61 "author"=>"Unknown author",
62 "subject"=>"Unknown subject"
63 );
64
65 foreach($additionalSettings as $key=>$value){
66 $this->values[$key] = $value;
67 }
68 }
69
70 /**
71 * Get a value from the settings
72 * @param string $key Key of the setting
73 * @return mixed The value of the setting
74 */
75 public function get($key){
76 return $this->values[$key];
77 }
78
79 /**
80 * Checks if a value is set
81 * @param string $key Key of the setting
82 * @return bool True if the value exists
83 */
84 public function exists($key){
85 return isset($this->values[$key]);
86 }
87
88 public function __toString() {
89 $out = "Settings: {\n";
90 foreach($this->values as $key=>$value){
91 $out .= "\t".$key.": ".$value."\n";
92 }
93 $out .= "}";
94 return $out;
95 }
96}
97?>
diff --git a/inc/3rdparty/libraries/MOBIClass/constants.php b/inc/3rdparty/libraries/MOBIClass/constants.php
new file mode 100644
index 00000000..bd363118
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/constants.php
@@ -0,0 +1,11 @@
1<?php
2define("NO_COMPRESSION", 1);
3define("PALMDOC_COMPRESSION", 2);
4define("HUFF", 17480);
5define("RECORD_SIZE", 4096);
6
7define("NO_ENCRYPTION", 0);
8
9define("MOBIPOCKET_BOOK", 2);
10define("CP1252", 1252);
11define("UTF8", 65001); \ No newline at end of file
diff --git a/inc/3rdparty/libraries/MOBIClass/downloaders/FanFictionNet.php b/inc/3rdparty/libraries/MOBIClass/downloaders/FanFictionNet.php
new file mode 100644
index 00000000..65d5a466
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/downloaders/FanFictionNet.php
@@ -0,0 +1,125 @@
1<?php
2
3/**
4 * Description of FanFictionNet
5 *
6 * @author Sander
7 */
8class FanFictionNet extends MultipleFileHandler {
9 private static $prefix = "http://www.fanfiction.net/s/";
10 private $downloadedMetadata = false;
11 private $id = 0;
12 private $chapterCount = -1;
13
14 public function __construct($url) {
15 $ending = substr($url, strlen(self::$prefix));
16 $this->id = intval(substr($ending, 0, strpos($ending, "/")));
17
18 for($i = 1; $i <= max(1, $this->chapterCount); $i++){
19 $this->addChapter($i);
20 }
21 }
22
23 private function addChapter($n){
24 $doc = new DOMDocument();
25 $file = Http::Request(self::$prefix.$this->id."/".$n."/");
26 @$doc->loadHTML($file) or die($file);
27
28 if(!$this->downloadedMetadata){
29 $this->loadMetadata($doc);
30 $this->downloadedMetadata = true;
31 }
32 if($this->chapterCount < 0){
33 $this->chapterCount = $this->getNumberChapters($doc);
34
35 if($this->chapterCount > 4){
36 die("Too many files to download, don't use php for this!");
37 }
38 }
39
40 $textEl = $doc->getElementById("storytext");
41 if($textEl == null) die("Error: ".$doc->saveHTML());
42 $horizontalRulebars = $doc->getElementsByTagName('hr');
43 /**
44 * @var DOMNode
45 */
46 $hr;
47 foreach($horizontalRulebars as $hr) {
48 $hr->setAttribute("size", null);
49 $hr->setAttribute("noshade", null);
50 }
51 $text = $this->innerHtml($textEl);
52
53 $title = "";
54 $selects = $doc->getElementsByTagName('select');
55 foreach($selects as $select) {
56 if($select->hasAttribute("name") && $select->getAttribute("name") == "chapter"){
57 $options = $select->getElementsByTagName("option");
58
59 $test = $n.". ";
60 foreach($options as $option){
61 $val = $option->nodeValue;
62 if(substr($val, 0, strlen($test)) == $test){
63 $title = substr($val, strlen($test));
64 break;
65 }
66 }
67 break;
68 }
69 }
70 $this->addPage($text, $title);
71 }
72
73 private function getNumberChapters($doc){
74 $selects = $doc->getElementsByTagName('select');
75 foreach($selects as $select) {
76 if($select->hasAttribute("name") && $select->getAttribute("name") == "chapter"){
77 $options = $select->getElementsByTagName("option");
78
79 $count = $options->length;
80 return $count;
81 }
82 }
83 }
84
85 private function loadMetadata($doc){
86 //Author
87 $links = $doc->getElementsByTagName('a');
88 foreach($links as $link) {
89 if($link == null){
90 var_dump($link);
91 }
92 if($link->hasAttribute("href") && substr($link->getAttribute("href"), 0, 3) == "/u/"){
93 $this->setMetadata("author", $link->nodeValue);
94 }
95 }
96 //Title
97 /*
98 $links = $doc->getElementsByTagName('link');
99 foreach($links as $link) {
100 if($link->hasAttribute("rel") && $link->getAttribute("rel") == "canonical"){
101 $url = $link->getAttribute("href");
102 $title = str_replace("_", " ", substr($url, strrpos($url, "/")+1));
103 $this->setMetadata("title", $title);
104 }
105 }*/
106
107 //TODO: Find a more reliable way to extract the title
108 $title = $doc->getElementsByTagName("b")->item(0)->nodeValue;
109 $this->setMetadata("title", $title);
110 }
111
112 private function innerHtml($node){
113 $doc = new DOMDocument();
114 foreach ($node->childNodes as $child)
115 $doc->appendChild($doc->importNode($child, true));
116
117 return $doc->saveHTML();
118 }
119
120 public static function Matches($url){
121 //TODO: Implement with regex
122 return strpos($url, self::$prefix) !== false;
123 }
124}
125?>
diff --git a/inc/3rdparty/libraries/MOBIClass/http_build_url.php b/inc/3rdparty/libraries/MOBIClass/http_build_url.php
new file mode 100644
index 00000000..b475edb0
--- /dev/null
+++ b/inc/3rdparty/libraries/MOBIClass/http_build_url.php
@@ -0,0 +1,94 @@
1<?php
2if(!is_callable("http_build_url")){
3 define('HTTP_URL_REPLACE', 1); // Replace every part of the first URL when there's one of the second URL
4 define('HTTP_URL_JOIN_PATH', 2); // Join relative paths
5 define('HTTP_URL_JOIN_QUERY', 4); // Join query strings
6 define('HTTP_URL_STRIP_USER', 8); // Strip any user authentication information
7 define('HTTP_URL_STRIP_PASS', 16); // Strip any password authentication information
8 define('HTTP_URL_STRIP_AUTH', 32); // Strip any authentication information
9 define('HTTP_URL_STRIP_PORT', 64); // Strip explicit port numbers
10 define('HTTP_URL_STRIP_PATH', 128); // Strip complete path
11 define('HTTP_URL_STRIP_QUERY', 256); // Strip query string
12 define('HTTP_URL_STRIP_FRAGMENT', 512); // Strip any fragments (#identifier)
13 define('HTTP_URL_STRIP_ALL', 1024); // Strip anything but scheme and host
14
15 // Build an URL
16 // The parts of the second URL will be merged into the first according to the flags argument.
17 //
18 // @param mixed (Part(s) of) an URL in form of a string or associative array like parse_url() returns
19 // @param mixed Same as the first argument
20 // @param int A bitmask of binary or'ed HTTP_URL constants (Optional)HTTP_URL_REPLACE is the default
21 // @param array If set, it will be filled with the parts of the composed url like parse_url() would return
22 function http_build_url($url, $parts = array (), $flags = HTTP_URL_REPLACE, &$new_url = false) {
23 $keys = array (
24 'user',
25 'pass',
26 'port',
27 'path',
28 'query',
29 'fragment'
30 );
31
32 // HTTP_URL_STRIP_ALL becomes all the HTTP_URL_STRIP_Xs
33 if ($flags & HTTP_URL_STRIP_ALL) {
34 $flags |= HTTP_URL_STRIP_USER;
35 $flags |= HTTP_URL_STRIP_PASS;
36 $flags |= HTTP_URL_STRIP_PORT;
37 $flags |= HTTP_URL_STRIP_PATH;
38 $flags |= HTTP_URL_STRIP_QUERY;
39 $flags |= HTTP_URL_STRIP_FRAGMENT;
40 }
41 // HTTP_URL_STRIP_AUTH becomes HTTP_URL_STRIP_USER and HTTP_URL_STRIP_PASS
42 else if ($flags & HTTP_URL_STRIP_AUTH) {
43 $flags |= HTTP_URL_STRIP_USER;
44 $flags |= HTTP_URL_STRIP_PASS;
45 }
46
47 // Parse the original URL
48 $parse_url = parse_url($url);
49
50 // Scheme and Host are always replaced
51 if (isset($parts['scheme']))
52 $parse_url['scheme'] = $parts['scheme'];
53
54 if (isset($parts['host']))
55 $parse_url['host'] = $parts['host'];
56
57 // (If applicable) Replace the original URL with it's new parts
58 if ($flags & HTTP_URL_REPLACE) {
59 foreach ($keys as $key) {
60 if (isset($parts[$key]))
61 $parse_url[$key] = $parts[$key];
62 }
63 } else {
64 // Join the original URL path with the new path
65 if (isset($parts['path']) && ($flags & HTTP_URL_JOIN_PATH)) {
66 if (isset($parse_url['path']))
67 $parse_url['path'] = rtrim(str_replace(basename($parse_url['path']), '', $parse_url['path']), '/') . '/' . ltrim($parts['path'], '/');
68 else
69 $parse_url['path'] = $parts['path'];
70 }
71
72 // Join the original query string with the new query string
73 if (isset($parts['query']) && ($flags & HTTP_URL_JOIN_QUERY)) {
74 if (isset($parse_url['query']))
75 $parse_url['query'] .= '&' . $parts['query'];
76 else
77 $parse_url['query'] = $parts['query'];
78 }
79 }
80
81 // Strips all the applicable sections of the URL
82 // Note: Scheme and Host are never stripped
83 foreach ($keys as $key) {
84 if ($flags & (int)constant('HTTP_URL_STRIP_' . strtoupper($key)))
85 unset($parse_url[$key]);
86 }
87
88 $new_url = $parse_url;
89
90 return ((isset($parse_url['scheme'])) ? $parse_url['scheme'] . '://' : '') . ((isset($parse_url['user'])) ? $parse_url['user'] . ((isset($parse_url['pass'])) ? ':' . $parse_url['pass'] : '') . '@' : '')
91 . ((isset($parse_url['host'])) ? $parse_url['host'] : '') . ((isset($parse_url['port'])) ? ':' . $parse_url['port'] : '') . ((isset($parse_url['path'])) ? $parse_url['path'] : '')
92 . ((isset($parse_url['query'])) ? '?' . $parse_url['query'] : '') . ((isset($parse_url['fragment'])) ? '#' . $parse_url['fragment'] : '');
93 }
94}
diff --git a/inc/3rdparty/libraries/readability/Readability.php b/inc/3rdparty/libraries/readability/Readability.php
index 4fa3ba63..a30012ce 100755
--- a/inc/3rdparty/libraries/readability/Readability.php
+++ b/inc/3rdparty/libraries/readability/Readability.php
@@ -46,6 +46,7 @@
46 46
47// This class allows us to do JavaScript like assignements to innerHTML 47// This class allows us to do JavaScript like assignements to innerHTML
48require_once(dirname(__FILE__).'/JSLikeHTMLElement.php'); 48require_once(dirname(__FILE__).'/JSLikeHTMLElement.php');
49libxml_use_internal_errors(true);
49 50
50// Alternative usage (for testing only!) 51// Alternative usage (for testing only!)
51// uncomment the lines below and call Readability.php in your browser 52// uncomment the lines below and call Readability.php in your browser
@@ -697,7 +698,7 @@ class Readability
697 $articleContent = $this->dom->createElement('div'); 698 $articleContent = $this->dom->createElement('div');
698 $articleContent->setAttribute('id', 'readability-content'); 699 $articleContent->setAttribute('id', 'readability-content');
699 $siblingScoreThreshold = max(10, ((int)$topCandidate->getAttribute('readability')) * 0.2); 700 $siblingScoreThreshold = max(10, ((int)$topCandidate->getAttribute('readability')) * 0.2);
700 $siblingNodes = $topCandidate->parentNode->childNodes; 701 $siblingNodes = @$topCandidate->parentNode->childNodes;
701 if (!isset($siblingNodes)) { 702 if (!isset($siblingNodes)) {
702 $siblingNodes = new stdClass; 703 $siblingNodes = new stdClass;
703 $siblingNodes->length = 0; 704 $siblingNodes->length = 0;
@@ -1148,4 +1149,4 @@ class Readability
1148 } 1149 }
1149 1150
1150} 1151}
1151?> \ No newline at end of file 1152?>
diff --git a/inc/3rdparty/libraries/tcpdf/CHANGELOG.TXT b/inc/3rdparty/libraries/tcpdf/CHANGELOG.TXT
new file mode 100644
index 00000000..a7dde3f0
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/CHANGELOG.TXT
@@ -0,0 +1,2860 @@
16.0.093 (2014-09-02)
2 - Security fix: some serialize/unserialize methods were replaced with json_encode/json_decode to avoid a potential object injection with user supplied content. Thanks to ownCloud Inc. for reporting this issue.
3 - K_TIMEZONE constant was added to the default configuration to supress date-time warnings.
4
56.0.092 (2014-09-01)
6 - Bug item #956 "Monospaced fonts are not alignd at the baseline" was fixed.
7 - Bug item #964 "Problem when changing font size" was fixed.
8 - Bug item #969 "ImageSVG with radialGradient problem" was fixed.
9 - sRGB.icc file was replaced with the one from the Debian package icc-profiles-free (2.0.1+dfsg-1)
10
116.0.091 (2014-08-13)
12 - Issue #325"Division by zero when css fontsize equals 0" was fixed.
13
146.0.090 (2014-08-08)
15 - Starting from this version TCPDF is also available in GitHub at https://github.com/tecnickcom/TCPDF
16 - Function getmypid() was removed for better compatibility with shared hosting environments.
17 - Support for pulling SVG stroke opacity value from RGBa color was mergeg [adf006].
18 - Bug item #951 "HTML Table within TCPDF columns doesnt flow correctly on page break ..." was fixed.
19
206.0.089 (2014-07-16)
21 - Bug item #948 "bottom line of rowspan cell not work correctly" was fixed.
22
236.0.088 (2014-07-09)
24 - Bug item #946 "Case sensitive type check causes broken match for SVG" was fixed.
25 - Bug item #945 "Imagick load doesn't account for passed data string " was fixed.
26
276.0.087 (2014-06-25)
28 - A bug affecting fitcell option in Multicell was fixed.
29
306.0.086 (2014-06-20)
31 - Bug item #938 "Hyphenation-dash extends outside of cell" was fixed (collateral effect).
32
336.0.085 (2014-06-19)
34 - Some example images were replaced.
35 - A race condition bug was fixed.
36 - Bug item #938 "Hyphenation-dash extends outside of cell" was fixed.
37
386.0.084 (2014-06-13)
39 - A bug related to MultiCell fitcell feature was fixed.
40 - Bug item #931 "Documentation error for setPageFormat()" was fixed.
41
426.0.083 (2014-05-29)
43 - Bug item #928 "setHtmlVSpace with HR element" was fixed.
44
456.0.082 (2014-05-23)
46 - Bug item #926 "test statement instead of assignment used in tcpdf_fonts.php" was fixed.
47 - Bug item #925 "924 transparent images bug" was fixed.
48
496.0.081 (2014-05-22)
50 - Bug item #922 "writehtml tables thead repeating" was fixed.
51 - Patch #71 "External and internal links, local and remote" wa applied.
52
536.0.080 (2014-05-20)
54 - Bug item #921 "Fatal error in hyphenateText() function" was fixed.
55 - Bug item #923 "Automatic Hyphenation error" was fixed.
56 - Patch #70 "Augument TCPDFBarcode classes with ability to return raw png image data" was applied.
57
586.0.079 (2014-05-19)
59 - Patch item #69 "Named destinations, HTML internal and external links" was merged.
60 - Bug item #920 "hyphenateText() should not hyphenate the content of style-tags in HTML mode" was fixed.
61 - Image method now trigs an error in case the cache is now writeable.
62 - Fixed issue with layer default status.
63
646.0.078 (2014-05-12)
65 - A warning issue in addTTFfont() method was fixed.
66 - Fonts were updated to include cbbox metrics.
67
686.0.077 (2014-05-06)
69 - A Datamatrix barcode bug was fixed.
70
716.0.076 (2014-05-06)
72 - A bug in Datamatrix Base256 encoding was fixed.
73 - Merged fix for SVG use/clip-gradient.
74 - Now it is possible to prefix a page number in Link methods with the * character to avoid been changed when adding/deleting/moving pages (see example_045.php).
75
766.0.075 (2014-05-05)
77 - Bug #917 "Using realtive Units like ex or em for images distort output in HTML mode" was fixed.
78
796.0.074 (2014-05-03)
80 - Part of Bug #917 "Using realtive Units like ex or em for images distort output in HTML mode" was fixed.
81 - Bug #915 "Problem with SVG Image using Radial Gradients" was fixed.
82
836.0.073 (2014-04-29)
84 - Bug #913 "Possible bug with line-height" was fixed.
85 - Bug #914 "MultiCell and FitCell" was fixed.
86 - Bug #915 "Problem with SVG Image using Radial Gradients" was fixed.
87
886.0.072 (2014-04-27)
89 - Deprecated curly braces substring syntax was replaced with square braces.
90
916.0.071 (2014-04-25)
92 - Bug #911 "error with buffered png pics" was fixed.
93
946.0.070 (2014-04-24)
95 - Bug #910 "An SVG image is being cut off (with clipping mask) when you use align options" was fixed.
96
976.0.069 (2014-04-24)
98 - Datamatrix Base256 encoding was fixed.
99
1006.0.068 (2014-04-22)
101 - Some Datamatrix barcode bugs were fixed.
102
1036.0.067 (2014-04-21)
104 - startLayer() method signature was changed to include a new "lock" parameter.
105
1066.0.066 (2014-04-20)
107 - Bug #908 "Linebreak is not considered when getting length of the next string" was fixed.
108
1096.0.065 (2014-04-10)
110 - Bug #905 "RGB percentage color bug in convertHTMLColorToDec()" was fixed.
111
1126.0.064 (2014-04-07)
113 - Header and Footer fonts are now set by default.
114 - Bug #904 "PDF corrupted" was fixed.
115
1166.0.063 (2014-04-03)
117 - Method TCPDF_IMAGES::_parsepng() was fixed to support transparency in Indexed images.
118
1196.0.062 (2014-03-02)
120 - The method startLayer() now accepts the NULL value for the $print parameter to not set the print layer option.
121
1226.0.061 (2014-02-18)
123 - Bug #893 "Parsing error on streamed xref for secured pdf" was fixed.
124
1256.0.060 (2014-02-16)
126 - Bug #891 "Error on parsing hexa fields" was fixed.
127 - Bug #892 "Parsing pdf with trailing space at start" was fixed.
128
1296.0.059 (2014-02-03)
130 - SVG 'use' support was imporved.
131
1326.0.058 (2014-01-31)
133 - Bug #886 "Bugs with SVG using <defs> and <use>" was fixed.
134
1356.0.057 (2014-01-26)
136 - Bug #883 "Parsing error" was fixed.
137
1386.0.056 (2014-01-25)
139 - The automatic cache folder selection now works also with some restricted hosting environments.
140 - CSS text-transform property is now supported (requires the multibyte string library for php) - see examle n. 061 (Thanks to Walter Ferraz).
141 - Bug #884 "Parsing error prev tag looking for" was fixed.
142
1436.0.055 (2014-01-15)
144 - Bug #880 "Error detecting hX tags (h1,h2..)" was fixed
145 - Bug #879 "Thead on the second page inherits style of previous tr" was fixed
146
1476.0.054 (2014-01-13)
148 - Bug #877 "Parenteses causing corrupt text" was fixed.
149
1506.0.053 (2014-01-03)
151 - Bug #876 "Cell padding should not be multiplied with number of lines in getStringHeight" was fixed.
152 - Patch #68 "Empty img src attribute leads to access of uninitialized string offset" was applied.
153
1546.0.052 (2013-12-12)
155 - Bug #871 "Datamatrix coding" was fixed.
156
1576.0.051 (2013-12-02)
158 - cbbox array values in addTTFfont() were converted to integers.
159
1606.0.050 (2013-12-01)
161 - The method getNumLines() was extended to support hyphenation.
162 - The CSS property line-height now supports non percentage values.
163
1646.0.050 (2013-11-27)
165 - A bug related to PNG images was fixed.
166
1676.0.048 (2013-11-24)
168 - SVG vars are now reset in ImageSVG() method.
169
1706.0.047 (2013-11-19)
171 - SVG support was extended to support some nested defs.
172
1736.0.046 (2013-11-17)
174 - preg_replace_callback functions were replaced to improve memory performances.
175
1766.0.045 (2013-11-17)
177 - Bug #862 "Parsing error on flate filter" was fixed.
178
1796.0.044 (2013-11-10)
180 - Bug #857 "Undefined offset error" was fixed.
181 - The uniord method now uses a static cache to improve performances (thanks to Mathieu Masseboeuf for the sugegstion).
182 - Two bugs in the TCPDF_FONTS class were fixed.
183
1846.0.043 (2013-10-29)
185 - Bug #854 "CSS instruction display" was fixed.
186
1876.0.042 (2013-10-25)
188 - Bug #852 "CMYK Colors Bug" was fixed.
189
1906.0.041 (2013-10-21)
191 - Bug #851 "Problem with images in PDF. PHP timing out" was fixed.
192
1936.0.040 (2013-10-20)
194 - Bug #849 "SVG import bug" was fixed.
195
1966.0.039 (2013-10-13)
197 - Bug #843 "Wrong call in parser" was fixed.
198 - Bug #844 "Wrong object type named" was fixed.
199 - Bug #845 "Parsing error on obj ref prefixed by '000000'" was fixed.
200
2016.0.038 (2013-10-06)
202 - Bug #841 "Division by zero warning at writeHTML a <li> tag" was fixed.
203
2046.0.037 (2013-09-30)
205 - Method getAllSpotColors() was added to return all spot colors.
206 - Method colorRegistrationBar() was extended to automatically print all spot colors and support individual spot colors.
207 - The method registrationMarkCMYK() was added to print a registration mark for CMYK colors.
208 - A bug related to page groups was fixed.
209 - Gradient() method now supports CMYK equivalents of spot colors.
210 - Example n. 56 was updated.
211
2126.0.036 (2013-09-29)
213 - Methods for registration bars and crop marks were extended to support registration color (see example n. 56).
214 - New default spot colors were added to tcpdf_colors.php, including the 'All' and 'None' special registration colors.
215
2166.0.035 (2013-09-25)
217 - TCPDF_PARSER class was improved.
218
2196.0.034 (2013-09-24)
220 - Bug #839 "Error in xref parsing in mixed newline chars" was fixed.
221
2226.0.033 (2013-09-23)
223 - Bug fix related to PNG image transparency using GD library.
224
2256.0.032 (2013-09-23)
226 - Bug #838 "Fatal error when imagick cannot handle the image, even though GD is available and can" was fixed.
227
2286.0.031 (2013-09-18)
229 - Bug #836 "Optional EOL marker before endstream" was fixed.
230 - Some additional controls were added to avoid "division by zero" error with badly formatted input.
231
2326.0.030 (2013-09-17)
233 - Bug #835 "PDF417 and Cyrilic simbols" was fixed.
234
2356.0.029 (2013-09-15)
236 - Constants K_TCPDF_PARSER_THROW_EXCEPTION_ERROR and K_TCPDF_PARSER_IGNORE_DECODING_ERRORS where removed in favor of a new configuration array in the TCPDF_PARSER class.
237 - The TCPDF_PARSER class can now be configured using the new $cfg parameter.
238
2396.0.028 (2013-09-15)
240 - A debug print_r was removed form tcpdf_parser.php.
241 - TCPDF_FILTERS class now throws an exception in case of error.
242 - TCPDF_PARSER class now throws an exception in case of error unless you define the constant K_TCPDF_PARSER_THROW_EXCEPTION_ERROR to false.
243 - The constant K_TCPDF_PARSER_IGNORE_DECODING_ERRORS can be set to tru eto ignore decoding errors on TCPDF_PARSER.
244
2456.0.027 (2013-09-14)
246 - A bug in tcpdf_parser wen parsing hexadecimal strings was fixed.
247 - A bug in tcpdf_parser wen looking for statxref was fixed.
248 - A bug on RC4 encryption was fixed.
249
2506.0.026 (2013-09-14)
251 - A bug in tcpdf_parser wen decoding streams was fixed.
252
2536.0.025 (2013-09-04)
254 - A pregSplit() bug was fixed.
255 - Improved content loading from URLs.
256 - Improved font path loading.
257
2586.0.024 (2013-09-02)
259 - Bug #826 "addEmptySignatureAppearance issue" was fixed.
260
2616.0.023 (2013-08-05)
262 - GNU Freefont fonts were updated.
263 - Licensing and copyright information about fonts were improved.
264 - PNG image support was improved.
265
2666.0.022 (2013-08-02)
267 - fixing initialization problem for signature_appearance property.
268
2696.0.021 (2013-07-18)
270 - The bug caused by the preg_split function on some PHP 5.2.x versions was fixed.
271
2726.0.020 (2013-06-04)
273 - The method addTTFfont() was fixed (Bug item #813 Undefined offset).
274
2756.0.019 (2013-06-04)
276 - The magic constant __DIR__ was replaced with dirname(__FILE__) for php 5.2 compatibility.
277 - The exceptions raised by file_exists() function were suppressed.
278
2796.0.018 (2013-05-19)
280 - The barcode examples were changed to automatically search for the barcode class path (in case the examples directory is not installed under the TCPDF root).
281
2826.0.017 (2013-05-16)
283 - The command line tool tcpdf_addfont.php was improved.
284 - The php logic was removed from configuration files that now contains only constant defines.
285 - The tcpdf_autoconfig.php file was added to automatically set missing configuration values.
286
2876.0.016 (2013-05-15)
288 - The tcpdf_addfont.php tool was improved (thanks to Remi Collet).
289 - Constant K_PATH_IMAGES is now automatically set in configuration file.
290
2916.0.015 (2013-05-14)
292 - Some unused vars were removed from AddFont() method.
293 - Some directories were moved inside the examples directory.
294 - All examples were updated to reflect the new default structure.
295 - Source code were clean-up up to be more compatible with system packaging.
296 - Files encodings and permissions were reset.
297 - The command line tool tcpdf_addfont.php was added on the tools directory.
298
2996.0.014 (2013-04-13)
300 - The signature of addTTFfont() method includes a new parameter to link existing fonts instead of copying and compressing them.
301
3026.0.013 (2013-04-10)
303 - Add support for SVG dx and dy text/tspan attributes.
304 - replace require() with require_once().
305 - fix some minor typos on documentation.
306 - fix a problem when deleting all pages.
307
3086.0.012 (2013-04-24)
309 - An error condition in addHtmlLink() method was fixed (bug #799).
310
3116.0.011 (2013-04-22)
312 - Minor documentation changes.
313
3146.0.010 (2013-04-03)
315 - The method Rect() was fixed to print borders correctly.
316
3176.0.009 (2013-04-02)
318 - Adding back some files that were not properly committed on the latest release.
319
3206.0.008 (2013-04-01)
321 - Duplicated encoding maps was removed from tcpdf_font_data.php.
322 - Fixing bug on AddTTFFont().
323
3246.0.007 (2013-03-29)
325 - HTML/CSS font size conversion were improved.
326
3276.0.006 (2013-03-27)
328 - Bug related to SVG and EPS files on xobjects were fixed.
329
3306.0.005 (2013-03-26)
331 - Default font path was fixed.
332
3336.0.004 (2013-03-21)
334 - Return value of addTTFfont() method was fixed.
335
3366.0.003 (2013-03-20)
337 - A bug related to non-unicode mode was fixed.
338
3396.0.002 (2013-03-18)
340 - _getFIXED call on tcpdf_fonts.php was fixed.
341
3426.0.001 (2013-03-18)
343 - Fixed $uni_type call on tcpdf.php.
344
3456.0.000 (2013-03-17)
346 - IMPORTANT: PHP4 support has been removed starting from this version.
347 - Several TCPDF methods and vars were moved to new class files: tcpdf_static.php, tcpdf_colors.php, tcpdf_images.php, tcpdf_font_data.php, tcpdf_fonts.php.
348 - Files htmlcolors.php, spotcolors.php, unicode_data.php and ecodings_maps.php were removed.
349 - Barcode classes were renamed and new barcode examples were added.
350 - Class TCPDF_PARSER was improved.
351
352********************************************************************************
353
3545.9.209 (2013-03-15)
355 - Image method was improved.
356
3575.9.208 (2013-03-15)
358 - objclone fuction was patched to support old imagick extensions.
359 - tcpdf_parser was improved to support Cross-Reference Streams and large streams.
360
3615.9.207 (2013-03-04)
362 - Datamatrix class was fixed (a debug echo was removed).
363
3645.9.206 (2013-02-22)
365 - Bug item #754 "PNG with alpha channel becomes gray scale" was fixed.
366 - Minor documentation fixes.
367
3685.9.205 (2013-02-06)
369 - The constant K_TCPDF_THROW_EXCEPTION_ERROR was added on configuration file to change the behavior of Error() method.
370 - PDF417 barcode bug was fixed.
371
3725.9.204 (2013-01-23)
373 - The method Bookmark() was extended to include named destinations, URLs, internal links or embedded files (see example n. 15).
374 - automatic path calculation on configuration file was fixed.
375 - Error() method was extended to throw new Exception if PHP > 5.
376
3775.9.203 (2013-01-22)
378 - Horizontal position of radiobuttons and checkboxes was adjusted.
379
3805.9.202 (2012-12-16)
381 - Vertical space problem after table was fixed.
382
3835.9.201 (2012-12-10)
384 - First 256 chars are now always included on font subset to overcome a problem reported on the forum.
385
3865.9.200 (2012-12-05)
387 - Bug item #768 "Rowspan with Pagebreak error" was fixed.
388 - Page regions now works also with limited MultiCell() cells.
389
3905.9.199 (2012-11-29)
391 - Internal setImageBuffer() method was improved.
392
3935.9.198 (2012-11-19)
394 - Datamatrix EDIFACT mode was fixed.
395
3965.9.197 (2012-11-06)
397 - Bug item #756 "TCPDF 5.9.196 shows line on top of all PDFs" was fixed.
398
3995.9.196 (2012-11-02)
400 - Several methods were improved to avoid output when the context is out of page.
401 - Bug item #755 "remove cached files before unsetting" was fixed.
402
4035.9.195 (2012-10-24)
404 - Method _putfonts() was improved.
405
4065.9.194 (2012-10-23)
407 - Text alignment on TextField() method was fixed.
408
4095.9.193 (2012-09-25)
410 - Support for named destinations on HTML links was added (i.e.: <a href="#destinationname">link to named destination</a>).
411
4125.9.192 (2012-09-24)
413 - A problem on the releasing process was fixed.
414
4155.9.191 (2012-09-24)
416 - SVG image naow support svg and eps images.
417
4185.9.190 (2012-09-23)
419 - "page" word translation is now set to empty if not defined.
420 - Tooltip feature was added on the radiobutton annotation.
421
4225.9.189 (2012-09-18)
423 - Bug item #3568969 "ini_get safe_mode error" was fixed.
424
4255.9.188 (2012-09-15)
426 - A datamatrix barcode bug was fixed.
427
4285.9.187 (2012-09-14)
429 - Subset feature was extended to include the first 256 characters.
430
4315.9.186 (2012-09-13)
432 - barcodes.php file was resynced.
433 - Methods SetAbsX, SetAbsY, SetAbsXY where added to set the absolute pointer coordinates.
434 - Method getCharBBox were added to get single character bounding box.
435 - Signature of addTTFfont method was changed ($addcbbox paramter was added).
436
4375.9.185 (2012-09-12)
438 - Method _putfontwidths() was fixed.
439
4405.9.184 (2012-09-11)
441 - A problem with EAN barcodes was fixed.
442
4435.9.183 (2012-09-07)
444 - A problem with font names normalization was fixed.
445
4465.9.182 (2012-09-05)
447 - Bug item #3564982 "Infinite loop in Write() method" was fixed.
448
4495.9.181 (2012-08-31)
450 - composer.json file was added.
451 - Bug item #3563369 "Cached images are not unlinked some time" was fixed.
452
4535.9.180 (2012-08-22)
454 - Bug item #3560493 "Problems with nested cells in HTML" was fixed.
455
4565.9.179 (2012-08-04)
457 - SVG 'use' tag was fixed for 'circle' and 'ellipse' shift problem.
458 - Alpha status is now correctly stored and restored by getGraphicVars() and SetGraphicVars() methods.
459
4605.9.178 (2012-08-02)
461 - SVG 'use' tag was fixed for 'circle' and 'ellipse'.
462
4635.9.177 (2012-08-02)
464 - An additional control on annotations was fixed.
465
4665.9.176 (2012-07-25)
467 - A bug related to stroke width was fixed.
468 - A problem related to font spacing in HTML was fixed.
469
4705.9.175 (2012-07-25)
471 - The problem of missing letter on hyphen break was fixed.
472
4735.9.174 (2012-07-25)
474 - The problem of wrong filename when downloading PDF from an Android device was fixed.
475 - The method setHeaderData() was extended to set text and line color for header (see example n. 1).
476 - The method setFooterData() was added to set text and line color for footer (see example n. 1).
477 - The methods setTextShadow() and getTextShadow() were added to set text shadows (see example n. 1).
478 - The GetCharWidth() method was fixed for negative character spacing.
479 - A 'none' border mode is now correctly recognized.
480 - Break on hyphen problem was fixed.
481
4825.9.173 (2012-07-23)
483 - Some additional control wher added on barcode methods.
484 - The option CURLOPT_FOLLOWLOCATION on Image method is now disabled if PHP safe_mode is on or open_basedir is set.
485 - Method Bookmark() was extended to include X parameter.
486 - Method setDestination() was extended to include X parameter.
487 - A problem with Thai language was fixed.
488
4895.9.172 (2012-07-02)
490 - A PNG color profile issue was fixed.
491
4925.9.171 (2012-07-01)
493 - Some SVG rendering problems were fixed.
494
4955.9.170 (2012-06-27)
496 - Bug #3538227 "Numerous errors inserting shared images" was fixed.
497
4985.9.169 (2012-06-25)
499 - Some SVG rendering problems were fixed.
500
5015.9.168 (2012-06-22)
502 - Thai language rendering was fixed.
503
5045.9.167 (2012-06-22)
505 - Thai language rendering was fixed and improved.
506 - Method isCharDefined() was improved.
507 - Protected method replaceChar() was added.
508 - Font "kerning" word was corrected to "tracking".
509
5105.9.166 (2012-06-21)
511 - Array to string conversion on file_id creation was fixed.
512 - Thai language rendering was fixed (thanks to Atsawin Chaowanakritsanakul).
513
5145.9.165 (2012-06-07)
515 - Some HTML form related bugs were fixed.
516
5175.9.164 (2012-06-06)
518 - A bug introduced on the latest release was fixed.
519
5205.9.163 (2012-06-05)
521 - Method getGDgamma() was changed.
522 - Rendering performances of PNG images with alpha channel were improved.
523
5245.9.162 (2012-05-11)
525 - A bug related to long text on TD cells was fixed.
526
5275.9.161 (2012-05-09)
528 - A bug on XREF table was fixed (Bug ID: 3525051).
529 - Deprecated Imagick:clone was replaced.
530 - Method objclone() was fixed for PHP4.
531
5325.9.160 (2012-05-03)
533 - A bug on tcpdf_parser.php was fixed.
534
5355.9.159 (2012-04-30)
536 - Barcode classes were updated to fix PNG export Bug (ID: 3522291).
537
5385.9.158 (2012-04-22)
539 - Some SVG-related bugs were fixed.
540
5415.9.157 (2012-04-16)
542 - Some SVG-related bugs were fixed.
543
5445.9.156 (2012-04-10)
545 - Bug item #3515885 "TOC and booklet: left and right page exchanged".
546 - SetAutoPageBreak(false) now works also in multicolumn mode.
547
5485.9.155 (2012-04-02)
549 - Bug item #3512596 "font import problems" was fixed.
550 - Method addTTFfont() was modified to extract only specified Platform ID and Encoding ID (check the source code documentation).
551 - All fonts were updated.
552 - Bug item #3513867 "booklet and setHeaderTemplateAutoreset: header shifted left" was fixed.
553 - Bug item #3513749 "TCPDF Superscript/Subscript" was fixed.
554
5555.9.154 (2012-03-29)
556 - A debug echo was removed.
557
5585.9.153 (2012-03-28)
559 - A bug on font conversion was fixed.
560 - All fonts were updated.
561 - Method isCharDefined() was added to find if a character is defined on the selected font.
562 - Method replaceMissingChars() was added to automatically replace missing chars on selected font.
563 - SetFont() method was fixed.
564
5655.9.152 (2012-03-23)
566 - The following overprint methods were added: setOverprint(), getOverprint().
567 - Signature of setAlpha() method was changed and method getAlpha() was added.
568 - stroke-opacity support was added on SVG.
569 - The following date methods were added: setDocCreationTimestamp(), setDocModificationTimestamp(), getDocCreationTimestamp(), getDocModificationTimestamp(), getFormattedDate(), getTimestamp().
570 - Signature of _datestring() method was changed.
571 - Method getFontBBox() was added.
572 - Method setPageBoxTypes() was aded.
573
5745.9.151 (2012-03-22)
575 - Bug item #3509889 "Transform() distorts PDF" was fixed.
576 - Precision of real number were extended.
577 - ComboBox and ListBox methods were fixed.
578 - Bulgarian language file was added.
579 - addTOC() method was improved to include bookmark color and font style.
580
5815.9.150 (2012-03-16)
582 - A bug related to form fields in PDF/A mode was fixed.
583
5845.9.149 (2012-02-21)
585 - Bug item #3489933 "SVG Parser treats tspan like text" was fixed.
586
5875.9.148 (2012-02-17)
588 - Bug item #3488600 "Multiple radiobutton sets get first set value" was fixed.
589
5905.9.147 (2012-02-14)
591 - A problem with SVG gradients has been fixed.
592
5935.9.146 (2012-02-12)
594 - Bug item #3486880 "$filehash undefine error" was fixed.
595 - The default font is now the one specified at PDF_FONT_NAME_MAIN constant.
596
5975.9.145 (2012-01-28)
598 - Japanese language file was added.
599 - TCPDF license and README.TXT files were updated.
600
6015.9.144 (2012-01-12)
602 - HTML output on barcode classes was improved.
603
6045.9.143 (2012-01-08)
605 - Bug item #3471057 "setCreator() has no effect" was fixed.
606
6075.9.142 (2011-12-23)
608 - Source code documentation was updated.
609
6105.9.141 (2011-12-14)
611 - Some minor bugs were fixed.
612
6135.9.140 (2011-12-13)
614 - SVG now supports embedded images encoded as base64.
615
6165.9.139 (2011-12-11)
617 - Spot color methods were fixed.
618
6195.9.138 (2011-12-10)
620 - cropMark() method was improved (check source code documentation).
621 - Example n. 56 was updated.
622 - Bug item #3452390 "Check Box still not ticked when set to true" was fixed.
623
6245.9.137 (2011-12-01)
625 - Bug item #3447005 "Background color and border of Form Elements is printed" was fixed.
626 - Color support for Form elements was improved.
627
6285.9.136 (2011-11-27)
629 - Bug item #3443387 "SetMargins with keep option does not work for top margin" was fixed.
630
6315.9.135 (2011-11-04)
632 - Bug item #3433406 "Double keywords in description" was fixed.
633
6345.9.134 (2011-10-29)
635 - The default value for $defcol parameter on convertHTMLColorToDec() method was fixed.
636 - Deafult HTTP headers were changed to avoid browser caching.
637 - Some deprecated syntax were replaced.
638
6395.9.133 (2011-10-26)
640 - Bug item #3428446 "copyPage method not working when diskcache enabled" was fixed.
641
6425.9.132 (2011-10-20)
643 - Bug item #3426167 "bug in function convertHTMLColorToDec()" was fixed.
644
6455.9.131 (2011-10-13)
646 - An error message was added to ImagePngAlpha() method.
647
6485.9.130 (2011-10-12)
649 - Now you can set image data strings on HTML img tag by encoding the image binary data in this way: $imgsrc = '@'.base64_encode($imgdata);
650
6515.9.129 (2011-10-07)
652 - Core fonts metrics was fixed (replace all helvetica and times php files on fonts folder).
653 - Form fields support was improved and some problems were fixed (check the example n. 14).
654 - Bug item #3420249 "Issue with booklet and MultiCell" was fixed.
655
6565.9.128 (2011-10-06)
657 - Method addTTFfont() was improved (check the source code documentation).
658 - Method setExtraXMP() to set custom XMP data was added.
659
6605.9.127 (2011-10-04)
661 - Readonly mode option was activated for radiobuttons.
662
6635.9.126 (2011-10-03)
664 - Bug item #3417989 "Graphics State operator in form XObject fails to render" was fixed.
665 - Xobjects problems with transparency, gradients and spot colors were fixed.
666
6675.9.125 (2011-10-03)
668 - Support for 8-digit CMYK hexadecimal color representation was added (to be used with XHTML and SVG).
669 - Spot colors support was improved (check example n. 37).
670 - Color methods were improved.
671
6725.9.124 (2011-10-02)
673 - Core fonts were updated.
674
6755.9.123 (2011-10-02)
676 - The method addTTFfont() wad added to automatically convert TTF fonts (check the new fonts guide at http://www.tcpdf.org).
677 - Old font utils were removed.
678 - All fonts were updated and new arabic fonts were added (almohanad were removed and replaced by aefurat and aealarabiya).
679 - The file unicode_data.php was updated.
680 - The file encodings_maps.php was added.
681 - PDF/A files are now compressed to save space.
682 - XHTML input form fields now support text-alignment attribute.
683
6845.9.122 (2011-09-29)
685 - PDF/A-1b compliance was improved to pass some online testing.
686
6875.9.121 (2011-09-28)
688 - This version includes support for PDF/A-1b format (the class constructor signature was changed - see example n. 65).
689 - Method setSRGBmode() was added to force sRGB_IEC61966-2.1 black scaled ICC color profile for the whole document (file sRGB.icc was added).
690 - 14 new fonts were added to allow embedding core fonts (for PDF/A compliance).
691 - Font utils were fixed.
692
6935.9.120 (2011-09-22)
694 - This version includes a fix for _getTrueTypeFontSubset() method.
695
6965.9.119 (2011-09-19)
697 - This version includes a fix for extra page numbering on TOC.
698
6995.9.118 (2011-09-17)
700 - This version includes some changes that allows you to add a bookmark for a page that do not exist.
701
7025.9.117 (2011-09-15)
703 - TCPDFBarcode and TCPDF2DBarcode classes were extended to include a method for exporting barcodes as PNG images.
704
7055.9.116 (2011-09-14)
706 - Datamatrix class was improved and documentation was fixed.
707
7085.9.115 (2011-09-13)
709 - Datamatrix ECC200 barcode support was added (a new datamatrix.php file was added) - check example n. 50.
710 - getBarcodeHTML() method was added on TCPDFBarcode and TCPDF2DBarcode classes to return an HTML representation of the barcode.
711 - cURL options on Image() method were improved.
712 - A bug on write2DBarcode() was fixed.
713
7145.9.114 (2011-09-04)
715 - A bug related to column position was fixed.
716
7175.9.113 (2011-08-24)
718 - This release include two new experimental files for parsing an existing PDF document (the integration with TCPDF is under development).
719
7205.9.112 (2011-08-18)
721 - A newline character was added after the 'trailer' keyword for compatibility with some parsers.
722 - Support for layers was improved.
723
7245.9.111 (2011-08-17)
725 - Barcode CODE 39 default gap was restored at 1.
726
7275.9.110 (2011-08-17)
728 - Barcode CODE 39 was fixed.
729
7305.9.109 (2011-08-12)
731 - Method getNumLines() was fixed.
732 - A bug related to page break in multi-column mode was fixed.
733
7345.9.108 (2011-08-09)
735 - A bug on PHP4 version was fixed.
736
7375.9.107 (2011-08-08)
738 - This version includes a minor bugfix.
739
7405.9.106 (2011-08-04)
741 - This version includes transparency groups: check the new parameter on startTemplate() method and example 62.
742
7435.9.105 (2011-08-04)
744 - Bug item #3386153 "Check Box not ticked when set to true" was fixed.
745
7465.9.104 (2011-08-01)
747 - Bug item #3383698 "imagemagick, resize and dpi" was fixed.
748
7495.9.103 (2011-07-16)
750 - Alignment of XHTML lines was improved.
751 - Spell of the "length" word was fixed.
752
7535.9.102 (2011-07-13)
754 - Methods startLayer() and endLayer() were added to support arbitrary PDF layers.
755 - Some improvements/fixes for images were added (thanks to Brendan Abbott).
756
7575.9.101 (2011-07-07)
758 - Support for JPEG and PNG ICC Color Profiles was added.
759 - Method addEmptySignatureAppearance() was added to add empty signature fields (see example n. 52).
760 - Bug item #3354332 "Strange line spacing with reduced font-size in writeHTML" was fixed.
761
7625.9.100 (2011-06-29)
763 - An SVG bug has been fixed.
764
7655.9.099 (2011-06-27)
766 - Bug item #3335045 "Font freesans seems somehow corrupted in footer" was fixed.
767
7685.9.098 (2011-06-23)
769 - The Named Destination feature was fixed.
770
7715.9.097 (2011-06-23)
772 - The method setHtmlVSpace() now can be used also for tags: div, li, br, dt and dd.
773 - The Named Destination feature was added (check the example n. 15) - thanks to Christian Deligant.
774
7755.9.096 (2011-06-19)
776 - Bug item #3322234 "Surrogate pairs codes in arrUTF8ToUTF16BE" was fixed.
777
7785.9.095 (2011-06-18)
779 - Numbers alignment for Table-Of-Content methods was improved and fixed.
780 - Font subsetting was fixed to include all parts of composite fonts.
781
7825.9.094 (2011-06-17)
783 - Bug item #3317898 "Page Group numbering broken in 5.9.093" was fixed.
784
7855.9.093 (2011-06-16)
786 - Method setStartingPageNumber() was added to set starting page number (for automatic page numbering).
787
7885.9.092 (2011-06-15)
789 - Method _putpages() was improved.
790 - Bug item #3316678 "Memory overflow when use Rotate and SetAutoPageBreak" was fixed.
791 - Right alignment of page numbers was improved.
792
7935.9.090 (2011-06-14)
794 - Methods AliasNbPages() and AliasNumPage() were re-added as deprecated for backward compatibility.
795
7965.9.089 (2011-06-13)
797 - Example n. 8 was updated.
798 - Method sendOutputData() was changed to remove default compression (it was incompatible with some server settings).
799 - Bugs related to page group numbers were fixed.
800 - Method copyPage() was fixed.
801 - Method Image() was improved to include support for alternative and external images.
802
8035.9.088 (2011-06-01)
804 - Method getAutoPageBreak() was added (see example n. 51).
805 - Example n. 51 (full page background) was updated.
806
8075.9.087 (2011-06-01)
808 - Method sendOutputData() was improved to include deflate encoding.
809 - Barcode classes on PHP 4 version were fixed.
810
8115.9.086 (2011-05-31)
812 - Font files were updated (the ones on the previous release were broken).
813 - The script fonts/utils/makeallttffonts.php was updated and fixed.
814 - Output() method was improved to use compression when available.
815
8165.9.085 (2011-05-31)
817 - TCPDFBarcode class (barcodes.php) now includes getBarcodeSVG() and getBarcodeSVGcode() methods to get SVG image representation of the barcode.
818 - TCPDF2DBarcode class (2dbarcodes.php) now includes getBarcodeSVG() and getBarcodeSVGcode() methods to get SVG image representation of the barcode.
819
8205.9.084 (2011-05-29)
821 - Font files were updated.
822 - The file fonts/utils/makeallttffonts.php was updated.
823 - Bug item# 3308774 "Problems with font subsetting" was fixed.
824
8255.9.083 (2011-05-24)
826 - Bug item #3308387 "line height & SetCellHeightRatio" was fixed.
827
8285.9.082 (2011-05-22)
829 - Bug item #3305592 "Setting fill color <> text color breaks text clipping" was fixed.
830
8315.9.081 (2011-05-18)
832 - Method resetHeaderTemplate() was added to reset the xobject template used by Header() method.
833 - Method setHeaderTemplateAutoreset() was added to automatically reset the xobject template used by Header() method at each page.
834
8355.9.080 (2011-05-17)
836 - A problem related to file path calculation for images was fixed.
837 - A problem related to unsupressed getimagesize() error was fixed.
838
8395.9.079 (2011-05-16)
840 - Footer() method was changed to use C128 barcode as default (instead of the previous C128B).
841
8425.9.078 (2011-05-12)
843 - Bug item #3300878 "wrong rendering for html bullet list in some case" was fixed.
844 - Bug item #3301017 "Emphasized vs. font-weight" was fixed.
845 - Barcode Code 128 was improved to include AUTO mode (automatically switch between A, B and C modes).
846 - Examples n. 27 and 49 were updated.
847
8485.9.077 (2011-05-07)
849 - Bug item #3298591 "error code93" was fixed.
850 - SetLineStyle() function was improved.
851
8525.9.076 (2011-05-06)
853 - Bug item #3298264 "codebar 93 error" was fixed.
854
8555.9.075 (2011-05-02)
856 - Table header alignment when using WriteHTMLCell() or MultiCell() was fixed.
857
8585.9.074 (2011-04-28)
859 - Bug item #3294306 "CSS classes not work in <thead> table section" was fixed.
860
8615.9.073 (2011-04-27)
862 - A bug related to character entities on HTML cells was fixed.
863
8645.9.072 (2011-04-26)
865 - Method resetColumns() was added to remove multiple columns and reset page margins (example n. 10 was updated).
866
8675.9.071 (2011-04-19)
868 - Bug #3288574 "<br/> trouble" was fixed.
869
8705.9.069 (2011-04-19)
871 - Bug #3288763 "HTML-Table: non-breaking table rows: Bug" was fixed.
872
8735.9.068 (2011-04-15)
874 - Bookmark, addTOC and addHTMLTOC methods were improved to include font style and color (Examples 15, 49 and 59 were updated).
875 - Default $_SERVER['DOCUMENT_ROOT'] value on tcpdf_config.php file was changed.
876
8775.9.067 (2011-04-10)
878 - Performances were drastically improved (PDF documents are now created more quickly).
879
8805.9.066 (2011-04-09)
881 - A bug related to digital signature + encryption was fixed.
882 - A bug related to encryption + xobject templates was fixed.
883
8845.9.065 (2011-04-08)
885 - Bug item #3280512 "Text encoding iso-8859-2 crashes" was fixed.
886
8875.9.064 (2011-04-05)
888 - A bug related to character entities on HTML cells was fixed.
889
8905.9.063 (2011-04-01)
891 - Bug item #3267235 "WriteHTML() and image that doesn't fit on the page" was fixed.
892
8935.9.062 (2011-03-23)
894 - Bug item #3232650 "Using Write if there are pageRegions active creates error" was fixed.
895 - Bug item #3221891 "text input borders" was fixed.
896 - Bug item #3228958 "Adobe Reader 9.4.2 crash" was fixed.
897
8985.9.061 (2011-03-15)
899 - Bug item #3213488 "wrong function call in function Write" was fixed.
900 - Bug item #3203007 "list element with black background" was fixed.
901
9025.9.060 (2011-03-08)
903 - addTOC() method was fixed for text alignment problems.
904
9055.9.059 (2011-02-27)
906 - Default Header() method was improved to reduce document size.
907
9085.9.058 (2011-02-25)
909 - Image() method was improved to cache images with transparency layers (thanks to Korneliusz Jarzębski for reporting this problem).
910
9115.9.057 (2011-02-24)
912 - A problem with image caching system was fixed (thanks to Korneliusz Jarzębski for reporting this problem).
913
9145.9.056 (2011-02-22)
915 - A bug on fixHTMLCode() method was fixed.
916 - Automatic line break for HTML was fixed.
917
9185.9.055 (2011-02-17)
919 - Another bug related to HTML table page break was fixed.
920
9215.9.054 (2011-02-16)
922 - A bug related to HTML table page break was fixed.
923
9245.9.053 (2011-02-16)
925 - Support for HTML attribute display="none" was added.
926
9275.9.052 (2011-02-15)
928 - A bug related to HTML automatic newlines was fixed.
929
9305.9.051 (2011-02-12)
931 - "Commas at beginning of new lines" problem was fixed.
932
9335.9.050 (2011-02-11)
934 - Bug #3177606 "SVG Bar chart error" was fixed.
935
9365.9.049 (2011-02-03)
937 - Bug #3170777 "TCPDF creates a new page after a single line in writeHTML" was fixed.
938
9395.9.048 (2011-02-02)
940 - No changes. Just released to override previous release that was not uploaded correctly.
941
9425.9.047 (2011-01-28)
943 - Bug #3167115 "PDF error in <table> (example 48)" was fixed (was introduced in 5.8.046).
944
9455.9.046 (2011-01-18)
946 - PDF view/print layers are now automatically turned off if not used (see setVisibility() method).
947
9485.9.045 (2011-01-17)
949 - HTML list support were improved.
950
9515.9.044 (2011-01-15)
952 - Bug #3158422 "writeHTMLCell Loop" was fixed.
953 - Some HTML image alignment problems were fixed.
954
9555.9.043 (2011-01-14)
956 - Bug #3158178 "PHP Notice" was fixed.
957 - Bug #3158193 "Endless loop in writeHTML" was fixed.
958 - Bug #3157764 "SVG Pie chart incorrectly rendered2".
959
9605.9.042 (2011-01-14)
961 - Some problems of the PHP4 version were fixed.
962
9635.9.041 (2011-01-13)
964 - A problem with SVG elliptical arc path was fixed (ref. bug #3156574).
965 - A problem related to font weight on HTML table headers was fixed.
966
9675.9.040 (2011-01-12)
968 - A bug related to empty pages after table was fixed.
969
9705.9.039 (2011-01-12)
971 - Bug item #3155759 "openssl_random_pseudo_bytes() slow under Windows" was fixed.
972
9735.9.038 (2011-01-11)
974 - Minor bugs were fixed.
975
9765.9.037 (2011-01-09)
977 - An alignment problem for HTML texts was fixed.
978
9795.9.036 (2011-01-07)
980 - A bug related to HTML tables on header was fixed.
981
9825.9.035 (2011-01-03)
983 - A problem related to HTML table border alignment was fixed.
984 - Bug #2996366 "FastCGI and Header Problems" was fixed.
985
9865.9.034 (2010-12-19)
987 - DejaVu and GNU Free fonts were updated.
988
9895.9.033 (2010-12-18)
990 - Source code documetnation was improved.
991
9925.9.032 (2010-12-18)
993 - Default font stretching and spacing values are now inherited by HTML methods.
994
9955.9.031 (2010-12-16)
996 - Source code documentation errors were fixed.
997
9985.9.030 (2010-12-16)
999 - Several source code documentation errors were fixed.
1000 - Source code style was changed for Doxygen.
1001 - Source code documentation was moved online to http://www.tcpdf.org
1002
10035.9.029 (2010-12-04)
1004 - The $fitbox parameter on Image() method was extended to specify image alignment inside the box (check the example n. 9).
1005
10065.9.028 (2010-12-03)
1007 - Font utils makefont.php and makeallttffonts.php were updated.
1008
10095.9.027 (2010-12-01)
1010 - Spot Colors are now better integrated with HTML mode.
1011 - Method SetDocInfoUnicode() was added to turn on/off Unicode mode for document information dictionary (meta tags) - check the example n. 19.
1012
10135.9.026 (2010-12-01)
1014 - A problem with mixed text directions on HTML was fixed.
1015
10165.9.025 (2010-12-01)
1017 - The AddSpotColor() now automatically fills the spotcolor array (defined on spotcolors.php file).
1018
10195.9.024 (2010-11-30)
1020 - Bug item #3123612 "SVG not use gradientTransform in percentage mode" was fixed.
1021
10225.9.023 (2010-11-25)
1023 - A potential bug on SVG transcoder was fixed.
1024
10255.9.022 (2010-11-21)
1026 - Method ImageEPS includes support for EPS/AI Spot colors.
1027 - Method ImageEPS includes a new parameter $fixoutvals to remove values outside the bounding box.
1028
10295.9.021 (2010-11-20)
1030 - Support for custom bullet points images was added (check the example n.6)
1031 - Examples n. 6 and 61 were update (check the comments inside).
1032
10335.9.020 (2010-11-19)
1034 - A problem related to additional page when using multicolumn mode was fixed.
1035
10365.9.019 (2010-11-19)
1037 - An SVG bug was fixed.
1038 - ImageSVG() and ImageEPS() methods now accepts image data streams (put the string on the $file parameter preceded by '@' character).
1039 - Option 'E' was added to the $dest parameter of Output() method to return the document as base64 mime multi-part email attachment (RFC 2045).
1040
10415.9.018 (2010-11-19)
1042 - An SVG bug was fixed.
1043
10445.9.017 (2010-11-16)
1045 - Tagline color was set to transparent.
1046 - The method fixHTMLCode() was added to automatically clean up HTML code (requires HTML Tidy).
1047
10485.9.016 (2010-11-16)
1049 - Bug item #3109705 "list item page break hanging bullet" was fixed.
1050
10515.9.015 (2010-11-16)
1052 - Bug item affecting QRCode was fixed.
1053 - Some bugs affecting HTML lists were fixed.
1054 - ImageSVG() and fitBlock() methods were improved to handle some SVG problems.
1055 - Some problems with PHP4 compatibility were fixed.
1056
10575.9.014 (2010-11-15)
1058 - Bug item #3109464 "QRCode error" was fixed.
1059
10605.9.013 (2010-11-15)
1061 - Bug item #3109257 "Problem with interlaced GIFs and PNGs" was fixed.
1062 - Image function now accepts image data streams (check example n. 9).
1063
10645.9.012 (2010-11-12)
1065 - Method getTCPDFVersion() was added.
1066 - PDF_PRODUCER constant was removed.
1067 - Method convertHTMLColorToDec() was improved.
1068 - HTML colors now support spot color names defined on the new spotcolors.php file.
1069 - The default method Header() was improved to support SVG and EPS/AI images.
1070 - A bug on SVG importer was fixed.
1071
10725.9.011 (2010-11-02)
1073 - Bug item #3101486 "Bug Fix for image loading" was fixed.
1074
10755.9.010 (2010-10-27)
1076 - Support for CSS properties 'border-spacing' and 'padding' for tables were added.
1077 - Several language files were added.
1078
10795.9.009 (2010-10-21)
1080 - HTML text alignment was improved to include the case of RTL text on LTR direction and LTR text on RTL direction.
1081
10825.9.008 (2010-10-21)
1083 - Bug item #3091502 "Bookmark oddity" was fixed.
1084 - HTML internal links now accepts page number and Y position.
1085 - The method write1DBarcode() was improved to accept separate horizontal and vertical padding (see example n. 27).
1086
10875.9.007 (2010-10-20)
1088 - Method adjustCellPadding() was fixed to handle bad input.
1089
10905.9.006 (2010-10-19)
1091 - Support for AES 256 bit encryption was added (see example n. 16).
1092 - Method getNumLines() was fixed for the empty string case.
1093
10945.9.005 (2010-10-18)
1095 - Method addPageRegion() was changed to accept regions starting exactly from the top of the page.
1096
10975.9.004 (2010-10-18)
1098 - A bug related to annotations was fixed.
1099 - The file unicode_data.php was canged to encapsulate all data in a class.
1100 - The file htmlcolors.php was changed to remove the global variable.
1101
11025.9.003 (2010-10-15)
1103 - Support for no-write page regions was added. Check the example n. 64 and new methods setPageRegions(), addPageRegion(), getPageRegions(), removePageRegion().
1104 - A bug on Right-To-Left alignment was fixed.
1105
11065.9.002 (2010-10-08)
1107 - Cell method was improved to preserve the font stretching and spacing values when using the $stretch parameter (see example n. 4).
1108
11095.9.001 (2010-10-07)
1110 - The problem of blank page for nobr table higher than a single page was fixed.
1111
11125.9.000 (2010-10-06)
1113 - Support for text stretching and spacing (tracking) was added, see example n. 63 and methods setFontStretching(), getFontStretching(), setFontSpacing(), getFontSpacing().
1114 - Support for CSS properties 'font-stretch' and 'letter-spacing' was added (see example n. 63).
1115 - The cMargin state was replaced by cell_padding array that can be set/get using setCellPadding() and getCellPadding() methods.
1116 - Methods getCellPaddings() and setCellPaddings() were added to fine tune cell paddings (see example n. 5).
1117 - Methods getCellMargins() and setCellMargins() were added to fine tune cell margins (see example n. 5).
1118 - Method write1DBarcode() was improved to permit custom labels (see example n. 27).
1119 - Method ImagePngAlpha() now includes support for ImageMagick to improve performances.
1120 - XObject Template support was extended to support Multicell(), writeHTML() and writeHTMLCell() methods.
1121 - The signature of getNumLines() and getStringHeight() methods is changed.
1122 - Example n. 57 was updated.
1123
1124// -------------------------------------------------------------------
1125
11265.8.034 (2010-09-27)
1127 - A bug related to SetFont on XObject templates was fixed.
1128
11295.8.033 (2010-09-25)
1130 - A problem with Footer() and multiple columns was fixed.
1131
11325.8.032 (2010-09-22)
1133 - Bug #3073165 "Issues with changes to addHTMLVertSpace()" was fixed.
1134
11355.8.031 (2010-09-20)
1136 - Bug #3071961 "Spaces in HTML" was fixed.
1137
11385.8.030 (2010-09-17)
1139 - SVG support was improved and some bugs were fixed.
1140
11415.8.029 (2010-09-16)
1142 - A problem with HTML borders was fixed.
1143
11445.8.028 (2010-09-13)
1145 - Bug #3065224 "mcrypt_create_iv error on TCPDF 5.8.027 on PHP 5.3.2" was fixed.
1146
11475.8.027 (2010-09-13)
1148 - Bug #3065118 "mcrypt_decrypt error on TCPDF 5.8.026 on PHP 5.3.2" was fixed.
1149
11505.8.026 (2010-09-13)
1151 - A bug on addHTMLTOC() method was fixed. Note: be sure that the #TOC_PAGE_NUMBER# template has enough width to be printed correctly.
1152
11535.8.025 (2010-09-09)
1154 - Bug #3062692 "Textarea inside a table" was fixed.
1155
11565.8.024 (2010-09-08)
1157 - Bug #3062005 "Undefined variable: ann_obj_id" was fixed.
1158
11595.8.023 (2010-08-31)
1160 - Forms bug added on version 5.8.019 was fixed.
1161
11625.8.022 (2010-08-31)
1163 - Bug #3056632 "SVG rendered vertically flipped" was fixed.
1164
11655.8.021 (2010-08-30)
1166 - A new CID-0 'chinese' font was added for traditional Chinese.
1167 - Bug #3054287 'Inner tags are ignored due to "align" attribute' was fixed.
1168
11695.8.020 (2010-08-26)
1170 - CSS "catch-all" class selector is now supported.
1171
11725.8.019 (2010-08-26)
1173 - XObject Templates now includes support for links and annotations.
1174 - A problem related to link alignment on cell was fixed.
1175 - A problem related to SVG styles was fixed.
1176
11775.8.018 (2010-08-25)
1178 - Method getNumberOfColumns() was added.
1179 - A problem related to table header was fixed.
1180 - Method getSVGTransformMatrix() was fixed to apply SVG transformations in the correct order.
1181 - SVG support was improved and several bugs were fixed.
1182
11835.8.017 (2010-08-25)
1184 - This version includes support for XObject Templates (see the new example n. 62).
1185 - Methods starttemplate(), endTemplate() and printTemplate() were added (see the new example n. 62).
1186
11875.8.016 (2010-08-24)
1188 - Alignment problem on write2DBarcode was fixed.
1189
11905.8.015 (2010-08-24)
1191 - A problem arised with the latest bugfix was fixed.
1192
11935.8.014 (2010-08-23)
1194 - Method _getxobjectdict() was added for better compatibility with external extensions.
1195 - A bug related to radiobuttons was fixed.
1196 - Bug #3051509 "new line after punctuation marks" was fixed (partially).
1197
11985.8.013 (2010-08-23)
1199 - SVG support for 'direction' property was added.
1200 - A problem on default width calculation for linear barcodes was fixed.
1201 - New option was added to write1DBarcode() method to improve alignments (see example n. 27).
1202 - Bug #3050896 "Nested HTML tables: styles are not applied" was fixed.
1203 - Method _putresourcedict() was improved to include external XObject templates.
1204
12055.8.012 (2010-08-22)
1206 - Support for SVG 'text-anchor' property was added.
1207
12085.8.011 (2010-08-21)
1209 - Method write1DBarcode() was improved to be backward compatible (check the new example n. 27).
1210 - Support for CSS width and height properties on images were added.
1211
12125.8.010 (2010-08-20)
1213 - Documentation of unhtmlentities() was fixed.
1214 - The 'fitwidth' option was added and border color problem was fixed on write1DBarcode() method (check the example n. 27).
1215
12165.8.009 (2010-08-20)
1217 - Internal object numbering was improved.
1218 - Some errors in object encryption were fixed.
1219
12205.8.008 (2010-08-19)
1221 - Method write1DBarcode() was changed, check the example n. 27.
1222 - Method Footer() was changed to account for barcode changes.
1223 - Automatic calculation of K_PATH_URL constant was fixed on configuration file.
1224 - Method setEqualColumns() was fixed for $width=0 case.
1225 - Method AddTOC() was fixed for multipage and multicolumn modes.
1226 - Better support for SVG "font-family" property.
1227 - A problem on default Page Zoom mode was fixed.
1228 - Several Annotation bugs were fixed.
1229
12305.8.007 (2010-08-18)
1231 - A bug affecting HTML tables was fixed.
1232 - Bug #3047500 "SVG not rendering paths properly" was fixed.
1233
12345.8.006 (2010-08-17)
1235 - A bug affecting HTML table nesting was fixed.
1236
12375.8.005 (2010-08-17)
1238 - A bug affecting the HTML 'select' tag in certain conditions was fixed.
1239
12405.8.004 (2010-08-17)
1241 - Better support for HTML "font-family" property.
1242 - A bug related to HTML multicolumn was fixed.
1243
12445.8.003 (2010-08-16)
1245 - Better support for HTML "font-family" property.
1246
12475.8.002 (2010-08-14)
1248 - HTML alignments were improved
1249 - IMPORTANT: Default regular expression to find spaces has been changed to exclude the non-breaking-space (160 DEC- A0 HEX). If you are using setSpacesRE() method, please read the new documentation.
1250 - Example n. 1 was updated.
1251
12525.8.001 (2010-08-12)
1253 - Bug #3043650 "subsetchars incorrectly cached" was fixed.
1254
12555.8.000 (2010-08-11)
1256 - A control to avoid bookmarking page 0 was added.
1257 - addTOC() method now includes support for multicolumn mode.
1258 - Support for tables in multicolumn mode was improved.
1259 - Example n.10 was updated.
1260 - All trimming functions were replaced with stringLeftTrim(), stringRightTrim() and stringTrim().
1261 - HTML alignments were improved.
1262
1263------------------------------------------------------------
1264
12655.7.003 (2010-08-08)
1266 - Bug #3041263 "php source ending is bad" was fixed (all PHP files were updated, including fonts).
1267
12685.7.002 (2010-08-06)
1269 - Methods copyPage(), movePage() and deletePage() were changed to account for internal markings.
1270
12715.7.001 (2010-08-05)
1272 - Bug #3040105 "Broken PDF when using TOC (example 45)" was fixed.
1273
12745.7.000 (2010-08-03)
1275 - CSS borders are now supported for HTML tables and other block tags (see example n. 61);
1276 - Cell borders were improved (see example n. 57);
1277 - Minor bugs were fixed.
1278
1279------------------------------------------------------------
1280
12815.6.000 (2010-07-31)
1282 - A bug with object IDs was fixes.
1283 - Performances were improved.
1284
1285------------------------------------------------------------
1286
12875.5.015 (2010-07-29)
1288 - Automatic fix for unclosed self-closing tag.
1289 - Support for deprecated 's' and 'strike' tags was added.
1290 - Empty list items problem was fixed.
1291
12925.5.014 (2010-07-15)
1293 - Support for external images was improved.
1294
12955.5.013 (2010-07-14)
1296 - Bug #3029338 "FI and FO output destination filename bug" was fixed (previous fix was wrong).
1297
12985.5.012 (2010-07-14)
1299 - Bug #3029310 "Font baseline inconsistencies with line-height and font-size" was fixed.
1300 - Bug #3029338 "FI and FO output destination filename bug" was fixed.
1301
13025.5.011 (2010-07-09)
1303 - Support for multiple CSS classes was added.
1304 - The method getColumn() was added to return the current column number.
1305 - Some regular Expressions were fixed to be more compatible with UTF-8.
1306
13075.5.010 (2010-07-06)
1308 - Bug item #3025772 "Borders in all image functions are still flawed" was fixed.
1309
13105.5.009 (2010-07-05)
1311 - A problem related to last page footer was fixed.
1312 - Image alignments and fit-on-page features were improved.
1313
13145.5.008 (2010-07-02)
1315 - A problem on table header alignment in booklet mode was fixed.
1316 - Default graphic vars are now applied for setHeader();
1317
13185.5.007 (2010-07-02)
1319 - Attribute "readonly" was added to input and textarea form fields.
1320 - Vertical alignment feature was added on MultiCell() method only for simple text mode (see example n. 5).
1321 - Text-Fit feature was added on MultiCell() method only for simple text mode (see example n. 5).
1322
13235.5.006 (2010-06-29)
1324 - getStringHeight() and getNumLines() methods were fixed.
1325
13265.5.005 (2010-06-28)
1327 - Bug #3022170 "getFontDescent() does not return correct descent value" was fixed.
1328 - Some problems with multicolumn mode were fixed.
1329
13305.5.004 (2010-06-27)
1331 - Bug #3021803 "SVG Border" was fixed.
1332
13335.5.003 (2010-06-26)
1334 - On Write() method, blank lines at the beginning of a page or column are now automatically removed.
1335
13365.5.002 (2010-06-24)
1337 - ToUnicode Identity-H name was replaced with a full CMap (to avoid preflight syntax error).
1338 - Bug #3020638 "str_split() not available in php4" was fixed.
1339 - Bug #3020665 "file_get_contents() too many parameters for php4" was fixed.
1340
13415.5.001 (2010-06-23)
1342 - A problem on image streams was fixed.
1343
13445.5.000 (2010-06-22)
1345 - Several PDF syntax errors (and related bugs) were fixed.
1346 - Bug #3019090 "/Length values are wrong if AES encryption is used" was fixed.
1347
1348------------------------------------------------------------
1349
13505.4.003 (2010-06-19)
1351 - A problem related to page boxes was fixed.
1352 - Bug #3016920 "Font subsetting issues when editing pdf" was partially fixed (Note that flattening transparency layers is currently incompatible with TrueTypeUnicode fonts).
1353
13545.4.002 (2010-06-18)
1355 - A problem related with setProtection() method was fixed.
1356
13575.4.001 (2010-06-18)
1358 - A problem related with setProtection() method was fixed.
1359
13605.4.000 (2010-06-18)
1361 - The method setSignatureAppearance() was added, check the example n. 52.
1362 - Several problems related to font subsetting were fixed.
1363
1364------------------------------------------------------------
1365
13665.3.010 (2010-06-15)
1367 - Previous release was corrupted.
1368
13695.3.009 (2010-06-15)
1370 - Bug #3015934 "Bullets don't display correctly" was fixed.
1371
13725.3.008 (2010-06-13)
1373 - This version fixes some problems of SVG rasterization.
1374
13755.3.007 (2010-06-13)
1376 - This version improves SVG support.
1377
13785.3.006 (2010-06-10)
1379 - This version includes a change in uniqid calls for backward compatibility with PHP4.
1380
13815.3.005 (2010-06-09)
1382 - The method getPageSizeFromFormat() was changed to include all standard page formats (includes 281 page formats + variation).
1383
13845.3.004 (2010-06-08)
1385 - Bug #3013291 "HTML table cell width" was fixed.
1386 - Bug #3013294 "HTML table cell alignment" was fixed.
1387 - The columns widths of HTML tables are now inherited from the first row.
1388
13895.3.003 (2010-06-08)
1390 - Bug #3013102 "HTML table header misaligned after page break" was fixed.
1391
13925.3.002 (2010-06-07)
1393 - The methods setFontSubsetting() and setFontSubsetting() were added to control the default font subsetting mode (see example n. 1).
1394 - Bug #3012596 "Whitespace should not appeared after use Thai top characters" was fixed.
1395 - Examples n. 1, 14, and 54 were updated.
1396
13975.3.001 (2010-06-06)
1398 - Barcode PDF417 was improved to support Macro Code Blocks (see example n. 50).
1399
14005.3.000 (2010-06-05)
1401 - License was changed to GNU-LGPLv3 (see the updated LICENSE.TXT file).
1402 - PDF417 barcode support was added (check the example n. 50).
1403 - The method write2DBarcode() was improved (some parameters were added and other changed - check example n. 50).
1404
1405------------------------------------------------------------
1406
14075.2.000 (2010-06-02)
1408 - IMPORTANT: Support for font subsetting was added by default to reduce the size of documents using large unicode font files.
1409 If you embed the whole font in the PDF, the person on the other end can make changes to it even if he didn't have your font.
1410 If you subset the font, file size of the PDF will be smaller but the person who receives your PDF would need to have your same font in order to make changes to your PDF.
1411 - The signature of the SetFont() and AddFont() methods were changed to include the font subsetting option (subsetting is applied by default).
1412 - Examples 14 and 54 were updated.
1413
1414------------------------------------------------------------
1415
14165.1.002 (2010-05-27)
1417 - Bug #3007818 "SetAutoPageBreak fails with MultiCell" was fixed.
1418 - A bug related to MultiCell() minimun height was fixed.
1419
14205.1.001 (2010-05-26)
1421 - The problem of blank page after table was fixed.
1422
14235.1.000 (2010-05-25)
1424 - This version includes support for CSS (Cascading Style Sheets) (see example n. 61).
1425 - The convertHTMLColorToDec() method was improved.
1426
1427------------------------------------------------------------
1428
14295.0.014 (2010-05-21)
1430 - A problem on color and style of HTML links was fixed.
1431 - A bug relative to gradients was fixed.
1432 - The getStringHeight() method was added and getNumLines() method was improved.
1433 - All examples were updated.
1434
14355.0.013 (2010-05-19)
1436 - A bug related to page-breaks and table cells was fixed.
1437
14385.0.012 (2010-05-19)
1439 - Page orientation bug was fixed.
1440 - The access to method setPageFormat() was changed to 'protected' because it is not intended to be directly called.
1441
14425.0.011 (2010-05-19)
1443 - Page orientation bug was fixed.
1444 - Bug #3003966 "Multiple columns and nested lists" was fixed.
1445
14465.0.010 (2010-05-17)
1447 - The methods setPageFormat(), setPageOrientation() and related methods were extended to include page boxes, page rotations and page transitions.
1448 - The method setPageBoxes() was added to set page boundaries (MediaBox, CropBox, BleedBox, TrimBox, ArtBox);
1449 - A bug relative to underline, overline and linethrough was fixed.
1450
14515.0.009 (2010-05-16)
1452 - Bug #3002381 "Multiple columns and nested lists" was fixed.
1453
14545.0.008 (2010-05-15)
1455 - Bug "Columns WriteHTML and Justification" was fixed.
1456
14575.0.007 (2010-05-14)
1458 - Bug #3001347 "Bug when using WriteHTML with setEqualColumns()" was fixed.
1459 - Bug #3001505 "problem with sup and sub tags at the beginning of a line" was fixed.
1460
14615.0.006 (2010-05-13)
1462 - Length of hr tag was fixed.
1463 - An error on 2d barcode method was fixed.
1464
14655.0.005 (2010-05-12)
1466 - WARNING: The logic of permissions on the SetProtection() method has been inverted and extended (see example 16). Now you have to specify the features you want to block.
1467 - SetProtection() method was extended to support RSA and AES 128 encryption and public-keys (see example 16).
1468 - Bug #2999489 "setEqualColumns() and TOC uses wrong columns" was fixed (see the example 10).
1469
14705.0.004 (2010-05-10)
1471 - HTML line alignment when using sub and sup tags was fixed.
1472
14735.0.003 (2010-05-07)
1474 - Horizontal alignment was fixed for images and barcodes. Now the X coordinate is always relative to the left margin. Use GetAbsX() instead of GetX() to get the X relative to left margin.
1475 - Header() method was changed to account for new image alignment rules.
1476
14775.0.002 (2010-05-06)
1478 - Bookmark() and related methods were fixed to accept HTML code.
1479 - A problem on HTML links was fixed.
1480
14815.0.001 (2010-05-06)
1482 - Protected method _putstream was re-added for backward compatibility.
1483 - The following method were added to display HTML Table Of Content (see example n. 59):
1484 addTOCPage(), endTOCPage(), addHTMLTOC().
1485
14865.0.000 (2010-05-05)
1487 - Method ImageSVG() was added to embedd SVG images (see example n. 58). Note that not all SVG images are supported.
1488 - Method setRasterizeVectorImages() was added to enable/disable rasterization for vector images via ImageMagick library.
1489 - Method RoundedRectXY() was added.
1490 - Method PieSectorXY() was added.
1491 - Gradient() method is now public and support new features.
1492 - Shading to transparency is now supported.
1493 - Image alignments were fixed.
1494 - Support for dynamic images were improved.
1495 - PDF_IMAGE_SCALE_RATIO has been changed to 1.25 for better compatibility with SVG.
1496 - RAW and RAW2 modes were added to 2D Barcodes (see example n. 50).
1497 - Automatic padding feature was added on barcodes (see examples n. 27 and 50).
1498 - Bug #2995003 "Reproduced thead bug" was fixed.
1499 - The Output() method now accepts FI and FD destinations to save the document on server before sending it to the client.
1500 - Ellipse() method was improved and fixed (see page 2 of example n. 12).
1501
1502------------------------------------------------------------
1503
15044.9.018 (2010-04-21)
1505 - Bug item #2990356 "Current font size not respected with more than two HTML <p>" was fixed.
1506
15074.9.017 (2010-04-21)
1508 - Bug item #2990224 "Different behaviour for equivalent HTML strings" was fixed.
1509 - Bug item #2990314 "Dash is not appearing with SHY character" was fixed.
1510
15114.9.016 (2010-04-20)
1512 - An error on htmlcolors.php was fixed.
1513 - getImageFileType() method was improved.
1514 - GIF images with transparency are now better supported.
1515 - Automatic page orientation was improved.
1516
15174.9.015 (2010-04-20)
1518 - A new method copyPage() was added to clone pages (see example n. 44).
1519 - Support for text overline was added.
1520 - Underline and linethrough methods were fixed.
1521 - Bug #2989058 "SHY character causes unnecessary word-wrapping" was fixed.
1522
15234.9.014 (2010-04-18)
1524 - Bug item #2988845 was fixed.
1525
15264.9.013 (2010-04-15)
1527 - Image() and ImageEPS() methods were fixed and improved; $fitonpage parameter was added.
1528
15294.9.012 (2010-04-12)
1530 - The hyphenateText() method was added to automatically hyphenate text (see example n. 46).
1531
15324.9.011 (2010-04-07)
1533 - Vertical alignments for Cell() method were improved (see example n. 57).
1534
15354.9.010 (2010-04-06)
1536 - Signature of Cell() method now includes new parameters for vertical alignment (see example n. 57).
1537 - Text() method was extended to include all Cell() parameters.
1538 - HTML line alignment procedure was changed to fix some bugs.
1539
15404.9.009 (2010-04-05)
1541 - Text() method was fixed for backward compatibility.
1542
15434.9.008 (2010-04-03)
1544 - Additional line space after table header was removed.
1545 - Support for HTML lists in multicolumn mode was added.
1546 - The method setTextRenderingMode() was added to set text rendering modes (see the example n. 26).
1547 - The following HTML attributes were added to set text rendering modes (see the example n. 26): stroke, strokecolor, fill.
1548
15494.9.007 (2010-04-03)
1550 - Font Descent computation was fixed (patch #2981441).
1551
15524.9.006 (2010-04-02)
1553 - The constant K_TCPDF_CALLS_IN_HTML was added on configuration file to enable/disable the ability to call TCPDF methods in HTML.
1554 - The usage of tcpdf tag in HTML mode was changed to remove the possible security flaw offered by the eval() function (thanks to Matthias Hecker for spotting this security problem). See the new example n. 49 for further information.
1555
15564.9.005 (2010-04-01)
1557 - Bug# 2980354 "Wrong File attachment description with security" was fixed.
1558 - Several problems with HTML line alignment were fixed.
1559 - The constant K_THAI_TOPCHAR was added on configuration file to enable/disable the special procedure used to avoid the overlappind of symbols on Thai language.
1560 - A problem with font name directory was fixed.
1561 - A bug on _destroy() method was fixed.
1562
15634.9.004 (2010-03-31)
1564 - Patch #979681 "GetCharWidth - default character width" was applied (bugfix).
1565
15664.9.003 (2010-03-30)
1567 - Problem of first <br /> on multiple columns was fixed.
1568 - HTML line alignment was fixed.
1569 - A QR-code bug was fixed.
1570
15714.9.002 (2010-03-29)
1572 - Patch #2978349 "$ignore_min_height is ignored in function Cell()" was applied.
1573 - Bug #2978607 "2D Barcodes are wrong" was fixed.
1574 - A problem with HTML block tags was fixed.
1575 - Artificial italic for CID-0 fonts was added.
1576 - Several multicolumn bugs were fixed.
1577 - Support for HTML tables on multicolumn was added.
1578
15794.9.001 (2010-03-28)
1580 - QR Code minor bug was fixed.
1581 - Multicolumn mode was added (see the new example n. 10).
1582 - The following methods were added: setEqualColumns(), setColumnsArray(), selectColumn().
1583 - Thai diacritics support were changed (note that this is incompatible with html justification).
1584
15854.9.000 (2010-03-27)
1586 - QR Code (2D barcode) support was added (see example n. 50).
1587 - The following methods were added to print crop and registration marks (see example n. 56): colorRegistrationBar(), cropMark(), registrationMark().
1588 - Limited support for CSS line-height property was added.
1589 - Gradient method now supports Gray, RGB and CMYK space color.
1590 - Example n. 51 was updated.
1591 - Vertical alignment of font inside cell was fixed.
1592 - Support for multiple Thai diacritics was added.
1593 - Bug item #2974929 "Duplicate case values" was fixed.
1594 - Bug item #2976729 "File attachment not working with security" was fixed.
1595
1596------------------------------------------------------------
1597
15984.8.039 (2010-03-20)
1599 - Problems related to custom locale settings were fixed.
1600 - Problems related to HTML on Header and Footer were fixed.
1601
16024.8.038 (2010-03-13)
1603 - Various bugs related to page-break in HTML mode were fixed.
1604 - Bug item #2968974 "Another <thead> pagebreak problem" was fixed.
1605 - Bug item #2969276 "justification problem" was fixed.
1606 - Bug item #2969289 "bug when using justified text and custom headers" was fixed.
1607 - Images are now automatically resized to be contained on the page.
1608 - Some HTML line alignments were fixed.
1609 - Signature of AddPage() and SetMargins() methods were changed to include an option to set default page margins.
1610
16114.8.037 (2010-03-03)
1612 - Bug item #2962068 was fixed.
1613 - Bug item #2967017 "Problems with <thead> and pagebreaks" was fixed.
1614 - Bug item #2967023 "table header lost with pagebreak" was fixed.
1615 - Bug item #2967032 "Header lost with nested tables" was fixed.
1616
16174.8.036 (2010-02-24)
1618 - Automatic page break for HTML images was improved.
1619 - Example 10 was updated.
1620 - Japanese was removed from example 8 because the freeserif font doesn't contain japanese (you can display it using arialunicid0 font).
1621
16224.8.035 (2010-02-23)
1623 - Automatic page break for HTML images was added.
1624 - Support for multicolumn HTML was added (example 10 was updated).
1625
16264.8.034 (2010-02-17)
1627 - Language files were updated.
1628
16294.8.033 (2010-02-12)
1630 - A bug related to protection mode with links was fixed.
1631
16324.8.032 (2010-02-04)
1633 - A bug related to $maxh parameter on Write() and MultiCell() was fixed.
1634 - Support for body tag was added.
1635
16364.8.031 (2010-01-30)
1637 - Bug item #2941589 "paragraph justify not working on some non-C locales" was fixed.
1638
16394.8.030 (2010-01-27)
1640 - Some text alignment cases were fixed.
1641
16424.8.029 (2010-01-27)
1643 - Bug item #2941057 "TOC Error in PDF File Output" was fixed.
1644 - Some text alignment cases were fixed.
1645
16464.8.028 (2010-01-26)
1647 - Text alignment for RTL mode was fixed.
1648
16494.8.027 (2010-01-25)
1650 - Bug item #2938412 "Table related problems - thead, nobr, table width" was fixed.
1651
16524.8.026 (2010-01-19)
1653 - The misspelled word "lenght" was replaced with "length" in some variables and comments.
1654
16554.8.025 (2010-01-18)
1656 - addExtGState() method was improved to reuse existing ExtGState objects.
1657
16584.8.024 (2010-01-15)
1659 - Justification mode for HTML was fixed (Bug item #2932470).
1660
16614.8.023 (2010-01-15)
1662 - Bug item #2932470 "Some HTML entities breaks justification" was fixed.
1663
16644.8.022 (2010-01-14)
1665 - Source code documentation was fixed.
1666
16674.8.021 (2010-01-03)
1668 - A Bug relative to Table Of Content index was fixed.
1669
16704.8.020 (2009-12-21)
1671 - Bug item #2918545 "Display problem of the first row of a table with larger font" was fixed.
1672 - A Bug relative to table rowspan mode was fixed.
1673
16744.8.019 (2009-12-16)
1675 - Bug item #2915684 "Image size" was fixed.
1676 - Bug item #2914995 "Image jpeg quality" was fixed.
1677 - The signature of the Image() method was changed (check the documentation for the $resize parameter).
1678
16794.8.018 (2009-12-15)
1680 - Bug item #2914352 "write error" was fixed.
1681
16824.8.017 (2009-11-27)
1683 - THEAD problem when table is used on header/footer was fixed.
1684 - A first line alignment on HTML justification was fixed.
1685 - Method getImageFileType() was added.
1686 - Images with unknown extension and type are now supported via ImageMagick PHP extension.
1687
16884.8.016 (2009-11-21)
1689 - Document Information Dictionary was fixed.
1690 - CSS attributes 'page-break-before', 'page-break-after' and 'page-break-inside' are now supported.
1691 - Problem of unclosed last page was fixed.
1692 - Problem of 'thead' unnecessarily repeated on the next page was fixed.
1693
16944.8.015 (2009-11-20)
1695 - A problem with some PNG transparency images was fixed.
1696 - Bug #2900762 "Sort issues in Bookmarks" was fixed.
1697 - Text justification was fixed for various modes: underline, strikeout and background.
1698
16994.8.014 (2009-11-04)
1700 - Bug item #2891316 "writeHTML, underlining replacing spaces" was fixed.
1701 - The handling of temporary RTL text direction mode was fixed.
1702
17034.8.013 (2009-10-26)
1704 - Bug item #2884729 "Problem with word-wrap and hyphen" was fixed.
1705
17064.8.012 (2009-10-23)
1707 - Table cell alignments for RTL booklet mode were fixed.
1708 - Images and barcode alignments for booklet mode were fixed.
1709
17104.8.011 (2009-10-22)
1711 - DejaVu fonts were updated to latest version.
1712
17134.8.010 (2009-10-21)
1714 - Bookmark for TOC page was added.
1715 - Signature of addTOC() method is changed.
1716 - Bookmarks are now automatically sorted by page and Y position.
1717 - Example n. 45 was updated.
1718 - Example n. 55 was added to display all charactes available on core fonts.
1719
17204.8.009 (2009-09-30)
1721 - Compatibility with PHP 5.3 was improved.
1722 - All examples were updated.
1723 - Index file for examples was added.
1724
17254.8.008 (2009-09-29)
1726 - Example 49 was updated.
1727 - Underline and linethrough now works with cell stretching mode.
1728
17294.8.007 (2009-09-23)
1730 - Infinite loop problem caused by nobr attribute was fixed.
1731
17324.8.006 (2009-09-23)
1733 - Bug item #2864522 "No images if DOCUMENT_ROOT=='/'" was fixed.
1734 - Support for text-indent CSS attribute was added.
1735 - Method rollbackTransaction() was changed to support self-reassigment of previous object (check source code documentation).
1736 - Support for the HTML "nobr" attribute was added to avoid splitting a table or a table row on two pages (i.e.: <tr nobr="true">...</tr>).
1737
17384.8.005 (2009-09-17)
1739 - A bug relative to multiple transformations and annotations was fixed.
1740
17414.8.004 (2009-09-16)
1742 - A bug on _putannotsrefs() method was fixed.
1743
17444.8.003 (2009-09-15)
1745 - Bug item #2858754 "Division by zero" was fixed.
1746 - A bug relative to HTML list items was fixed.
1747 - A bug relative to form fields on multiple pages was fixed.
1748 - PolyLine() method was added (see example n. 12).
1749 - Signature of Polygon() method was changed.
1750
17514.8.002 (2009-09-12)
1752 - A problem related to CID-0 fonts offset was fixed: if the $cw[1] entry on the CID-0 font file is not defined, then a CID keys offset is introduced.
1753
17544.8.001 (2009-09-09)
1755 - The appearance streams (AP) for anotations form fields was fixed (see examples n. 14 and 54).
1756 - Radiobuttons were fixed.
1757
17584.8.000 (2009-09-07)
1759 - This version includes some support for Forms fields (see example n. 14) and XHTML forms (see example n. 54).
1760 - The following methods were changed to work without JavaScript: TextField(), RadioButton(), ListBox(), ComboBox(), CheckBox(), Button().
1761 - Support for Widget annotations was improved.
1762 - Alignment of annotation objects was fixed (examples 36 and 41 were updated).
1763 - addJavascriptObject() method was added.
1764 - Signature of Image() method was changed.
1765 - htmlcolors.php file was updated.
1766
1767------------------------------------------------------------
1768
17694.7.003 (2009-09-03)
1770 - Support for TCPDF methods on HTML was improved (see example n. 49).
1771
17724.7.002 (2009-09-02)
1773 - Bug item #2848892 "writeHTML + table: Gaps between rows" was fixed.
1774 - JavaScript support was fixed (see example n. 53).
1775
17764.7.001 (2009-08-30)
1777 - The Polygon() and Arrow() methods were fixed and improved (see example n. 12).
1778
17794.7.000 (2009-08-29)
1780 - This is a major release.
1781 - Some procedures were internally optimized.
1782 - The problem of mixed signature and annotations was fixed (example n. 52).
1783
17844.6.030 (2009-08-29)
1785 - IMPORTANT: percentages on table cell widths are now relative to the full table width (as in standard HTML).
1786 - Various minor bugs were fixed.
1787 - Example n. 52 (digital signature) was updated.
1788
17894.6.029 (2009-08-26)
1790 - PHP4 version was fixed.
1791
17924.6.028 (2009-08-25)
1793 - Signature algorithm was finally fixed (see example n. 52).
1794
17954.6.027 (2009-08-24)
1796 - TCPDF now supports unembedded TrueTypeUnicode Fonts (just comment the $file entry on the fonts' php file.
1797
17984.6.026 (2009-08-21)
1799 - Bug #2841693 "Problem with MultiCell and ishtml and justification" was fixed.
1800 - Signature functions were improved but not yet fixed (tcpdf.crt and example n. 52 were updated).
1801
18024.6.025 (2009-08-17)
1803 - Carriage returns (\r) were removed from source code.
1804 - Problem related to set_magic_quotes_runtime() depracated was fixed.
1805
18064.6.024 (2009-08-07)
1807 - Bug item #2833556 "justification using other units than mm" was fixed.
1808 - Documentation was fixed/updated.
1809
18104.6.023 (2009-08-02)
1811 - Bug item #2830537 "MirrorH can show mask for transparent PNGs" was fixed.
1812
18134.6.022 (2009-07-24)
1814 - A bug relative to single line printing when using WriteHTMLCell() was fixed.
1815 - Signature support were improved but is still experimental.
1816 - Fonts Free and Dejavu were updated to latest versions.
1817
18184.6.021 (2009-07-20)
1819 - Bug item #2824015 "XHTML Ampersand &amp; in hyperlink bug" was fixed.
1820 - Bug item #2824036 "Image as hyperlink in table, text displaced at page break" was fixed.
1821 - Links alignment on justified text was fixed.
1822 - Unicode "\u" modifier was added to re_spaces variable by default.
1823
18244.6.020 (2009-07-16)
1825 - Bug item #2821921 "issue in example 18" was fixed.
1826 - Signature of SetRTL() method was changed.
1827
18284.6.019 (2009-07-13)
1829 - Bug item #2820703 "xref table broken" was fixed.
1830
18314.6.018 (2009-07-10)
1832 - Bug item #2819319 "Text over text" was fixed.
1833 - Method Arrow() was added to print graphic arrows (example 12 was updated).
1834
18354.6.017 (2009-07-05)
1836 - Bug item #2816079 "Example 48 not working" was fixed.
1837 - The signature of the checkPageBreak() was changed. The parameter $addpage was added to turn off the automatic page creation.
1838
18394.6.016 (2009-06-16)
1840 - Method setSpacesRE() was added to set the regular expression used for detecting withespaces or word separators. If you are using chinese, try: setSpacesRE('/[\s\p{Z}\p{Lo}]/');, otherwise you can use setSpacesRE('/[\s\p{Z}]/');
1841 - The method _putinfo() now automatically fills the metadata with '?' in case of empty string.
1842
18434.6.015 (2009-06-11)
1844 - Bug #2804667 "word wrap bug" was fixed.
1845
18464.6.014 (2009-06-04)
1847 - Bug #2800931 "Table thead tag bug" was fixed.
1848 - A bug related to <pre> tag was fixed.
1849
18504.6.013 (2009-05-28)
1851 - List bullets position was fixed for RTL languages.
1852
18534.6.012 (2009-05-23)
1854 - setUserRights() method doesn't work anymore unless you call the setSignature() method with the Adobe private key!
1855
18564.6.011 (2009-05-18)
1857 - Signature of the Image() method was changed to include the new $fitbox parameter (see source code documentation).
1858
18594.6.010 (2009-05-17)
1860 - Image() method was improved: now is possible to specify the maximum dimensions for a constraint box defined by $w and $h parameters, and setting the $resize parameter to null.
1861 - <tcpdf> tag indent problem was fixed.
1862 - $y parameter was added to checkPageBreak() method.
1863 - Bug n. 2791773 "writeHTML" was fixed.
1864
18654.6.009 (2009-05-13)
1866 - xref table for embedded files was fixed.
1867
18684.6.008 (2009-05-07)
1869 - setSignature() method was improved (but is still experimental).
1870 - Example n. 52 was added.
1871
18724.6.007 (2009-05-05)
1873 - Bug #2786685 "writeHtmlCell and <br /> in custom footer" was fixed.
1874 - Table header repeating bug was fixed.
1875 - Some newlines and tabs are now automatically removed from HTML strings.
1876
18774.6.006 (2009-04-28)
1878 - Support for "<a name="...">...</a>" was added.
1879 - By default TCPDF requires PCRE Unicode support turned on but now works also without it (with limited ability to detect some Unicode blank spaces).
1880
18814.6.005 (2009-04-25)
1882 - Points (pt) conversion in getHTMLUnitToUnits() was fixed.
1883 - Default tcpdf.pem certificate file was added.
1884 - Experimental support for signing document was added but it is not yet completed (some help is needed - I think that the calculation of the ByteRange is OK and the problem is on the signature calculation).
1885
18864.6.004 (2009-04-23)
1887 - Method deletePage() was added to delete pages (see example n. 44).
1888
18894.6.003 (2009-04-21)
1890 - The caching mechanism of the UTF8StringToArray() method was fixed.
1891
18924.6.002 (2009-04-20)
1893 - Documentation of rollbackTransaction() method was fixed.
1894 - The setImageScale() and getImageScale() methods now set and get the adjusting parameter used by pixelsToUnits() method.
1895 - HTML images now support other units of measure than pixels (getHTMLUnitToUnits() is now used instead of pixelsToUnits()).
1896 - WARNING: PDF_IMAGE_SCALE_RATIO has been changed by default to 1.
1897
18984.6.001 (2009-04-17)
1899 - Spaces between HTML block tags are now automatically removed.
1900 - The bug related to cMargin changes between tables was fixed.
1901
19024.6.000 (2009-04-16)
1903 - WARNING: THIS VERSION CHANGES THE BEHAVIOUR OF $x and $y parameters for several TCPDF methods:
1904 zero coordinates for $x and $y are now valid coordinates;
1905 set $x and $y as empty strings to get the current value.
1906 - Some error caused by 'empty' funtion were fixed.
1907 - Default color for convertHTMLColorToDec() method was changed to white and the return value for invalid color is false.
1908 - HTML on footer bug was fixed.
1909 - The following examples were fixed: 5,7,10,17,19,20,21,33,42,43.
1910
19114.5.043 (2009-04-15)
1912 - Barcode class (barcode.php) was extended to include new linear barcode types (see example n. 27):
1913 C39 : CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9
1914 C39+ : CODE 39 with checksum
1915 C39E : CODE 39 EXTENDED
1916 C39E+ : CODE 39 EXTENDED + CHECKSUM
1917 C93 : CODE 93 - USS-93
1918 S25 : Standard 2 of 5
1919 S25+ : Standard 2 of 5 + CHECKSUM
1920 I25 : Interleaved 2 of 5
1921 I25+ : Interleaved 2 of 5 + CHECKSUM
1922 C128A : CODE 128 A
1923 C128B : CODE 128 B
1924 C128C : CODE 128 C
1925 EAN2 : 2-Digits UPC-Based Extention
1926 EAN5 : 5-Digits UPC-Based Extention
1927 EAN8 : EAN 8
1928 EAN13 : EAN 13
1929 UPCA : UPC-A
1930 UPCE : UPC-E
1931 MSI : MSI (Variation of Plessey code)
1932 MSI+ : MSI + CHECKSUM (modulo 11)
1933 POSTNET : POSTNET
1934 PLANET : PLANET
1935 RMS4CC : RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)
1936 KIX : KIX (Klant index - Customer index)
1937 IMB: Intelligent Mail Barcode - Onecode - USPS-B-3200 (NOTE: requires BCMath PHP extension)
1938 CODABAR : CODABAR
1939 CODE11 : CODE 11
1940 PHARMA : PHARMACODE
1941 PHARMA2T : PHARMACODE TWO-TRACKS
1942
19434.5.042 (2009-04-15)
1944 - Method Write() was fixed for the strings containing only zero value.
1945
19464.5.041 (2009-04-14)
1947 - Barcode methods were fixed.
1948
19494.5.040 (2009-04-14)
1950 - Method Write() was fixed to handle empty strings.
1951
19524.5.039 (2009-04-11)
1953 - Support for linear barcodes was extended (see example n. 27 and barcodes.php documentation).
1954
19554.5.038 (2009-04-10)
1956 - Write() method was improved to support separators for Japanese, Korean, Chinese Traditional and Chinese Simplified.
1957
19584.5.037 (2009-04-09)
1959 - General performances were improved.
1960 - The signature of the method utf8Bidi() was changed.
1961 - The method UniArrSubString() was added.
1962 - Experimental support for 2D barcodes were added (see example n. 50 and 2dbarcodes.php class).
1963
19644.5.036 (2009-04-03)
1965 - TCPDF methods can be called inside the HTML code (see example n. 49).
1966 - All tag attributes, such as <p align="center"> must be enclosed within double quotes.
1967
19684.5.035 (2009-03-28)
1969 - Bug #2717436 "writeHTML rowspan problem (continued)" was fixed.
1970 - Bug #2719090 "writeHTML fix follow up" was fixed.
1971 - The method _putuserrights() was changed to avoid Adobe Reader 9.1 crash. This broken the 'trick' that was used to display forms in Acrobat Reader.
1972
19734.5.034 (2009-03-27)
1974 - Bug #2716914 "Bug writeHTML of a table in body and footer related with pb" was fixed.
1975 - Bug #2717056 ] "writeHTML problem when setting tr style" was fixed.
1976 - The signature of the Cell() method was changed.
1977
19784.5.033 (2009-03-27)
1979 - The support for rowspan/colspan on HTML tables was improved (see example n. 48).
1980
19814.5.032 (2009-03-23)
1982 - setPrintFooter(false) bug was fixed.
1983
19844.5.031 (2009-03-20)
1985 - Table header support was extended to multiple pages.
1986
19874.5.030 (2009-03-20)
1988 - thead tag is now supported on HTML tables (header rows are repeated after page breaks).
1989 - The startTransaction() was improved to autocommit.
1990 - List bullets now uses the foreground color (putHtmlListBullet()).
1991
19924.5.029 (2009-03-19)
1993 - The following methods were added to UNDO commands (see example 47): startTransaction(), commitTransaction(), rollbackTransaction().
1994 - All examples were updated.
1995
19964.5.028 (2009-03-18)
1997 - Bug #2690945 "List Bugs" was fixed.
1998 - HTML text alignment on lists was fixed.
1999 - The constant PDF_FONT_MONOSPACED was added to the configuration file to define the default monospaced font.
2000 - The following methods were fixed: getPageWidth(), getPageHeight(), getBreakMargin().
2001 - All examples were updated.
2002
20034.5.027 (2009-03-16)
2004 - Method getPageDimensions() was added to get page dimensions.
2005 - The signature of the following methos were changed: getPageWidth(), getPageHeight(), getBreakMargin().
2006 - _parsepng() method was fixed for PNG URL images (fread bug).
2007
20084.5.026 (2009-03-11)
2009 - Bug #2681793 affecting URL images with spaces was fixed.
2010
20114.5.025 (2009-03-10)
2012 - A small bug affecting hyphenation support was fixed.
2013 - The method SetDefaultMonospacedFont() was added to define the default monospaced font.
2014
20154.5.024 (2009-03-07)
2016 - The bug #2666493 was fixed "Footer corrupts document".
2017
20184.5.023 (2009-03-06)
2019 - The bug #2666688 was fixed "Rowspan in tables".
2020
20214.5.022 (2009-03-05)
2022 - The bug #2659676 was fixed "refer to #2157099 test 4 < BR > problem still not fixed".
2023 - addTOC() function bug was fixed.
2024
20254.5.020 (2009-03-03)
2026 - The following bug was fixed: "function removeSHY corrupts unicode".
2027
20284.5.019 (2009-02-28)
2029 - The problem of decimal separator using different locale was fixed.
2030 - The text hyphenation is now supported (see example n. 46).
2031
20324.5.018 (2009-02-26)
2033 - The _destroy() method was added to unset all class variables and frees memory.
2034 - Now it's possible to call Output() method multiple times.
2035
20364.5.017 (2009-02-24)
2037 - A minor bug that raises a PHP warning was fixed.
2038
20394.5.016 (2009-02-24)
2040 - Bug item #2631200 "getNumLines() counts wrong" was fixed.
2041 - Multiple attachments bug was fixed.
2042 - All class variables are now cleared on Output() for memory otpimization.
2043
20444.5.015 (2009-02-18)
2045 - Bug item #2612553 "function Write() must not break a line on &nbsp; character" was fixed.
2046
20474.5.014 (2009-02-13)
2048 - Bug item #2595015 "POSTNET Barcode Checksum Error" was fixed (on barcode.php).
2049 - Pagebreak bug for barcode was fixed.
2050
20514.5.013 (2009-02-12)
2052 - border attribute is now supported on HTML images (only accepts the same values accepted by Cell()).
2053
20544.5.012 (2009-02-12)
2055 - An error on image border feature was fixed.
2056
20574.5.011 (2009-02-12)
2058 - HTML links for images are now supported.
2059 - height attribute is now supported on HTML cells.
2060 - $border parameter was added to Image() and ImageEps() methods.
2061 - The method getNumLines() was added to estimate the number of lines required for the specified text.
2062
20634.5.010 (2009-01-29)
2064 - Bug n. 2546108 "BarCode Y position" was fixed.
2065
20664.5.009 (2009-01-26)
2067 - Bug n. 2538094 "Empty pdf file created" was fixed.
2068
20694.5.008 (2009-01-26)
2070 - setPage() method was fixed to correctly restore graphic states.
2071 - Source code was cleaned up for performances.
2072
20734.5.007 (2009-01-24)
2074 - checkPageBreak() and write1DBarcode() methods were fixed.
2075 - Source code was cleaned up for performances.
2076 - barcodes.php was updated.
2077
20784.5.006 (2009-01-23)
2079 - getHTMLUnitToPoints() method was replaced by getHTMLUnitToUnits() to fix HTML units bugs.
2080
20814.5.005 (2009-01-23)
2082 - Page closing bug was fixed.
2083
20844.5.004 (2009-01-21)
2085 - The access of convertHTMLColorToDec() method was changed to public
2086 - Fixed bug on UL tag.
2087
20884.5.003 (2009-01-19)
2089 - Fonts on different folders are now supported.
2090
20914.5.002 (2009-01-07)
2092 - addTOC() function was improved (see example n. 45).
2093
20944.5.001 (2009-01-04)
2095 - The signature of startPageGroup() function was changed.
2096 - Method Footer() was improved to automatically print page or page-group number (see example n. 23).
2097 - Protected method formatTOCPageNumber() was added to customize the format of page numbers on the Table Of Content.
2098 - The signature of addTOC() was changed to include the font used for page numbers.
2099
21004.5.000 (2009-01-03)
2101 - A new $diskcache parameter was added to class constructor to enable disk caching and reduce RAM memory usage (see example n. 43).
2102 - The method movePageTo() was added to move pages to previous positions (see example n. 44).
2103 - The methods getAliasNumPage() and getPageNumGroupAlias() were added to get the alias for page number (needed when using movepageTo()).
2104 - The methods addTOC() was added to print a Table Of Content (see example n. 45).
2105 - Imagick class constant was removed for better compatibility with PHP4.
2106 - All existing examples were updated and new examples were added.
2107
21084.4.009 (2008-12-29)
2109 - Examples 1 and 35 were fixed.
2110
21114.4.008 (2008-12-28)
2112 - Bug #2472169 "Unordered bullet size not adjusted for unit type" was fixed.
2113
21144.4.007 (2008-12-23)
2115 - Bug #2459935 "no unit conversion for header line" was fixed.
2116 - Example n. 42 for image alpha channel was added.
2117 - All examples were updated.
2118
21194.4.006 (2008-12-11)
2120 - Method setLIsymbol() was changed to reflect latest changes in HTML list handling.
2121
21224.4.005 (2008-12-10)
2123 - Bug item #2413870 "ordered list override value" was fixed.
2124
21254.4.004 (2008-12-10)
2126 - The protected method getHTMLUnitToPoints() was added to accept various HTML units of measure (em, ex, px, in, cm, mm, pt, pc, %).
2127 - The method intToRoman() was added to convert integer number to Roman representation.
2128 - Support fot HTML lists was improved: the CSS property list-style-type is now supported.
2129
21304.4.003 (2008-12-09)
2131 - Bug item #2412147 "Warning on line 3367" was fixed.
2132 - Method setHtmlLinksStyle() was added to set default HTML link colors and font style.
2133 - Method addHtmlLink() was changed to use color and style defined on the inline CSS.
2134
21354.4.002 (2008-12-09)
2136 - Borders on Multicell() were fixed.
2137 - Problem of Multicell() on Header function (Bug item #2407579) was fixed.
2138 - Problem on graphics tranformations applied to Multicell() was fixed.
2139 - Support for ImageMagick was added.
2140 - Width calculation for nested tables was fixed.
2141
21424.4.001 (2008-12-08)
2143 - Some missing core fonts were added on fonts directory.
2144 - CID0 fonts rendering was fixed.
2145 - HTML support was improved (<pre> and <tt> tags are now supported).
2146 - Bug item #2406022 "Left padding bug in MultiCell with maxh" was fixed.
2147
21484.4.000 (2008-12-07)
2149 - File attachments are now supported (see example n. 41).
2150 - Font functions were optimized to reduce document size.
2151 - makefont.php was updated.
2152 - Linux binaries were added on /fonts/utils
2153 - All fonts were updated.
2154 - $autopadding parameter was added to Multicell() to disable automatic padding features.
2155 - $maxh parameter was added to Multicell() and Write() to set a maximum height.
2156
21574.3.009 (2008-12-05)
2158 - Bug item #2392989 (Custom header + setlinewidth + cell border bug) was fixed.
2159
21604.3.008 (2008-12-05)
2161 - Bug item #2390566 "rect bug" was fixed.
2162 - File path was fixed for font embedded files.
2163 - SetFont() method signature was changed to include the font filename.
2164 - Some font-related methods were improved.
2165 - Methods getFontFamily() and getFontStyle() were added.
2166
21674.3.007 (2008-12-03)
2168 - PNG alpha channel is now supported (GD library is required).
2169 - AddFont() function now support custom font file path on $file parameter.
2170 - The default width variable ($dw) is now always defined for any font.
2171 - The 'Style' attribute on CID-0 fonts was removed because of protection bug.
2172
21734.3.006 (2008-12-01)
2174 - A regular expression on getHtmlDomArray() to find HTML tags was fixed.
2175
21764.3.005 (2008-11-25)
2177 - makefont.php was fixed.
2178 - Bug item #2339877 was fixed (false loop condition detected on WriteHTML()).
2179 - Bug item #2336733 was fixed (lasth value update on Multicell() when border and fill are disabled).
2180 - Bug item #2342303 was fixed (automatic page-break on Image() and ImageEPS()).
2181
21824.3.004 (2008-11-19)
2183 - Function _textstring() was fixed (bug 2309051).
2184 - All examples were updated.
2185
21864.3.003 (2008-11-18)
2187 - CID-0 font bug was fixed.
2188 - Some functions were optimized.
2189 - Function getGroupPageNoFormatted() was added.
2190 - Example n. 23 was updated.
2191
21924.3.002 (2008-11-17)
2193 - Bug item #2305518 "CID-0 font don't work with encryption" was fixed.
2194
21954.3.001 (2008-11-17)
2196 - Bug item #2300007 "download mimetype pdf" was fixed.
2197 - Double quotes were replaced by single quotes to improve PHP performances.
2198 - A bug relative to HTML cell borders was fixed.
2199
22004.3.000 (2008-11-14)
2201 - The function setOpenCell() was added to set the top/bottom cell sides to be open or closed when the cell cross the page.
2202 - A bug relative to list items indentation was fixed.
2203 - A bug relative to borders on HTML tables and Multicell was fixed.
2204 - A bug relative to rowspanned cells was fixed.
2205 - A bug relative to html images across pages was fixed.
2206
22074.2.009 (2008-11-13)
2208 - Spaces between li tags are now automatically removed.
2209
22104.2.008 (2008-11-12)
2211 - A bug relative to fill color on next page was fixed.
2212
22134.2.007 (2008-11-12)
2214 - The function setListIndentWidth() was added to set custom indentation widht for HTML lists.
2215
22164.2.006 (2008-11-06)
2217 - A bug relative to HTML justification was fixed.
2218
22194.2.005 (2008-11-06)
2220 - A bug relative to HTML justification was fixed.
2221 - The methods formatPageNumber() and PageNoFormatted() were added to format page numbers.
2222 - Default Footer() method was changed to use PageNoFormatted() instead of PageNo().
2223 - Example 6 was updated.
2224
22254.2.004 (2008-11-04)
2226 - Bug item n. 2217039 "filename handling improvement" was fixed.
2227
22284.2.003 (2008-10-31)
2229 - Font style bug was fixed.
2230
22314.2.002 (2008-10-31)
2232 - Bug item #2210922 (htm element br not work) was fixed.
2233 - Write() function was improved to support margin changes.
2234
22354.2.001 (2008-10-30)
2236 - setHtmlVSpace($tagvs) function was added to set custom vertical spaces for HTML tags.
2237 - writeHTML() function now support margin changes during execution.
2238 - Signature of addHTMLVertSpace() function is changed.
2239
22404.2.000 (2008-10-29)
2241 - htmlcolors.php was changed to support class-loaders.
2242 - ImageEps() function was improved in performances.
2243 - Signature of Link() And Annotation() functions were changed.
2244 - (Bug item #2198926) Links and Annotations alignment were fixed (support for geometric tranformations was added).
2245 - rowspan mode for HTML table cells was improved and fixed.
2246 - Booklet mode for double-sided pages was added; see SetBooklet() function and example n. 40.
2247 - lastPage() signature is changed.
2248 - Signature of Write() function is changed.
2249 - Some HTML justification problems were fixed.
2250 - Some functions were fixed to better support RTL mode.
2251 - Example n. 10 was changed to support RTL mode.
2252 - All examples were updated.
2253
22544.1.004 (2008-10-23)
2255 - unicode_data.php was changed to support class-loaders.
2256 - Bug item #2186040/2 (writeHTML margin problem) was fixed.
2257
22584.1.003 (2008-10-22)
2259 - Bug item #2185399 was fixed (rowspan and page break).
2260 - Bugs item #2186040 was fixed (writeHTML margin problem).
2261 - Newline after table was removed.
2262
22634.1.002 (2008-10-21)
2264 - Bug item #2184525 was fixed (rowspan on HTML cell).
2265
22664.1.001 (2008-10-21)
2267 - Support for "start" attribute was added to HTML ordered list.
2268 - unicode_data.php file was changed to include UTF-8 to ASCII table.
2269 - Some functions were modified to better support UTF-8 extensions to core fonts.
2270 - Support for images on HTML lists was improved.
2271 - Examples n. 1 and 6 were updated.
2272
22734.1.000 (2008-10-18)
2274 - Page-break bug using HTML content was fixed.
2275 - The "false" parameter was reintroduced to class_exists function on PHP5 version to avoid autoload.
2276 - addHtmlLink() function was improved to support internal links (i.e.: <a href="#23">link to page 23</a>).
2277 - Justification alignment is now supported on HTML (see example n. 39).
2278 - example_006.php was updated.
2279
22804.0.033 (2008-10-13)
2281 - Bug n. 2157099 was fixed.
2282 - SetX() and SetY() functions were improved.
2283 - SetY() includes a new parameter to avoid the X reset.
2284
22854.0.032 (2008-10-10)
2286 - Bug n. 2156926 was fixed (bold, italic, underlined, linethrough).
2287 - setStyle() method was removed.
2288 - Configuration file was changed to use helvetica (non-unicode) font by default.
2289 - The use of mixed font types was improved.
2290 - All examples were updated.
2291
22924.0.031 (2008-10-09)
2293 - _putannots() and _putbookmarks() links alignments were fixed.
2294
22954.0.030 (2008-10-07)
2296 - _putbookmarks() function was fixed.
2297 - _putannots() was fixed to include internal links.
2298
22994.0.029 (2008-09-27)
2300 - Infinite loop bug was fixed [Bug item #130309].
2301 - Multicell() problem on Header() was fixed.
2302
23034.0.028 (2008-09-26)
2304 - setLIsymbol() was added to set the LI symbol used on UL lists.
2305 - Missing $padding and $encryption_key variables declarations were added [Bug item #2129058].
2306
23074.0.027 (2008-09-19)
2308 - Bug #2118588 "Undefined offset in tcpdf.php on line 9581" was fixed.
2309 - arailunicid0.php font was updated.
2310 - The problem of javascript form fields duplication after saving was fixed.
2311
23124.0.026 (2008-09-17)
2313 - convertHTMLColorToDec() function was improved to support rgb(RR,GG,BB) notation.
2314 - The following inline CSS attributes are now supported: text-decoration, color, background-color and font-size names: xx-small, x-small, small, medium, large, x-large, xx-large
2315 - Example n. 6 was updated.
2316
23174.0.025 (2008-09-15)
2318 - _putcidfont0 function was improved to include CJK fonts (Chinese, Japanese, Korean, CJK, Asian fonts) without embedding.
2319 - arialunicid0 font was added (see the new example n. 38).
2320 - The following Unicode to CID-0 tables were added on fonts folder: uni2cid_ak12.php, uni2cid_aj16.php, uni2cid_ag15.php, uni2cid_ac15.php.
2321
23224.0.024 (2008-09-12)
2323 - "stripos" function was replaced with "strpos + strtolower" for backward compatibility with PHP4.
2324 - support for Spot Colors were added. Check the new example n. 37 and the following new functions:
2325 AddSpotColor()
2326 SetDrawSpotColor()
2327 SetFillSpotColor()
2328 SetTextSpotColor()
2329 _putspotcolors()
2330 - Bookmark() function was improved to fix wrong levels.
2331 - $lasth changes after header/footer calls were fixed.
2332
23334.0.023 (2008-09-05)
2334 - Some HTML related problems were fixed.
2335 - Image alignment on HTML was changed, now it always defaults to the normal mode (see example_006.php).
2336
23374.0.022 (2008-08-28)
2338 - Line height on HTML was fixed.
2339 - Image inside an HTML cell problem was fixed.
2340 - A new "zarbold" persian font was added.
2341
23424.0.021 (2008-08-24)
2343 - HTTP headers were fixed on Output function().
2344 - getAliasNbPages() and getPageGroupAlias() functions were changed to support non-unicode fonts on unicode documents.
2345 - Function Write() was fixed.
2346 - The problem of additional vertical spaces on HTML was fixed.
2347 - The problem of frame around HTML links was fixed.
2348
23494.0.020 (2008-08-15)
2350 - "[2052259] WriteHTML <u> & <b>" bug was fixed.
2351
23524.0.019 (2008-08-13)
2353 - "Rowspan on first cell" bug was fixed.
2354
23554.0.018 (2008-08-08)
2356 - Default cellpadding for HTML tables was fixed.
2357 - Annotation() function was added to support some PDF annotations (see example_036.php and section 8.4 of PDF reference 1.7).
2358 - HTML links are now correclty shifted during line alignments.
2359 - function getAliasNbPages() was added and Footer() was updated.
2360 - RowSpan mode for HTML tables was fixed.
2361 - Bugs item #2043610 "Multiple sizes vertical align wrong" was fixed.
2362 - ImageEPS() function was improved and RTL alignment was fixed (see example_032.php).
2363
23644.0.017 (2008-08-05)
2365 - Missing CNZ and CEO style modes were added to Rect() function.
2366 - Fonts utils were updated to include support for OpenType fonts.
2367 - getLastH() function was added.
2368
23694.0.016 (2008-07-30)
2370 - setPageMark() function was added. This function must be called after calling Image() function for a background image.
2371
23724.0.015 (2008-07-29)
2373 - Some functions were changed to support different page formats (see example_028.php).
2374 - The signature of setPage() function is changed.
2375
23764.0.014 (2008-07-29)
2377 - K_PATH_MAIN calculation on tcpdf_config.php was fixed.
2378 - HTML support for EPS/AI images was added (see example_006.php).
2379 - Bugs item #2030807 "Truncated text on multipage html fields" was fixed.
2380 - PDF header bug was fixed.
2381 - helvetica was added as default font family.
2382 - Stroke mode was fixed on Text function.
2383 - several minor bugs were fixed.
2384
23854.0.013 (2008-07-27)
2386 - Bugs item #2027799 " Big spaces between lines after page break" was fixed.
2387 - K_PATH_MAIN calculation on tcpdf_config.php was changed.
2388 - Function setVisibility() was fixed to avoid the "Incorrect PDEObject type" error message.
2389
23904.0.012 (2008-07-24)
2391 - Addpage(), Header() and Footer() functions were changed to simplify the implementation of external header/footer functions.
2392 - The following functions were added:
2393 setHeader()
2394 setFooter()
2395 getImageRBX()
2396 getImageRBY()
2397 getCellHeightRatio()
2398 getHeaderFont()
2399 getFooterFont()
2400 getRTL()
2401 getBarcode()
2402 getHeaderData()
2403 getHeaderMargin()
2404 getFooterMargin()
2405
24064.0.011 (2008-07-23)
2407 - Font support was improved.
2408 - The folder /fonts/utils contains new utilities and instructions for embedd font files.
2409 - Documentation was updated.
2410
24114.0.010 (2008-07-22)
2412 - HTML tables were fixed to work across pages.
2413 - Header() and Footer() functions were updated to preserve previous settings.
2414 - example_035.php was added.
2415
24164.0.009 (2008-07-21)
2417 - UTF8StringToArray() function was fixed for non-unicode mode.
2418
24194.0.008 (2008-07-21)
2420 - Barcodes alignment was fixed (see example_027.php).
2421 - unicode_data.php was updated.
2422 - Arabic shaping for "Zero-Width Non-Joiner" character (U+200C) was fixed.
2423
24244.0.007 (2008-07-18)
2425 - str_split was replaced by preg_split for compatibility with PHP4 version.
2426 - Clipping mode was added to all graphic functions by using parameter $style = "CNZ" or "CEO" (see example_034.php).
2427
24284.0.006 (2008-07-16)
2429 - HTML rowspan bug was fixed.
2430 - Line style for MultiCell() was fixed.
2431 - WriteHTML() function was improved.
2432 - CODE128C barcode was fixed (barcodes.php).
2433
24344.0.005 (2008-07-11)
2435 - Bug [2015715] "PHP Error/Warning" was fixed.
2436
24374.0.004 (2008-07-09)
2438 - HTML cell internal padding was fixed.
2439
24404.0.003 (2008-07-08)
2441 - Removed URL encoding when F option is selected on Output() function.
2442 - fixed some minor bugs in html tables.
2443
24444.0.002 (2008-07-07)
2445 - Bug [2000861] was still unfixed and has been fixed.
2446
24474.0.001 (2008-07-05)
2448 - Bug [2000861] was fixed.
2449
24504.0.000 (2008-07-03)
2451 - THIS IS A MAIN RELEASE THAT INCLUDES SEVERAL NEW FEATURES AND BUGFIXES
2452 - Signature fo SetTextColor() and SetFillColor() functions was changed (parameter $storeprev was removed).
2453 - HTML support was completely rewritten and improved (see example 6).
2454 - Alignments parameters were fixed.
2455 - Functions GetArrStringWidth() and GetStringWidth() now include font parameters.
2456 - Fonts support was improved.
2457 - All core fonts were replaced and moved to fonts/ directory.
2458 - The following functions were added: getMargins(), getFontSize(), getFontSizePt().
2459 - File config/tcpdf_config_old.php was renamed tcpdf_config_alt.php and updated.
2460 - Multicell and WriteHTMLCell fill function was fixed.
2461 - Several minor bugs were fixed.
2462 - barcodes.php was updated.
2463 - All examples were updated.
2464
2465------------------------------------------------------------
2466
24673.1.001 (2008-06-13)
2468 - Bug [1992515] "K_PATH_FONTS default value wrong" was fixed.
2469 - Vera font was removed, DejaVu font and Free fonts were updated.
2470 - Image handling was improved.
2471 - All examples were updated.
2472
24733.1.000 (2008-06-11)
2474 - setPDFVersion() was added to change the default PDF version (currently 1.7).
2475 - setViewerPreferences() was added to control the way the document is to be presented on the screen or printed (see example 29).
2476 - SetDisplayMode() signature was changed (new options were added).
2477 - LinearGradient(), RadialGradient(), CoonsPatchMesh() functions were added to print various color gradients (see example 30).
2478 - PieSector() function was added to render render pie charts (see example 31).
2479 - ImageEps() was added to display EPS and AI images with limited support (see example 32).
2480 - writeBarcode() function is now depracated, a new write1DBarcode() function was added. The barcode directory was removed and a new barcodes.php file was added.
2481 - The new write1DBarcode() function support more barcodes and do not need the GD library (see example 027). All barcodes are directly written to PDF using graphic functions.
2482 - HTML lists were improved and could be nested (you may now represent trees).
2483 - AddFont() bug was fixed.
2484 - _putfonts() bug was fixed.
2485 - graphics functions were fixed.
2486 - unicode_data.php file was updated (fixed).
2487 - almohanad font was updated.
2488 - example 18 was updated (Farsi and Arabic languages).
2489 - source code cleanup.
2490 - All examples were updated and new examples were added.
2491
24923.0.015 (2008-06-06)
2493 - AddPage() function signature is changed to include page format.
2494 - example 28 was added to show page format changes.
2495 - setPageUnit() function was added to change the page units of measure.
2496 - setPageFormat() function was added to change the page format and orientation between pages.
2497 - setPageOrientation() function was added to change the page orientation.
2498 - Arabic font shaping was fixed for laa letter and square boxes (see the example 18).
2499
25003.0.014 (2008-06-04)
2501 - Arabic font shaping was fixed.
2502 - setDefaultTableColumns() function was added.
2503 - $cell_height_ratio variable was added.
2504 - setCellHeightRatio() function was added to define the default height of cell repect font height.
2505
25063.0.013 (2008-06-03)
2507 - Multicell height parameter was fixed.
2508 - Arabic font shaping was improved.
2509 - unicode_data.php was updated.
2510
25113.0.012 (2008-05-30)
2512 - K_PATH_MAIN and K_PATH_URL constants are now automatically set on config file.
2513 - DOCUMENT_ROOT constant was fixed for IIS Webserver (config file was updated).
2514 - Arabic font shaping was improved.
2515 - TranslateY() function was fixed (bug [1977962]).
2516 - setVisibility() function was fixed.
2517 - writeBarcode() function was fixed to scale using $xref parameter.
2518 - All examples were updated.
2519
25203.0.011 (2008-05-23)
2521 - CMYK color support was added to all graphic functions.
2522 - HTML table support was improved:
2523 -- now it's possible to include additional html tags inside a cell;
2524 -- colspan attribute was added.
2525 - example 006 was updated.
2526
25273.0.010 (2008-05-21)
2528 - fixed $laa_array inclusion on utf8Bidi() function.
2529
25303.0.009 (2008-05-20)
2531 - unicode_data.php was updated.
2532 - Arabic laa letter problem was fixed.
2533
25343.0.008 (2008-05-12)
2535 - Arabic support was fixed and improved (unicode_data.php was updated).
2536 - Polycurve() function was added to draw a poly-Bezier curve.
2537 - list items alignment was fixed.
2538 - example 6 was updated.
2539
25403.0.007 (2008-05-06)
2541 - Arabic support was fixed and improved.
2542 - AlMohanad (arabic) font was added.
2543 - C128 barcode bugs were fixed.
2544
25453.0.006 (2008-04-21)
2546 - Condition to check negative width values was added.
2547
25483.0.005 (2008-04-18)
2549 - back-Slash character escape was fixed on writeHTML() function.
2550 - Exampe 6 was updated.
2551
25523.0.004 (2008-04-11)
2553 - Bug [1939304] (Right to Left Issue) was fixed.
2554
25553.0.003 (2008-04-07)
2556 - Bug [1934523](Words between HTML tags in cell not kept on one line) was fixed.
2557 - "face" attribute of "font" tag is now fully supported.
2558
25593.0.002 (2008-04-01)
2560 - Write() functions now return the number of cells and not the number of lines.
2561 - TCPDF is released under LGPL 2.1, or any later version.
2562
25633.0.001 (2008-05-28)
2564 - _legacyparsejpeg() and _legacyparsepng() were renamed _parsejpeg() and _parsepng().
2565 - function writeBarcode() was fixed.
2566 - all examples were updated.
2567 - example 27 was added to show various barcodes.
2568
25693.0.000 (2008-03-27)
2570 - private function pixelsToMillimeters() was changed to public function pixelsToUnits() to fix html image size bug.
2571 - Image-related functions were rewritten.
2572 - resize parameter was added to Image() signature to reduce the image size and fit width and height (see example 9).
2573 - TCPDF now supports all images supported by GD library: GD, GD2, GD2PART, GIF, JPEG, PNG, BMP, XBM, XPM.
2574 - CMYK support was added to SetDrawColor(), SetFillColor(), SetTextColor() (see example 22).
2575 - Page Groups were added (see example 23).
2576 - setVisibility() function was added to restrict the rendering of some elements to screen or printout (see example 24).
2577 - All private variables and functions were changed to protected.
2578 - setAlpha() function was added to give transparency support for all objects (see example 25).
2579 - Clipping and stroke modes were added to Text() function (see example 26).
2580 - All examples were moved to "examples" directory.
2581 - function setJPEGQuality() was added to set the JPEG image comrpession (see example 9).
2582
25832.9.000 (2008-03-26)
2584 - htmlcolors.php file was added to include html colors.
2585 - Support for HTML color names and three-digit hexadecimal color codes was added.
2586 - private function convertColorHexToDec() was renamed convertHTMLColorToDec().
2587 - color and bgcolor attributes are now supported on all HTML tags (color nesting is also supported).
2588 - Write() function were fixed.
2589 - example_006.php was updated.
2590 - private function setUserRights() was added to release user rights on Acrobat Reader (this allows to display forms, see example 14)
2591
25922.8.000 (2008-03-20)
2593 - Private variables were changed to protected.
2594 - Function Write() was fixed and improved.
2595 - Support for dl, dt, dd, del HTML tags was introduced.
2596 - Line-trought mode was added for HTML and text.
2597 - Text vertical alignment on cells were fixed.
2598 - Examples were updated to reflect changes.
2599
26002.7.002 (2008-03-13)
2601 - Bug "[1912142] Encrypted PDF created/modified date" was fixed.
2602
26032.7.001 (2008-03-10)
2604 - Cell justification was fixed for non-unicode mode.
2605
26062.7.000 (2008-03-09)
2607 - Cell() stretching mode 4 (forced character spacing) was fixed.
2608 - writeHTMLCell() now uses Multicell() to write.
2609 - Multicell() has a new parameter $ishtml to act as writeHTMLCell().
2610 - Write() speed was improved for non-arabic strings.
2611 - Example n. 20 was changed.
2612
26132.6.000 (2008-03-07)
2614 - various alignments bugs were fixed.
2615
26162.5.000 (2008-03-07)
2617 - Several bugs were fixed.
2618 - example_019.php was added to test non-unicode mode using old fonts.
2619
26202.4.000 (2008-03-06)
2621 - RTL support was deeply improved.
2622 - GetStringWidth() was fixed to support RTL languages.
2623 - Text() RTL alignment was fixed.
2624 - Some functions were added: GetArrStringWidth(), GetCharWidth(), uniord(), utf8Bidi().
2625 - example_018.php was added and test_unicode.php was removed.
2626
26272.3.000 (2008-03-05)
2628 - MultiCell() signature is changed. Now support multiple columns across pages (see example_017).
2629 - Write() signature is changed. Now support the cell mode to be used with MultiCell.
2630 - Header() and Footer() were changed.
2631 - The following functions were added: UTF8ArrSubString() and unichr().
2632 - Examples were updated to reflect last changes.
2633
26342.2.004 (2008-03-04)
2635 - Several examples were added.
2636 - AddPage() Header() and Footer() were fixed.
2637 - Documentation is now available on http://www.tcpdf.org
2638
26392.2.003 (2008-03-03)
2640 - [1894853] Performance of MultiCell() was improved.
2641 - RadioButton and ListBox functions were added.
2642 - javascript form functions were rewritten and properties names are changed. The properties function supported by form fields are listed on Possible values are listed on http://www.adobe.com/devnet/acrobat/pdfs/js_developer_guide.pdf.
2643
26442.2.002 (2008-02-28)
2645 - [1900495] html images path was fixed.
2646 - Legacy image functions were reintroduced to allow PNG and JPEG support without GD library.
2647
26482.2.001 (2008-02-16)
2649 - The bug "[1894700] bug with replace relative path" was fixed
2650 - Justification was fixed
2651
26522.2.000 (2008-02-12)
2653 - fixed javascript bug introduced with latest release
2654
26552.1.002 (2008-02-12)
2656 - Justify function was fixed on PHP4 version.
2657 - Bookmank function was added ([1578250] Table of contents).
2658 - Javascript and Form fields support was added ([1796359] Form fields).
2659
26602.1.001 (2008-02-10)
2661 - The bug "[1885776] Race Condition in function justitfy" was fixed.
2662 - The bug "[1890217] xpdf complains that pdf is incorrect" was fixed.
2663
26642.1.000 (2008-01-07)
2665 - FPDF_FONTPATH constant was changed to K_PATH_FONTS on config file
2666 - Bidirectional Algorithm to correctly reverse bidirectional languages was added.
2667 - SetLeftMargin, SetTopMargin, SetRightMargin functions were fixed.
2668 - SetCellPadding function was added.
2669 - writeHTML was updated with new parameters.
2670 - Text function was fixed.
2671 - MultiCell function was fixed, now works also across multiple pages.
2672 - Line width was fixed on Header and Footer functions and <hr> tag.
2673 - "GetImageSize" was renamed "getimagesize".
2674 - Document version was changed from 1.3 to 1.5.
2675 - _begindoc() function was fixed.
2676 - ChangeDate was fixed and ModDate was added.
2677 - The following functions were added:
2678 setPage() : Move pointer to the specified document page.
2679 getPage() : Get current document page number.
2680 lastpage() : Reset pointer to the last document page.
2681 getNumPages() : Get the total number of inserted pages.
2682 GetNumChars() : count the number of (UTF-8) characters in a string.
2683 - $stretch parameter was added to Cell() function to fit text on cell:
2684 0 = disabled
2685 1 = horizontal scaling only if necessary
2686 2 = forced horizontal scaling
2687 3 = character spacing only if necessary
2688 4 = forced character spacing
2689 - Line function was fixed for RTL.
2690 - Graphic transformation functions were added [1811158]:
2691 StartTransform()
2692 StopTransform()
2693 ScaleX()
2694 ScaleY()
2695 ScaleXY()
2696 Scale()
2697 MirrorH()
2698 MirrorV()
2699 MirrorP()
2700 MirrorL()
2701 TranslateX()
2702 TranslateY()
2703 Translate()
2704 Rotate()
2705 SkewX()
2706 SkewY()
2707 Skew()
2708 - Graphic function were added/updated [1688549]:
2709 SetLineStyle()
2710 _outPoint()
2711 _outLine()
2712 _outRect()
2713 _outCurve()
2714 Line()
2715 Rect()
2716 Curve
2717 Ellipse
2718 Circle
2719 Polygon
2720 RegularPolygon
2721
27222.0.000 (2008-01-04)
2723 - RTL (Right-To-Left) languages support was added. Language direction is set using the $l['a_meta_dir'] setting on /configure/language/xxx.php language files.
2724 - setRTL($enable) method was added to manually enable/disable the RTL text direction.
2725 - The attribute "dir" was added to support custom text direction on HTML tags. Possible values are: ltr - for Left-To-Right and RTL for Right-To-Left.
2726 - RC4 40bit encryption was added. Check the SetProtection method.
2727 - [1815213] Improved image support for GIF, JPEG, PNG formats.
2728 - [1800094] Attribute "value" was added to ordered list items <li>.
2729 - Image function now has a new "align" parameter that indicates the alignment of the pointer next to image insertion and relative to image height. The value can be:
2730 T: top-right for LTR or top-left for RTL
2731 M: middle-right for LTR or middle-left for RTL
2732 B: bottom-right for LTR or bottom-left for RTL
2733 N: next line
2734 - Attribute "align" was added to <img> html tag to set the above image "align" parameter. Possible values are:
2735 top: top-right for LTR or top-left for RTL
2736 middle: middle-right for LTR or middle-left for RTL
2737 bottom: bottom-right for LTR or bottom-left for RTL
2738 - [1798103] newline was added after </ul>, </ol> and </p> tages.
2739 - [1816393] Documentation was updated.
2740 - 'ln' parameter was fixed on writeHTMLCell. Now it's possible to print two or more columns across several pages;
2741 - The method lastPage() was added to move the pointer on the last page;
2742
2743------------------------------------------------------------
2744
27451.53.0.TC034 (2007-07-30)
2746 - fixed htmlentities conversion.
2747 - MultiCell() function returns the number of cells.
2748
27491.53.0.TC033 (2007-07-30)
2750 - fixed bug 1762550: case sensitive for font files
2751 - NOTE: all fonts files names must be in lowercase!
2752
27531.53.0.TC032 (2007-07-27)
2754 - setLastH method was added to resolve bug 1689071.
2755 - all fonts names were converted in lowercase (bug 1713005).
2756 - bug 1740954 was fixed.
2757 - justification was added as Cell option.
2758
27591.53.0.TC031 (2007-03-20)
2760 - ToUnicode CMap were added on _puttruetypeunicode function. Now you may search and copy unicode text.
2761
27621.53.0.TC030 (2007-03-06)
2763 - fixed bug on PHP4 version.
2764
27651.53.0.TC029 (2007-03-06)
2766 - DejaVu Fonts were added.
2767
27681.53.0.TC028 (2007-03-03)
2769 - MultiCell function signature were changed: the $ln parameter were added. Check documentation for further information.
2770 - Greek language were added on example sentences.
2771 - setPrintHeader() and setPrintFooter() functions were added to enable or disable page header and footer.
2772
27731.53.0.TC027 (2006-12-14)
2774 - $attr['face'] bug were fixed.
2775 - K_TCPDF_EXTERNAL_CONFIG control where introduced on /config/tcpdf_config.php to use external configuration files.
2776
27771.53.0.TC026 (2006-10-28)
2778 - writeHTML function call were fixed on examples.
2779
27801.53.0.TC025 (2006-10-27)
2781 - Bugs item #1421290 were fixed (0D - 0A substitution in some characters)
2782 - Bugs item #1573174 were fixed (MultiCell documentation)
2783
27841.53.0.TC024 (2006-09-26)
2785 - getPageHeight() function were fixed (bug 1543476).
2786 - fixed missing breaks on closedHTMLTagHandler function (bug 1535263).
2787 - fixed extra spaces on Write function (bug 1535262).
2788
27891.53.0.TC023 (2006-08-04)
2790 - paths to barcode directory were fixed.
2791 - documentation were updated.
2792
27931.53.0.TC022 (2006-07-16)
2794 - fixed bug: [ 1516858 ] Probs with PHP autoloader and class_exists()
2795
27961.53.0.TC021 (2006-07-01)
2797 - HTML attributes with whitespaces are now supported (thanks to Nelson Benitez for his support)
2798
27991.53.0.TC020 (2006-06-23)
2800 - code cleanup
2801
28021.53.0.TC019 (2006-05-21)
2803 - fixed <strong> and <em> closing tags
2804
28051.53.0.TC018 (2006-05-18)
2806 - fixed font names bug
2807
28081.53.0.TC017 (2006-05-18)
2809 - the TTF2UFM utility to convert True Type fonts for TCPDF were included on fonts folder.
2810 - new free unicode fonts were included on /fonts/freefont.
2811 - test_unicode.php example were exended.
2812 - parameter $fill were added on Write, writeHTML and writeHTMLCell functions.
2813 - documentation were updated.
2814
28151.53.0.TC016 (2006-03-09)
2816 - fixed closing <strong> tag on html parser.
2817
28181.53.0.TC016 (2005-08-28)
2819 - fpdf.php and tcpdf.php files were joined in one single class (you can still extend TCPDF with your own class).
2820 - fixed problem when mb_internal_encoding is set.
2821
28221.53.0.TC014 (2005-05-29)
2823 - fixed WriteHTMLCell new page issue.
2824
28251.53.0.TC013 (2005-05-29)
2826 - fixed WriteHTMLCell across pages.
2827
28281.53.0.TC012 (2005-05-29)
2829 - font color attribute bug were fixed.
2830
28311.53.0.TC011 (2005-03-31)
2832 - SetFont function were fixed (thank Sjaak Lauwers for bug notice).
2833
28341.53.0.TC010 (2005-03-22)
2835 - the html functions were improved (thanks to Manfred Vervuert for bug reporting).
2836
28371.53.0.TC009 (2005-03-19)
2838 - a wrong reference to convertColorHexToDec were fixed.
2839
28401.53.0.TC008 (2005-02-07)
2841 - removed some extra bytes from PHP files.
2842
28431.53.0.TC007 (2005-01-08)
2844 - fill attribute were removed from writeHTMLCell method.
2845
28461.53.0.TC006 (2005-01-08)
2847 - the documentation were updated.
2848
28491.53.0.TC005 (2005-01-05)
2850 - Steven Wittens's unicode methods were removed.
2851 - All unicode methods were rewritten from scratch.
2852 - TCPDF is now licensed as LGPL.
2853
28541.53.0.TC004 (2005-01-04)
2855 - this changelog were added.
2856 - removed commercial fonts for licensing issue.
2857 - Bitstream Vera Fonts were added (http://www.bitstream.com/font_rendering/products/dev_fonts/vera.html).
2858 - Now the AddFont and SetFont functions returns the basic font if the styled version do not exist.
2859
2860EOF --------------------------------------------------------
diff --git a/inc/3rdparty/libraries/tcpdf/LICENSE.TXT b/inc/3rdparty/libraries/tcpdf/LICENSE.TXT
new file mode 100644
index 00000000..daf21f7d
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/LICENSE.TXT
@@ -0,0 +1,858 @@
1**********************************************************************
2* TCPDF LICENSE
3**********************************************************************
4
5 TCPDF is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation, either version 3 of the
8 License, or (at your option) any later version.
9
10**********************************************************************
11**********************************************************************
12
13 GNU LESSER GENERAL PUBLIC LICENSE
14 Version 3, 29 June 2007
15
16 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
17 Everyone is permitted to copy and distribute verbatim copies
18 of this license document, but changing it is not allowed.
19
20
21 This version of the GNU Lesser General Public License incorporates
22the terms and conditions of version 3 of the GNU General Public
23License, supplemented by the additional permissions listed below.
24
25 0. Additional Definitions.
26
27 As used herein, "this License" refers to version 3 of the GNU Lesser
28General Public License, and the "GNU GPL" refers to version 3 of the GNU
29General Public License.
30
31 "The Library" refers to a covered work governed by this License,
32other than an Application or a Combined Work as defined below.
33
34 An "Application" is any work that makes use of an interface provided
35by the Library, but which is not otherwise based on the Library.
36Defining a subclass of a class defined by the Library is deemed a mode
37of using an interface provided by the Library.
38
39 A "Combined Work" is a work produced by combining or linking an
40Application with the Library. The particular version of the Library
41with which the Combined Work was made is also called the "Linked
42Version".
43
44 The "Minimal Corresponding Source" for a Combined Work means the
45Corresponding Source for the Combined Work, excluding any source code
46for portions of the Combined Work that, considered in isolation, are
47based on the Application, and not on the Linked Version.
48
49 The "Corresponding Application Code" for a Combined Work means the
50object code and/or source code for the Application, including any data
51and utility programs needed for reproducing the Combined Work from the
52Application, but excluding the System Libraries of the Combined Work.
53
54 1. Exception to Section 3 of the GNU GPL.
55
56 You may convey a covered work under sections 3 and 4 of this License
57without being bound by section 3 of the GNU GPL.
58
59 2. Conveying Modified Versions.
60
61 If you modify a copy of the Library, and, in your modifications, a
62facility refers to a function or data to be supplied by an Application
63that uses the facility (other than as an argument passed when the
64facility is invoked), then you may convey a copy of the modified
65version:
66
67 a) under this License, provided that you make a good faith effort to
68 ensure that, in the event an Application does not supply the
69 function or data, the facility still operates, and performs
70 whatever part of its purpose remains meaningful, or
71
72 b) under the GNU GPL, with none of the additional permissions of
73 this License applicable to that copy.
74
75 3. Object Code Incorporating Material from Library Header Files.
76
77 The object code form of an Application may incorporate material from
78a header file that is part of the Library. You may convey such object
79code under terms of your choice, provided that, if the incorporated
80material is not limited to numerical parameters, data structure
81layouts and accessors, or small macros, inline functions and templates
82(ten or fewer lines in length), you do both of the following:
83
84 a) Give prominent notice with each copy of the object code that the
85 Library is used in it and that the Library and its use are
86 covered by this License.
87
88 b) Accompany the object code with a copy of the GNU GPL and this license
89 document.
90
91 4. Combined Works.
92
93 You may convey a Combined Work under terms of your choice that,
94taken together, effectively do not restrict modification of the
95portions of the Library contained in the Combined Work and reverse
96engineering for debugging such modifications, if you also do each of
97the following:
98
99 a) Give prominent notice with each copy of the Combined Work that
100 the Library is used in it and that the Library and its use are
101 covered by this License.
102
103 b) Accompany the Combined Work with a copy of the GNU GPL and this license
104 document.
105
106 c) For a Combined Work that displays copyright notices during
107 execution, include the copyright notice for the Library among
108 these notices, as well as a reference directing the user to the
109 copies of the GNU GPL and this license document.
110
111 d) Do one of the following:
112
113 0) Convey the Minimal Corresponding Source under the terms of this
114 License, and the Corresponding Application Code in a form
115 suitable for, and under terms that permit, the user to
116 recombine or relink the Application with a modified version of
117 the Linked Version to produce a modified Combined Work, in the
118 manner specified by section 6 of the GNU GPL for conveying
119 Corresponding Source.
120
121 1) Use a suitable shared library mechanism for linking with the
122 Library. A suitable mechanism is one that (a) uses at run time
123 a copy of the Library already present on the user's computer
124 system, and (b) will operate properly with a modified version
125 of the Library that is interface-compatible with the Linked
126 Version.
127
128 e) Provide Installation Information, but only if you would otherwise
129 be required to provide such information under section 6 of the
130 GNU GPL, and only to the extent that such information is
131 necessary to install and execute a modified version of the
132 Combined Work produced by recombining or relinking the
133 Application with a modified version of the Linked Version. (If
134 you use option 4d0, the Installation Information must accompany
135 the Minimal Corresponding Source and Corresponding Application
136 Code. If you use option 4d1, you must provide the Installation
137 Information in the manner specified by section 6 of the GNU GPL
138 for conveying Corresponding Source.)
139
140 5. Combined Libraries.
141
142 You may place library facilities that are a work based on the
143Library side by side in a single library together with other library
144facilities that are not Applications and are not covered by this
145License, and convey such a combined library under terms of your
146choice, if you do both of the following:
147
148 a) Accompany the combined library with a copy of the same work based
149 on the Library, uncombined with any other library facilities,
150 conveyed under the terms of this License.
151
152 b) Give prominent notice with the combined library that part of it
153 is a work based on the Library, and explaining where to find the
154 accompanying uncombined form of the same work.
155
156 6. Revised Versions of the GNU Lesser General Public License.
157
158 The Free Software Foundation may publish revised and/or new versions
159of the GNU Lesser General Public License from time to time. Such new
160versions will be similar in spirit to the present version, but may
161differ in detail to address new problems or concerns.
162
163 Each version is given a distinguishing version number. If the
164Library as you received it specifies that a certain numbered version
165of the GNU Lesser General Public License "or any later version"
166applies to it, you have the option of following the terms and
167conditions either of that published version or of any later version
168published by the Free Software Foundation. If the Library as you
169received it does not specify a version number of the GNU Lesser
170General Public License, you may choose any version of the GNU Lesser
171General Public License ever published by the Free Software Foundation.
172
173 If the Library as you received it specifies that a proxy can decide
174whether future versions of the GNU Lesser General Public License shall
175apply, that proxy's public statement of acceptance of any version is
176permanent authorization for you to choose that version for the
177Library.
178
179**********************************************************************
180**********************************************************************
181
182 GNU GENERAL PUBLIC LICENSE
183 Version 3, 29 June 2007
184
185 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
186 Everyone is permitted to copy and distribute verbatim copies
187 of this license document, but changing it is not allowed.
188
189 Preamble
190
191 The GNU General Public License is a free, copyleft license for
192software and other kinds of works.
193
194 The licenses for most software and other practical works are designed
195to take away your freedom to share and change the works. By contrast,
196the GNU General Public License is intended to guarantee your freedom to
197share and change all versions of a program--to make sure it remains free
198software for all its users. We, the Free Software Foundation, use the
199GNU General Public License for most of our software; it applies also to
200any other work released this way by its authors. You can apply it to
201your programs, too.
202
203 When we speak of free software, we are referring to freedom, not
204price. Our General Public Licenses are designed to make sure that you
205have the freedom to distribute copies of free software (and charge for
206them if you wish), that you receive source code or can get it if you
207want it, that you can change the software or use pieces of it in new
208free programs, and that you know you can do these things.
209
210 To protect your rights, we need to prevent others from denying you
211these rights or asking you to surrender the rights. Therefore, you have
212certain responsibilities if you distribute copies of the software, or if
213you modify it: responsibilities to respect the freedom of others.
214
215 For example, if you distribute copies of such a program, whether
216gratis or for a fee, you must pass on to the recipients the same
217freedoms that you received. You must make sure that they, too, receive
218or can get the source code. And you must show them these terms so they
219know their rights.
220
221 Developers that use the GNU GPL protect your rights with two steps:
222(1) assert copyright on the software, and (2) offer you this License
223giving you legal permission to copy, distribute and/or modify it.
224
225 For the developers' and authors' protection, the GPL clearly explains
226that there is no warranty for this free software. For both users' and
227authors' sake, the GPL requires that modified versions be marked as
228changed, so that their problems will not be attributed erroneously to
229authors of previous versions.
230
231 Some devices are designed to deny users access to install or run
232modified versions of the software inside them, although the manufacturer
233can do so. This is fundamentally incompatible with the aim of
234protecting users' freedom to change the software. The systematic
235pattern of such abuse occurs in the area of products for individuals to
236use, which is precisely where it is most unacceptable. Therefore, we
237have designed this version of the GPL to prohibit the practice for those
238products. If such problems arise substantially in other domains, we
239stand ready to extend this provision to those domains in future versions
240of the GPL, as needed to protect the freedom of users.
241
242 Finally, every program is threatened constantly by software patents.
243States should not allow patents to restrict development and use of
244software on general-purpose computers, but in those that do, we wish to
245avoid the special danger that patents applied to a free program could
246make it effectively proprietary. To prevent this, the GPL assures that
247patents cannot be used to render the program non-free.
248
249 The precise terms and conditions for copying, distribution and
250modification follow.
251
252 TERMS AND CONDITIONS
253
254 0. Definitions.
255
256 "This License" refers to version 3 of the GNU General Public License.
257
258 "Copyright" also means copyright-like laws that apply to other kinds of
259works, such as semiconductor masks.
260
261 "The Program" refers to any copyrightable work licensed under this
262License. Each licensee is addressed as "you". "Licensees" and
263"recipients" may be individuals or organizations.
264
265 To "modify" a work means to copy from or adapt all or part of the work
266in a fashion requiring copyright permission, other than the making of an
267exact copy. The resulting work is called a "modified version" of the
268earlier work or a work "based on" the earlier work.
269
270 A "covered work" means either the unmodified Program or a work based
271on the Program.
272
273 To "propagate" a work means to do anything with it that, without
274permission, would make you directly or secondarily liable for
275infringement under applicable copyright law, except executing it on a
276computer or modifying a private copy. Propagation includes copying,
277distribution (with or without modification), making available to the
278public, and in some countries other activities as well.
279
280 To "convey" a work means any kind of propagation that enables other
281parties to make or receive copies. Mere interaction with a user through
282a computer network, with no transfer of a copy, is not conveying.
283
284 An interactive user interface displays "Appropriate Legal Notices"
285to the extent that it includes a convenient and prominently visible
286feature that (1) displays an appropriate copyright notice, and (2)
287tells the user that there is no warranty for the work (except to the
288extent that warranties are provided), that licensees may convey the
289work under this License, and how to view a copy of this License. If
290the interface presents a list of user commands or options, such as a
291menu, a prominent item in the list meets this criterion.
292
293 1. Source Code.
294
295 The "source code" for a work means the preferred form of the work
296for making modifications to it. "Object code" means any non-source
297form of a work.
298
299 A "Standard Interface" means an interface that either is an official
300standard defined by a recognized standards body, or, in the case of
301interfaces specified for a particular programming language, one that
302is widely used among developers working in that language.
303
304 The "System Libraries" of an executable work include anything, other
305than the work as a whole, that (a) is included in the normal form of
306packaging a Major Component, but which is not part of that Major
307Component, and (b) serves only to enable use of the work with that
308Major Component, or to implement a Standard Interface for which an
309implementation is available to the public in source code form. A
310"Major Component", in this context, means a major essential component
311(kernel, window system, and so on) of the specific operating system
312(if any) on which the executable work runs, or a compiler used to
313produce the work, or an object code interpreter used to run it.
314
315 The "Corresponding Source" for a work in object code form means all
316the source code needed to generate, install, and (for an executable
317work) run the object code and to modify the work, including scripts to
318control those activities. However, it does not include the work's
319System Libraries, or general-purpose tools or generally available free
320programs which are used unmodified in performing those activities but
321which are not part of the work. For example, Corresponding Source
322includes interface definition files associated with source files for
323the work, and the source code for shared libraries and dynamically
324linked subprograms that the work is specifically designed to require,
325such as by intimate data communication or control flow between those
326subprograms and other parts of the work.
327
328 The Corresponding Source need not include anything that users
329can regenerate automatically from other parts of the Corresponding
330Source.
331
332 The Corresponding Source for a work in source code form is that
333same work.
334
335 2. Basic Permissions.
336
337 All rights granted under this License are granted for the term of
338copyright on the Program, and are irrevocable provided the stated
339conditions are met. This License explicitly affirms your unlimited
340permission to run the unmodified Program. The output from running a
341covered work is covered by this License only if the output, given its
342content, constitutes a covered work. This License acknowledges your
343rights of fair use or other equivalent, as provided by copyright law.
344
345 You may make, run and propagate covered works that you do not
346convey, without conditions so long as your license otherwise remains
347in force. You may convey covered works to others for the sole purpose
348of having them make modifications exclusively for you, or provide you
349with facilities for running those works, provided that you comply with
350the terms of this License in conveying all material for which you do
351not control copyright. Those thus making or running the covered works
352for you must do so exclusively on your behalf, under your direction
353and control, on terms that prohibit them from making any copies of
354your copyrighted material outside their relationship with you.
355
356 Conveying under any other circumstances is permitted solely under
357the conditions stated below. Sublicensing is not allowed; section 10
358makes it unnecessary.
359
360 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
361
362 No covered work shall be deemed part of an effective technological
363measure under any applicable law fulfilling obligations under article
36411 of the WIPO copyright treaty adopted on 20 December 1996, or
365similar laws prohibiting or restricting circumvention of such
366measures.
367
368 When you convey a covered work, you waive any legal power to forbid
369circumvention of technological measures to the extent such circumvention
370is effected by exercising rights under this License with respect to
371the covered work, and you disclaim any intention to limit operation or
372modification of the work as a means of enforcing, against the work's
373users, your or third parties' legal rights to forbid circumvention of
374technological measures.
375
376 4. Conveying Verbatim Copies.
377
378 You may convey verbatim copies of the Program's source code as you
379receive it, in any medium, provided that you conspicuously and
380appropriately publish on each copy an appropriate copyright notice;
381keep intact all notices stating that this License and any
382non-permissive terms added in accord with section 7 apply to the code;
383keep intact all notices of the absence of any warranty; and give all
384recipients a copy of this License along with the Program.
385
386 You may charge any price or no price for each copy that you convey,
387and you may offer support or warranty protection for a fee.
388
389 5. Conveying Modified Source Versions.
390
391 You may convey a work based on the Program, or the modifications to
392produce it from the Program, in the form of source code under the
393terms of section 4, provided that you also meet all of these conditions:
394
395 a) The work must carry prominent notices stating that you modified
396 it, and giving a relevant date.
397
398 b) The work must carry prominent notices stating that it is
399 released under this License and any conditions added under section
400 7. This requirement modifies the requirement in section 4 to
401 "keep intact all notices".
402
403 c) You must license the entire work, as a whole, under this
404 License to anyone who comes into possession of a copy. This
405 License will therefore apply, along with any applicable section 7
406 additional terms, to the whole of the work, and all its parts,
407 regardless of how they are packaged. This License gives no
408 permission to license the work in any other way, but it does not
409 invalidate such permission if you have separately received it.
410
411 d) If the work has interactive user interfaces, each must display
412 Appropriate Legal Notices; however, if the Program has interactive
413 interfaces that do not display Appropriate Legal Notices, your
414 work need not make them do so.
415
416 A compilation of a covered work with other separate and independent
417works, which are not by their nature extensions of the covered work,
418and which are not combined with it such as to form a larger program,
419in or on a volume of a storage or distribution medium, is called an
420"aggregate" if the compilation and its resulting copyright are not
421used to limit the access or legal rights of the compilation's users
422beyond what the individual works permit. Inclusion of a covered work
423in an aggregate does not cause this License to apply to the other
424parts of the aggregate.
425
426 6. Conveying Non-Source Forms.
427
428 You may convey a covered work in object code form under the terms
429of sections 4 and 5, provided that you also convey the
430machine-readable Corresponding Source under the terms of this License,
431in one of these ways:
432
433 a) Convey the object code in, or embodied in, a physical product
434 (including a physical distribution medium), accompanied by the
435 Corresponding Source fixed on a durable physical medium
436 customarily used for software interchange.
437
438 b) Convey the object code in, or embodied in, a physical product
439 (including a physical distribution medium), accompanied by a
440 written offer, valid for at least three years and valid for as
441 long as you offer spare parts or customer support for that product
442 model, to give anyone who possesses the object code either (1) a
443 copy of the Corresponding Source for all the software in the
444 product that is covered by this License, on a durable physical
445 medium customarily used for software interchange, for a price no
446 more than your reasonable cost of physically performing this
447 conveying of source, or (2) access to copy the
448 Corresponding Source from a network server at no charge.
449
450 c) Convey individual copies of the object code with a copy of the
451 written offer to provide the Corresponding Source. This
452 alternative is allowed only occasionally and noncommercially, and
453 only if you received the object code with such an offer, in accord
454 with subsection 6b.
455
456 d) Convey the object code by offering access from a designated
457 place (gratis or for a charge), and offer equivalent access to the
458 Corresponding Source in the same way through the same place at no
459 further charge. You need not require recipients to copy the
460 Corresponding Source along with the object code. If the place to
461 copy the object code is a network server, the Corresponding Source
462 may be on a different server (operated by you or a third party)
463 that supports equivalent copying facilities, provided you maintain
464 clear directions next to the object code saying where to find the
465 Corresponding Source. Regardless of what server hosts the
466 Corresponding Source, you remain obligated to ensure that it is
467 available for as long as needed to satisfy these requirements.
468
469 e) Convey the object code using peer-to-peer transmission, provided
470 you inform other peers where the object code and Corresponding
471 Source of the work are being offered to the general public at no
472 charge under subsection 6d.
473
474 A separable portion of the object code, whose source code is excluded
475from the Corresponding Source as a System Library, need not be
476included in conveying the object code work.
477
478 A "User Product" is either (1) a "consumer product", which means any
479tangible personal property which is normally used for personal, family,
480or household purposes, or (2) anything designed or sold for incorporation
481into a dwelling. In determining whether a product is a consumer product,
482doubtful cases shall be resolved in favor of coverage. For a particular
483product received by a particular user, "normally used" refers to a
484typical or common use of that class of product, regardless of the status
485of the particular user or of the way in which the particular user
486actually uses, or expects or is expected to use, the product. A product
487is a consumer product regardless of whether the product has substantial
488commercial, industrial or non-consumer uses, unless such uses represent
489the only significant mode of use of the product.
490
491 "Installation Information" for a User Product means any methods,
492procedures, authorization keys, or other information required to install
493and execute modified versions of a covered work in that User Product from
494a modified version of its Corresponding Source. The information must
495suffice to ensure that the continued functioning of the modified object
496code is in no case prevented or interfered with solely because
497modification has been made.
498
499 If you convey an object code work under this section in, or with, or
500specifically for use in, a User Product, and the conveying occurs as
501part of a transaction in which the right of possession and use of the
502User Product is transferred to the recipient in perpetuity or for a
503fixed term (regardless of how the transaction is characterized), the
504Corresponding Source conveyed under this section must be accompanied
505by the Installation Information. But this requirement does not apply
506if neither you nor any third party retains the ability to install
507modified object code on the User Product (for example, the work has
508been installed in ROM).
509
510 The requirement to provide Installation Information does not include a
511requirement to continue to provide support service, warranty, or updates
512for a work that has been modified or installed by the recipient, or for
513the User Product in which it has been modified or installed. Access to a
514network may be denied when the modification itself materially and
515adversely affects the operation of the network or violates the rules and
516protocols for communication across the network.
517
518 Corresponding Source conveyed, and Installation Information provided,
519in accord with this section must be in a format that is publicly
520documented (and with an implementation available to the public in
521source code form), and must require no special password or key for
522unpacking, reading or copying.
523
524 7. Additional Terms.
525
526 "Additional permissions" are terms that supplement the terms of this
527License by making exceptions from one or more of its conditions.
528Additional permissions that are applicable to the entire Program shall
529be treated as though they were included in this License, to the extent
530that they are valid under applicable law. If additional permissions
531apply only to part of the Program, that part may be used separately
532under those permissions, but the entire Program remains governed by
533this License without regard to the additional permissions.
534
535 When you convey a copy of a covered work, you may at your option
536remove any additional permissions from that copy, or from any part of
537it. (Additional permissions may be written to require their own
538removal in certain cases when you modify the work.) You may place
539additional permissions on material, added by you to a covered work,
540for which you have or can give appropriate copyright permission.
541
542 Notwithstanding any other provision of this License, for material you
543add to a covered work, you may (if authorized by the copyright holders of
544that material) supplement the terms of this License with terms:
545
546 a) Disclaiming warranty or limiting liability differently from the
547 terms of sections 15 and 16 of this License; or
548
549 b) Requiring preservation of specified reasonable legal notices or
550 author attributions in that material or in the Appropriate Legal
551 Notices displayed by works containing it; or
552
553 c) Prohibiting misrepresentation of the origin of that material, or
554 requiring that modified versions of such material be marked in
555 reasonable ways as different from the original version; or
556
557 d) Limiting the use for publicity purposes of names of licensors or
558 authors of the material; or
559
560 e) Declining to grant rights under trademark law for use of some
561 trade names, trademarks, or service marks; or
562
563 f) Requiring indemnification of licensors and authors of that
564 material by anyone who conveys the material (or modified versions of
565 it) with contractual assumptions of liability to the recipient, for
566 any liability that these contractual assumptions directly impose on
567 those licensors and authors.
568
569 All other non-permissive additional terms are considered "further
570restrictions" within the meaning of section 10. If the Program as you
571received it, or any part of it, contains a notice stating that it is
572governed by this License along with a term that is a further
573restriction, you may remove that term. If a license document contains
574a further restriction but permits relicensing or conveying under this
575License, you may add to a covered work material governed by the terms
576of that license document, provided that the further restriction does
577not survive such relicensing or conveying.
578
579 If you add terms to a covered work in accord with this section, you
580must place, in the relevant source files, a statement of the
581additional terms that apply to those files, or a notice indicating
582where to find the applicable terms.
583
584 Additional terms, permissive or non-permissive, may be stated in the
585form of a separately written license, or stated as exceptions;
586the above requirements apply either way.
587
588 8. Termination.
589
590 You may not propagate or modify a covered work except as expressly
591provided under this License. Any attempt otherwise to propagate or
592modify it is void, and will automatically terminate your rights under
593this License (including any patent licenses granted under the third
594paragraph of section 11).
595
596 However, if you cease all violation of this License, then your
597license from a particular copyright holder is reinstated (a)
598provisionally, unless and until the copyright holder explicitly and
599finally terminates your license, and (b) permanently, if the copyright
600holder fails to notify you of the violation by some reasonable means
601prior to 60 days after the cessation.
602
603 Moreover, your license from a particular copyright holder is
604reinstated permanently if the copyright holder notifies you of the
605violation by some reasonable means, this is the first time you have
606received notice of violation of this License (for any work) from that
607copyright holder, and you cure the violation prior to 30 days after
608your receipt of the notice.
609
610 Termination of your rights under this section does not terminate the
611licenses of parties who have received copies or rights from you under
612this License. If your rights have been terminated and not permanently
613reinstated, you do not qualify to receive new licenses for the same
614material under section 10.
615
616 9. Acceptance Not Required for Having Copies.
617
618 You are not required to accept this License in order to receive or
619run a copy of the Program. Ancillary propagation of a covered work
620occurring solely as a consequence of using peer-to-peer transmission
621to receive a copy likewise does not require acceptance. However,
622nothing other than this License grants you permission to propagate or
623modify any covered work. These actions infringe copyright if you do
624not accept this License. Therefore, by modifying or propagating a
625covered work, you indicate your acceptance of this License to do so.
626
627 10. Automatic Licensing of Downstream Recipients.
628
629 Each time you convey a covered work, the recipient automatically
630receives a license from the original licensors, to run, modify and
631propagate that work, subject to this License. You are not responsible
632for enforcing compliance by third parties with this License.
633
634 An "entity transaction" is a transaction transferring control of an
635organization, or substantially all assets of one, or subdividing an
636organization, or merging organizations. If propagation of a covered
637work results from an entity transaction, each party to that
638transaction who receives a copy of the work also receives whatever
639licenses to the work the party's predecessor in interest had or could
640give under the previous paragraph, plus a right to possession of the
641Corresponding Source of the work from the predecessor in interest, if
642the predecessor has it or can get it with reasonable efforts.
643
644 You may not impose any further restrictions on the exercise of the
645rights granted or affirmed under this License. For example, you may
646not impose a license fee, royalty, or other charge for exercise of
647rights granted under this License, and you may not initiate litigation
648(including a cross-claim or counterclaim in a lawsuit) alleging that
649any patent claim is infringed by making, using, selling, offering for
650sale, or importing the Program or any portion of it.
651
652 11. Patents.
653
654 A "contributor" is a copyright holder who authorizes use under this
655License of the Program or a work on which the Program is based. The
656work thus licensed is called the contributor's "contributor version".
657
658 A contributor's "essential patent claims" are all patent claims
659owned or controlled by the contributor, whether already acquired or
660hereafter acquired, that would be infringed by some manner, permitted
661by this License, of making, using, or selling its contributor version,
662but do not include claims that would be infringed only as a
663consequence of further modification of the contributor version. For
664purposes of this definition, "control" includes the right to grant
665patent sublicenses in a manner consistent with the requirements of
666this License.
667
668 Each contributor grants you a non-exclusive, worldwide, royalty-free
669patent license under the contributor's essential patent claims, to
670make, use, sell, offer for sale, import and otherwise run, modify and
671propagate the contents of its contributor version.
672
673 In the following three paragraphs, a "patent license" is any express
674agreement or commitment, however denominated, not to enforce a patent
675(such as an express permission to practice a patent or covenant not to
676sue for patent infringement). To "grant" such a patent license to a
677party means to make such an agreement or commitment not to enforce a
678patent against the party.
679
680 If you convey a covered work, knowingly relying on a patent license,
681and the Corresponding Source of the work is not available for anyone
682to copy, free of charge and under the terms of this License, through a
683publicly available network server or other readily accessible means,
684then you must either (1) cause the Corresponding Source to be so
685available, or (2) arrange to deprive yourself of the benefit of the
686patent license for this particular work, or (3) arrange, in a manner
687consistent with the requirements of this License, to extend the patent
688license to downstream recipients. "Knowingly relying" means you have
689actual knowledge that, but for the patent license, your conveying the
690covered work in a country, or your recipient's use of the covered work
691in a country, would infringe one or more identifiable patents in that
692country that you have reason to believe are valid.
693
694 If, pursuant to or in connection with a single transaction or
695arrangement, you convey, or propagate by procuring conveyance of, a
696covered work, and grant a patent license to some of the parties
697receiving the covered work authorizing them to use, propagate, modify
698or convey a specific copy of the covered work, then the patent license
699you grant is automatically extended to all recipients of the covered
700work and works based on it.
701
702 A patent license is "discriminatory" if it does not include within
703the scope of its coverage, prohibits the exercise of, or is
704conditioned on the non-exercise of one or more of the rights that are
705specifically granted under this License. You may not convey a covered
706work if you are a party to an arrangement with a third party that is
707in the business of distributing software, under which you make payment
708to the third party based on the extent of your activity of conveying
709the work, and under which the third party grants, to any of the
710parties who would receive the covered work from you, a discriminatory
711patent license (a) in connection with copies of the covered work
712conveyed by you (or copies made from those copies), or (b) primarily
713for and in connection with specific products or compilations that
714contain the covered work, unless you entered into that arrangement,
715or that patent license was granted, prior to 28 March 2007.
716
717 Nothing in this License shall be construed as excluding or limiting
718any implied license or other defenses to infringement that may
719otherwise be available to you under applicable patent law.
720
721 12. No Surrender of Others' Freedom.
722
723 If conditions are imposed on you (whether by court order, agreement or
724otherwise) that contradict the conditions of this License, they do not
725excuse you from the conditions of this License. If you cannot convey a
726covered work so as to satisfy simultaneously your obligations under this
727License and any other pertinent obligations, then as a consequence you may
728not convey it at all. For example, if you agree to terms that obligate you
729to collect a royalty for further conveying from those to whom you convey
730the Program, the only way you could satisfy both those terms and this
731License would be to refrain entirely from conveying the Program.
732
733 13. Use with the GNU Affero General Public License.
734
735 Notwithstanding any other provision of this License, you have
736permission to link or combine any covered work with a work licensed
737under version 3 of the GNU Affero General Public License into a single
738combined work, and to convey the resulting work. The terms of this
739License will continue to apply to the part which is the covered work,
740but the special requirements of the GNU Affero General Public License,
741section 13, concerning interaction through a network will apply to the
742combination as such.
743
744 14. Revised Versions of this License.
745
746 The Free Software Foundation may publish revised and/or new versions of
747the GNU General Public License from time to time. Such new versions will
748be similar in spirit to the present version, but may differ in detail to
749address new problems or concerns.
750
751 Each version is given a distinguishing version number. If the
752Program specifies that a certain numbered version of the GNU General
753Public License "or any later version" applies to it, you have the
754option of following the terms and conditions either of that numbered
755version or of any later version published by the Free Software
756Foundation. If the Program does not specify a version number of the
757GNU General Public License, you may choose any version ever published
758by the Free Software Foundation.
759
760 If the Program specifies that a proxy can decide which future
761versions of the GNU General Public License can be used, that proxy's
762public statement of acceptance of a version permanently authorizes you
763to choose that version for the Program.
764
765 Later license versions may give you additional or different
766permissions. However, no additional obligations are imposed on any
767author or copyright holder as a result of your choosing to follow a
768later version.
769
770 15. Disclaimer of Warranty.
771
772 THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
773APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
774HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
775OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
776THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
777PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
778IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
779ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
780
781 16. Limitation of Liability.
782
783 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
784WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
785THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
786GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
787USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
788DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
789PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
790EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
791SUCH DAMAGES.
792
793 17. Interpretation of Sections 15 and 16.
794
795 If the disclaimer of warranty and limitation of liability provided
796above cannot be given local legal effect according to their terms,
797reviewing courts shall apply local law that most closely approximates
798an absolute waiver of all civil liability in connection with the
799Program, unless a warranty or assumption of liability accompanies a
800copy of the Program in return for a fee.
801
802 END OF TERMS AND CONDITIONS
803
804 How to Apply These Terms to Your New Programs
805
806 If you develop a new program, and you want it to be of the greatest
807possible use to the public, the best way to achieve this is to make it
808free software which everyone can redistribute and change under these terms.
809
810 To do so, attach the following notices to the program. It is safest
811to attach them to the start of each source file to most effectively
812state the exclusion of warranty; and each file should have at least
813the "copyright" line and a pointer to where the full notice is found.
814
815 <one line to give the program's name and a brief idea of what it does.>
816 Copyright (C) <year> <name of author>
817
818 This program is free software: you can redistribute it and/or modify
819 it under the terms of the GNU General Public License as published by
820 the Free Software Foundation, either version 3 of the License, or
821 (at your option) any later version.
822
823 This program is distributed in the hope that it will be useful,
824 but WITHOUT ANY WARRANTY; without even the implied warranty of
825 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
826 GNU General Public License for more details.
827
828 You should have received a copy of the GNU General Public License
829 along with this program. If not, see <http://www.gnu.org/licenses/>.
830
831Also add information on how to contact you by electronic and paper mail.
832
833 If the program does terminal interaction, make it output a short
834notice like this when it starts in an interactive mode:
835
836 <program> Copyright (C) <year> <name of author>
837 This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
838 This is free software, and you are welcome to redistribute it
839 under certain conditions; type `show c' for details.
840
841The hypothetical commands `show w' and `show c' should show the appropriate
842parts of the General Public License. Of course, your program's commands
843might be different; for a GUI interface, you would use an "about box".
844
845 You should also get your employer (if you work as a programmer) or school,
846if any, to sign a "copyright disclaimer" for the program, if necessary.
847For more information on this, and how to apply and follow the GNU GPL, see
848<http://www.gnu.org/licenses/>.
849
850 The GNU General Public License does not permit incorporating your program
851into proprietary programs. If your program is a subroutine library, you
852may consider it more useful to permit linking proprietary applications with
853the library. If this is what you want to do, use the GNU Lesser General
854Public License instead of this License. But first, please read
855<http://www.gnu.org/philosophy/why-not-lgpl.html>.
856
857**********************************************************************
858**********************************************************************
diff --git a/inc/3rdparty/libraries/tcpdf/README.TXT b/inc/3rdparty/libraries/tcpdf/README.TXT
new file mode 100644
index 00000000..6d279ee2
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/README.TXT
@@ -0,0 +1,115 @@
1TCPDF - README
2============================================================
3
4I WISH TO IMPROVE AND EXPAND TCPDF BUT I NEED YOUR SUPPORT.
5PLEASE MAKE A DONATION:
6http://sourceforge.net/donate/index.php?group_id=128076
7
8------------------------------------------------------------
9
10Name: TCPDF
11Version: 6.0.093
12Release date: 2014-09-02
13Author: Nicola Asuni
14
15Copyright (c) 2002-2014:
16 Nicola Asuni
17 Tecnick.com LTD
18 www.tecnick.com
19
20URLs:
21 http://www.tcpdf.org
22 http://www.sourceforge.net/projects/tcpdf
23
24Description:
25 TCPDF is a PHP class for generating PDF files on-the-fly without requiring external extensions.
26 This library includes also a class to extract data from existing PDF documents and
27 classes to generate 1D and 2D barcodes in various formats.
28
29Main Features:
30 * no external libraries are required for the basic functions;
31 * all standard page formats, custom page formats, custom margins and units of measure;
32 * UTF-8 Unicode and Right-To-Left languages;
33 * TrueTypeUnicode, OpenTypeUnicode v1, TrueType, OpenType v1, Type1 and CID-0 fonts;
34 * font subsetting;
35 * methods to publish some XHTML + CSS code, Javascript and Forms;
36 * images, graphic (geometric figures) and transformation methods;
37 * supports JPEG, PNG and SVG images natively, all images supported by GD (GD, GD2, GD2PART, GIF, JPEG, PNG, BMP, XBM, XPM) and all images supported via ImagMagick (http: www.imagemagick.org/www/formats.html)
38 * 1D and 2D barcodes: CODE 39, ANSI MH10.8M-1983, USD-3, 3 of 9, CODE 93, USS-93, Standard 2 of 5, Interleaved 2 of 5, CODE 128 A/B/C, 2 and 5 Digits UPC-Based Extention, EAN 8, EAN 13, UPC-A, UPC-E, MSI, POSTNET, PLANET, RMS4CC (Royal Mail 4-state Customer Code), CBC (Customer Bar Code), KIX (Klant index - Customer index), Intelligent Mail Barcode, Onecode, USPS-B-3200, CODABAR, CODE 11, PHARMACODE, PHARMACODE TWO-TRACKS, Datamatrix, QR-Code, PDF417;
39 * JPEG and PNG ICC profiles, Grayscale, RGB, CMYK, Spot Colors and Transparencies;
40 * automatic page header and footer management;
41 * document encryption up to 256 bit and digital signature certifications;
42 * transactions to UNDO commands;
43 * PDF annotations, including links, text and file attachments;
44 * text rendering modes (fill, stroke and clipping);
45 * multiple columns mode;
46 * no-write page regions;
47 * bookmarks, named destinations and table of content;
48 * text hyphenation;
49 * text stretching and spacing (tracking);
50 * automatic page break, line break and text alignments including justification;
51 * automatic page numbering and page groups;
52 * move and delete pages;
53 * page compression (requires php-zlib extension);
54 * XOBject Templates;
55 * Layers and object visibility.
56 * PDF/A-1b support.
57
58Installation (full instructions on http: www.tcpdf.org):
59 1. copy the folder on your Web server
60 2. set your installation path and other parameters on the config/tcpdf_config.php
61 3. call the examples/example_001.php page with your browser to see an example
62
63Source Code Documentation:
64 http://www.tcpdf.org
65
66Additional Documentation:
67 http://www.tcpdf.org
68
69License:
70 Copyright (C) 2002-2014 Nicola Asuni - Tecnick.com LTD
71
72 TCPDF is free software: you can redistribute it and/or modify it
73 under the terms of the GNU Lesser General Public License as
74 published by the Free Software Foundation, either version 3 of the
75 License, or (at your option) any later version.
76
77 TCPDF is distributed in the hope that it will be useful, but
78 WITHOUT ANY WARRANTY; without even the implied warranty of
79 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
80 See the GNU Lesser General Public License for more details.
81
82 You should have received a copy of the License
83 along with TCPDF. If not, see
84 <http://www.tecnick.com/pagefiles/tcpdf/LICENSE.TXT>.
85
86 See LICENSE.TXT file for more information.
87
88Third party fonts:
89
90 This library may include third party font files released with different licenses.
91
92 All the PHP files on the fonts directory are subject to the general TCPDF license (GNU-LGPLv3),
93 they do not contain any binary data but just a description of the general properties of a particular font.
94 These files can be also generated on the fly using the font utilities and TCPDF methods.
95
96 All the original binary TTF font files have been renamed for compatibility with TCPDF and compressed using the gzcompress PHP function that uses the ZLIB data format (.z files).
97
98 The binary files (.z) that begins with the prefix "free" have been extracted from the GNU FreeFont collection (GNU-GPLv3).
99 The binary files (.z) that begins with the prefix "pdfa" have been derived from the GNU FreeFont, so they are subject to the same license.
100 For the details of Copyright, License and other information, please check the files inside the directory fonts/freefont-20120503
101 Link : http://www.gnu.org/software/freefont/
102
103 The binary files (.z) that begins with the prefix "dejavu" have been extracted from the DejaVu fonts 2.33 (Bitstream) collection.
104 For the details of Copyright, License and other information, please check the files inside the directory fonts/dejavu-fonts-ttf-2.33
105 Link : http://dejavu-fonts.org
106
107 The binary files (.z) that begins with the prefix "ae" have been extracted from the Arabeyes.org collection (GNU-GPLv2).
108 Link : http://projects.arabeyes.org/
109
110ICC profile:
111 TCPDF includes the sRGB.icc profile from the icc-profiles-free Debian package:
112 https://packages.debian.org/source/stable/icc-profiles-free
113
114
115============================================================
diff --git a/inc/3rdparty/libraries/tcpdf/composer.json b/inc/3rdparty/libraries/tcpdf/composer.json
new file mode 100644
index 00000000..43107544
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/composer.json
@@ -0,0 +1,40 @@
1{
2 "name": "tecnick.com/tcpdf",
3 "version": "6.0.093",
4 "homepage": "http://www.tcpdf.org/",
5 "type": "library",
6 "description": "TCPDF is a PHP class for generating PDF documents and barcodes.",
7 "keywords": ["PDF","tcpdf","PDFD32000-2008","qrcode","datamatrix","pdf417","barcodes"],
8 "license": "LGPLv3",
9 "authors": [
10 {
11 "name": "Nicola Asuni",
12 "email": "info@tecnick.com",
13 "homepage": "http://nicolaasuni.tecnick.com"
14 }
15 ],
16 "require": {
17 "php": ">=5.3.0"
18 },
19 "autoload": {
20 "classmap": [
21 "fonts",
22 "config",
23 "include",
24 "tcpdf.php",
25 "tcpdf_parser.php",
26 "tcpdf_import.php",
27 "tcpdf_barcodes_1d.php",
28 "tcpdf_barcodes_2d.php",
29 "include/tcpdf_colors.php",
30 "include/tcpdf_filters.php",
31 "include/tcpdf_font_data.php",
32 "include/tcpdf_fonts.php",
33 "include/tcpdf_images.php",
34 "include/tcpdf_static.php",
35 "include/barcodes/datamatrix.php",
36 "include/barcodes/pdf417.php",
37 "include/barcodes/qrcode.php"
38 ]
39 }
40}
diff --git a/inc/3rdparty/libraries/tcpdf/config/tcpdf_config.php b/inc/3rdparty/libraries/tcpdf/config/tcpdf_config.php
new file mode 100644
index 00000000..864a9d2d
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/config/tcpdf_config.php
@@ -0,0 +1,227 @@
1<?php
2//============================================================+
3// File name : tcpdf_config.php
4// Begin : 2004-06-11
5// Last Update : 2014-09-02
6//
7// Description : Configuration file for TCPDF.
8// Author : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com
9// License : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html)
10// -------------------------------------------------------------------
11// Copyright (C) 2004-2014 Nicola Asuni - Tecnick.com LTD
12//
13// This file is part of TCPDF software library.
14//
15// TCPDF is free software: you can redistribute it and/or modify it
16// under the terms of the GNU Lesser General Public License as
17// published by the Free Software Foundation, either version 3 of the
18// License, or (at your option) any later version.
19//
20// TCPDF is distributed in the hope that it will be useful, but
21// WITHOUT ANY WARRANTY; without even the implied warranty of
22// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23// See the GNU Lesser General Public License for more details.
24//
25// You should have received a copy of the GNU Lesser General Public License
26// along with TCPDF. If not, see <http://www.gnu.org/licenses/>.
27//
28// See LICENSE.TXT file for more information.
29//============================================================+
30
31/**
32 * Configuration file for TCPDF.
33 * @author Nicola Asuni
34 * @package com.tecnick.tcpdf
35 * @version 4.9.005
36 * @since 2004-10-27
37 */
38
39// IMPORTANT:
40// If you define the constant K_TCPDF_EXTERNAL_CONFIG, all the following settings will be ignored.
41// If you use the tcpdf_autoconfig.php, then you can overwrite some values here.
42
43
44/**
45 * Installation path (/var/www/tcpdf/).
46 * By default it is automatically calculated but you can also set it as a fixed string to improve performances.
47 */
48//define ('K_PATH_MAIN', '');
49
50/**
51 * URL path to tcpdf installation folder (http://localhost/tcpdf/).
52 * By default it is automatically set but you can also set it as a fixed string to improve performances.
53 */
54//define ('K_PATH_URL', '');
55
56/**
57 * Path for PDF fonts.
58 * By default it is automatically set but you can also set it as a fixed string to improve performances.
59 */
60//define ('K_PATH_FONTS', K_PATH_MAIN.'fonts/');
61
62/**
63 * Default images directory.
64 * By default it is automatically set but you can also set it as a fixed string to improve performances.
65 */
66//define ('K_PATH_IMAGES', '');
67
68/**
69 * Deafult image logo used be the default Header() method.
70 * Please set here your own logo or an empty string to disable it.
71 */
72//define ('PDF_HEADER_LOGO', '');
73
74/**
75 * Header logo image width in user units.
76 */
77//define ('PDF_HEADER_LOGO_WIDTH', 0);
78
79/**
80 * Cache directory for temporary files (full path).
81 */
82//define ('K_PATH_CACHE', '/tmp/');
83
84/**
85 * Generic name for a blank image.
86 */
87define ('K_BLANK_IMAGE', '_blank.png');
88
89/**
90 * Page format.
91 */
92define ('PDF_PAGE_FORMAT', 'A4');
93
94/**
95 * Page orientation (P=portrait, L=landscape).
96 */
97define ('PDF_PAGE_ORIENTATION', 'P');
98
99/**
100 * Document creator.
101 */
102define ('PDF_CREATOR', 'TCPDF');
103
104/**
105 * Document author.
106 */
107define ('PDF_AUTHOR', 'TCPDF');
108
109/**
110 * Header title.
111 */
112define ('PDF_HEADER_TITLE', 'TCPDF Example');
113
114/**
115 * Header description string.
116 */
117define ('PDF_HEADER_STRING', "by Nicola Asuni - Tecnick.com\nwww.tcpdf.org");
118
119/**
120 * Document unit of measure [pt=point, mm=millimeter, cm=centimeter, in=inch].
121 */
122define ('PDF_UNIT', 'mm');
123
124/**
125 * Header margin.
126 */
127define ('PDF_MARGIN_HEADER', 5);
128
129/**
130 * Footer margin.
131 */
132define ('PDF_MARGIN_FOOTER', 10);
133
134/**
135 * Top margin.
136 */
137define ('PDF_MARGIN_TOP', 27);
138
139/**
140 * Bottom margin.
141 */
142define ('PDF_MARGIN_BOTTOM', 25);
143
144/**
145 * Left margin.
146 */
147define ('PDF_MARGIN_LEFT', 15);
148
149/**
150 * Right margin.
151 */
152define ('PDF_MARGIN_RIGHT', 15);
153
154/**
155 * Default main font name.
156 */
157define ('PDF_FONT_NAME_MAIN', 'helvetica');
158
159/**
160 * Default main font size.
161 */
162define ('PDF_FONT_SIZE_MAIN', 10);
163
164/**
165 * Default data font name.
166 */
167define ('PDF_FONT_NAME_DATA', 'helvetica');
168
169/**
170 * Default data font size.
171 */
172define ('PDF_FONT_SIZE_DATA', 8);
173
174/**
175 * Default monospaced font name.
176 */
177define ('PDF_FONT_MONOSPACED', 'courier');
178
179/**
180 * Ratio used to adjust the conversion of pixels to user units.
181 */
182define ('PDF_IMAGE_SCALE_RATIO', 1.25);
183
184/**
185 * Magnification factor for titles.
186 */
187define('HEAD_MAGNIFICATION', 1.1);
188
189/**
190 * Height of cell respect font height.
191 */
192define('K_CELL_HEIGHT_RATIO', 1.25);
193
194/**
195 * Title magnification respect main font size.
196 */
197define('K_TITLE_MAGNIFICATION', 1.3);
198
199/**
200 * Reduction factor for small font.
201 */
202define('K_SMALL_RATIO', 2/3);
203
204/**
205 * Set to true to enable the special procedure used to avoid the overlappind of symbols on Thai language.
206 */
207define('K_THAI_TOPCHARS', true);
208
209/**
210 * If true allows to call TCPDF methods using HTML syntax
211 * IMPORTANT: For security reason, disable this feature if you are printing user HTML content.
212 */
213define('K_TCPDF_CALLS_IN_HTML', true);
214
215/**
216 * If true and PHP version is greater than 5, then the Error() method throw new exception instead of terminating the execution.
217 */
218define('K_TCPDF_THROW_EXCEPTION_ERROR', false);
219
220/**
221 * Default timezone for datetime functions
222 */
223define('K_TIMEZONE', 'UTC');
224
225//============================================================+
226// END OF FILE
227//============================================================+
diff --git a/inc/3rdparty/libraries/tcpdf/fonts/courier.php b/inc/3rdparty/libraries/tcpdf/fonts/courier.php
new file mode 100644
index 00000000..e935b676
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/fonts/courier.php
@@ -0,0 +1,12 @@
1<?php
2// TCPDF FONT FILE DESCRIPTION
3$type='core';
4$name='Courier';
5$up=-100;
6$ut=50;
7$dw=600;
8$diff='';
9$enc='';
10$desc=array('Flags'=>33,'FontBBox'=>'[-23 -250 715 805]','ItalicAngle'=>0,'Ascent'=>805,'Descent'=>-250,'Leading'=>0,'CapHeight'=>562,'XHeight'=>426,'StemV'=>51,'StemH'=>51,'AvgWidth'=>600,'MaxWidth'=>600,'MissingWidth'=>600);
11$cw=array(0=>600,1=>600,2=>600,3=>600,4=>600,5=>600,6=>600,7=>600,8=>600,9=>600,10=>600,11=>600,12=>600,13=>600,14=>600,15=>600,16=>600,17=>600,18=>600,19=>600,20=>600,21=>600,22=>600,23=>600,24=>600,25=>600,26=>600,27=>600,28=>600,29=>600,30=>600,31=>600,32=>600,33=>600,34=>600,35=>600,36=>600,37=>600,38=>600,39=>600,40=>600,41=>600,42=>600,43=>600,44=>600,45=>600,46=>600,47=>600,48=>600,49=>600,50=>600,51=>600,52=>600,53=>600,54=>600,55=>600,56=>600,57=>600,58=>600,59=>600,60=>600,61=>600,62=>600,63=>600,64=>600,65=>600,66=>600,67=>600,68=>600,69=>600,70=>600,71=>600,72=>600,73=>600,74=>600,75=>600,76=>600,77=>600,78=>600,79=>600,80=>600,81=>600,82=>600,83=>600,84=>600,85=>600,86=>600,87=>600,88=>600,89=>600,90=>600,91=>600,92=>600,93=>600,94=>600,95=>600,96=>600,97=>600,98=>600,99=>600,100=>600,101=>600,102=>600,103=>600,104=>600,105=>600,106=>600,107=>600,108=>600,109=>600,110=>600,111=>600,112=>600,113=>600,114=>600,115=>600,116=>600,117=>600,118=>600,119=>600,120=>600,121=>600,122=>600,123=>600,124=>600,125=>600,126=>600,127=>600,128=>600,129=>600,130=>600,131=>600,132=>600,133=>600,134=>600,135=>600,136=>600,137=>600,138=>600,139=>600,140=>600,141=>600,142=>600,143=>600,144=>600,145=>600,146=>600,147=>600,148=>600,149=>600,150=>600,151=>600,152=>600,153=>600,154=>600,155=>600,156=>600,157=>600,158=>600,159=>600,160=>600,161=>600,162=>600,163=>600,164=>600,165=>600,166=>600,167=>600,168=>600,169=>600,170=>600,171=>600,172=>600,173=>600,174=>600,175=>600,176=>600,177=>600,178=>600,179=>600,180=>600,181=>600,182=>600,183=>600,184=>600,185=>600,186=>600,187=>600,188=>600,189=>600,190=>600,191=>600,192=>600,193=>600,194=>600,195=>600,196=>600,197=>600,198=>600,199=>600,200=>600,201=>600,202=>600,203=>600,204=>600,205=>600,206=>600,207=>600,208=>600,209=>600,210=>600,211=>600,212=>600,213=>600,214=>600,215=>600,216=>600,217=>600,218=>600,219=>600,220=>600,221=>600,222=>600,223=>600,224=>600,225=>600,226=>600,227=>600,228=>600,229=>600,230=>600,231=>600,232=>600,233=>600,234=>600,235=>600,236=>600,237=>600,238=>600,239=>600,240=>600,241=>600,242=>600,243=>600,244=>600,245=>600,246=>600,247=>600,248=>600,249=>600,250=>600,251=>600,252=>600,253=>600,254=>600,255=>600);
12// --- EOF ---
diff --git a/inc/3rdparty/libraries/tcpdf/fonts/courierb.php b/inc/3rdparty/libraries/tcpdf/fonts/courierb.php
new file mode 100644
index 00000000..acb01b0d
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/fonts/courierb.php
@@ -0,0 +1,12 @@
1<?php
2// TCPDF FONT FILE DESCRIPTION
3$type='core';
4$name='Courier-Bold';
5$up=-100;
6$ut=50;
7$dw=600;
8$diff='';
9$enc='';
10$desc=array('Flags'=>33,'FontBBox'=>'[-113 -250 749 801]','ItalicAngle'=>0,'Ascent'=>801,'Descent'=>-250,'Leading'=>0,'CapHeight'=>562,'XHeight'=>439,'StemV'=>106,'StemH'=>84,'AvgWidth'=>600,'MaxWidth'=>600,'MissingWidth'=>600);
11$cw=array(0=>600,1=>600,2=>600,3=>600,4=>600,5=>600,6=>600,7=>600,8=>600,9=>600,10=>600,11=>600,12=>600,13=>600,14=>600,15=>600,16=>600,17=>600,18=>600,19=>600,20=>600,21=>600,22=>600,23=>600,24=>600,25=>600,26=>600,27=>600,28=>600,29=>600,30=>600,31=>600,32=>600,33=>600,34=>600,35=>600,36=>600,37=>600,38=>600,39=>600,40=>600,41=>600,42=>600,43=>600,44=>600,45=>600,46=>600,47=>600,48=>600,49=>600,50=>600,51=>600,52=>600,53=>600,54=>600,55=>600,56=>600,57=>600,58=>600,59=>600,60=>600,61=>600,62=>600,63=>600,64=>600,65=>600,66=>600,67=>600,68=>600,69=>600,70=>600,71=>600,72=>600,73=>600,74=>600,75=>600,76=>600,77=>600,78=>600,79=>600,80=>600,81=>600,82=>600,83=>600,84=>600,85=>600,86=>600,87=>600,88=>600,89=>600,90=>600,91=>600,92=>600,93=>600,94=>600,95=>600,96=>600,97=>600,98=>600,99=>600,100=>600,101=>600,102=>600,103=>600,104=>600,105=>600,106=>600,107=>600,108=>600,109=>600,110=>600,111=>600,112=>600,113=>600,114=>600,115=>600,116=>600,117=>600,118=>600,119=>600,120=>600,121=>600,122=>600,123=>600,124=>600,125=>600,126=>600,127=>600,128=>600,129=>600,130=>600,131=>600,132=>600,133=>600,134=>600,135=>600,136=>600,137=>600,138=>600,139=>600,140=>600,141=>600,142=>600,143=>600,144=>600,145=>600,146=>600,147=>600,148=>600,149=>600,150=>600,151=>600,152=>600,153=>600,154=>600,155=>600,156=>600,157=>600,158=>600,159=>600,160=>600,161=>600,162=>600,163=>600,164=>600,165=>600,166=>600,167=>600,168=>600,169=>600,170=>600,171=>600,172=>600,173=>600,174=>600,175=>600,176=>600,177=>600,178=>600,179=>600,180=>600,181=>600,182=>600,183=>600,184=>600,185=>600,186=>600,187=>600,188=>600,189=>600,190=>600,191=>600,192=>600,193=>600,194=>600,195=>600,196=>600,197=>600,198=>600,199=>600,200=>600,201=>600,202=>600,203=>600,204=>600,205=>600,206=>600,207=>600,208=>600,209=>600,210=>600,211=>600,212=>600,213=>600,214=>600,215=>600,216=>600,217=>600,218=>600,219=>600,220=>600,221=>600,222=>600,223=>600,224=>600,225=>600,226=>600,227=>600,228=>600,229=>600,230=>600,231=>600,232=>600,233=>600,234=>600,235=>600,236=>600,237=>600,238=>600,239=>600,240=>600,241=>600,242=>600,243=>600,244=>600,245=>600,246=>600,247=>600,248=>600,249=>600,250=>600,251=>600,252=>600,253=>600,254=>600,255=>600);
12// --- EOF ---
diff --git a/inc/3rdparty/libraries/tcpdf/fonts/courierbi.php b/inc/3rdparty/libraries/tcpdf/fonts/courierbi.php
new file mode 100644
index 00000000..631c623e
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/fonts/courierbi.php
@@ -0,0 +1,12 @@
1<?php
2// TCPDF FONT FILE DESCRIPTION
3$type='core';
4$name='Courier-BoldOblique';
5$up=-100;
6$ut=50;
7$dw=600;
8$diff='';
9$enc='';
10$desc=array('Flags'=>97,'FontBBox'=>'[-57 -250 869 801]','ItalicAngle'=>-12,'Ascent'=>801,'Descent'=>-250,'Leading'=>0,'CapHeight'=>562,'XHeight'=>439,'StemV'=>106,'StemH'=>84,'AvgWidth'=>600,'MaxWidth'=>600,'MissingWidth'=>600);
11$cw=array(0=>600,1=>600,2=>600,3=>600,4=>600,5=>600,6=>600,7=>600,8=>600,9=>600,10=>600,11=>600,12=>600,13=>600,14=>600,15=>600,16=>600,17=>600,18=>600,19=>600,20=>600,21=>600,22=>600,23=>600,24=>600,25=>600,26=>600,27=>600,28=>600,29=>600,30=>600,31=>600,32=>600,33=>600,34=>600,35=>600,36=>600,37=>600,38=>600,39=>600,40=>600,41=>600,42=>600,43=>600,44=>600,45=>600,46=>600,47=>600,48=>600,49=>600,50=>600,51=>600,52=>600,53=>600,54=>600,55=>600,56=>600,57=>600,58=>600,59=>600,60=>600,61=>600,62=>600,63=>600,64=>600,65=>600,66=>600,67=>600,68=>600,69=>600,70=>600,71=>600,72=>600,73=>600,74=>600,75=>600,76=>600,77=>600,78=>600,79=>600,80=>600,81=>600,82=>600,83=>600,84=>600,85=>600,86=>600,87=>600,88=>600,89=>600,90=>600,91=>600,92=>600,93=>600,94=>600,95=>600,96=>600,97=>600,98=>600,99=>600,100=>600,101=>600,102=>600,103=>600,104=>600,105=>600,106=>600,107=>600,108=>600,109=>600,110=>600,111=>600,112=>600,113=>600,114=>600,115=>600,116=>600,117=>600,118=>600,119=>600,120=>600,121=>600,122=>600,123=>600,124=>600,125=>600,126=>600,127=>600,128=>600,129=>600,130=>600,131=>600,132=>600,133=>600,134=>600,135=>600,136=>600,137=>600,138=>600,139=>600,140=>600,141=>600,142=>600,143=>600,144=>600,145=>600,146=>600,147=>600,148=>600,149=>600,150=>600,151=>600,152=>600,153=>600,154=>600,155=>600,156=>600,157=>600,158=>600,159=>600,160=>600,161=>600,162=>600,163=>600,164=>600,165=>600,166=>600,167=>600,168=>600,169=>600,170=>600,171=>600,172=>600,173=>600,174=>600,175=>600,176=>600,177=>600,178=>600,179=>600,180=>600,181=>600,182=>600,183=>600,184=>600,185=>600,186=>600,187=>600,188=>600,189=>600,190=>600,191=>600,192=>600,193=>600,194=>600,195=>600,196=>600,197=>600,198=>600,199=>600,200=>600,201=>600,202=>600,203=>600,204=>600,205=>600,206=>600,207=>600,208=>600,209=>600,210=>600,211=>600,212=>600,213=>600,214=>600,215=>600,216=>600,217=>600,218=>600,219=>600,220=>600,221=>600,222=>600,223=>600,224=>600,225=>600,226=>600,227=>600,228=>600,229=>600,230=>600,231=>600,232=>600,233=>600,234=>600,235=>600,236=>600,237=>600,238=>600,239=>600,240=>600,241=>600,242=>600,243=>600,244=>600,245=>600,246=>600,247=>600,248=>600,249=>600,250=>600,251=>600,252=>600,253=>600,254=>600,255=>600);
12// --- EOF ---
diff --git a/inc/3rdparty/libraries/tcpdf/fonts/courieri.php b/inc/3rdparty/libraries/tcpdf/fonts/courieri.php
new file mode 100644
index 00000000..5ae725d4
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/fonts/courieri.php
@@ -0,0 +1,12 @@
1<?php
2// TCPDF FONT FILE DESCRIPTION
3$type='core';
4$name='Courier-Oblique';
5$up=-100;
6$ut=50;
7$dw=600;
8$diff='';
9$enc='';
10$desc=array('Flags'=>97,'FontBBox'=>'[-27 -250 849 805]','ItalicAngle'=>-12,'Ascent'=>805,'Descent'=>-250,'Leading'=>0,'CapHeight'=>562,'XHeight'=>426,'StemV'=>51,'StemH'=>51,'AvgWidth'=>600,'MaxWidth'=>600,'MissingWidth'=>600);
11$cw=array(0=>600,1=>600,2=>600,3=>600,4=>600,5=>600,6=>600,7=>600,8=>600,9=>600,10=>600,11=>600,12=>600,13=>600,14=>600,15=>600,16=>600,17=>600,18=>600,19=>600,20=>600,21=>600,22=>600,23=>600,24=>600,25=>600,26=>600,27=>600,28=>600,29=>600,30=>600,31=>600,32=>600,33=>600,34=>600,35=>600,36=>600,37=>600,38=>600,39=>600,40=>600,41=>600,42=>600,43=>600,44=>600,45=>600,46=>600,47=>600,48=>600,49=>600,50=>600,51=>600,52=>600,53=>600,54=>600,55=>600,56=>600,57=>600,58=>600,59=>600,60=>600,61=>600,62=>600,63=>600,64=>600,65=>600,66=>600,67=>600,68=>600,69=>600,70=>600,71=>600,72=>600,73=>600,74=>600,75=>600,76=>600,77=>600,78=>600,79=>600,80=>600,81=>600,82=>600,83=>600,84=>600,85=>600,86=>600,87=>600,88=>600,89=>600,90=>600,91=>600,92=>600,93=>600,94=>600,95=>600,96=>600,97=>600,98=>600,99=>600,100=>600,101=>600,102=>600,103=>600,104=>600,105=>600,106=>600,107=>600,108=>600,109=>600,110=>600,111=>600,112=>600,113=>600,114=>600,115=>600,116=>600,117=>600,118=>600,119=>600,120=>600,121=>600,122=>600,123=>600,124=>600,125=>600,126=>600,127=>600,128=>600,129=>600,130=>600,131=>600,132=>600,133=>600,134=>600,135=>600,136=>600,137=>600,138=>600,139=>600,140=>600,141=>600,142=>600,143=>600,144=>600,145=>600,146=>600,147=>600,148=>600,149=>600,150=>600,151=>600,152=>600,153=>600,154=>600,155=>600,156=>600,157=>600,158=>600,159=>600,160=>600,161=>600,162=>600,163=>600,164=>600,165=>600,166=>600,167=>600,168=>600,169=>600,170=>600,171=>600,172=>600,173=>600,174=>600,175=>600,176=>600,177=>600,178=>600,179=>600,180=>600,181=>600,182=>600,183=>600,184=>600,185=>600,186=>600,187=>600,188=>600,189=>600,190=>600,191=>600,192=>600,193=>600,194=>600,195=>600,196=>600,197=>600,198=>600,199=>600,200=>600,201=>600,202=>600,203=>600,204=>600,205=>600,206=>600,207=>600,208=>600,209=>600,210=>600,211=>600,212=>600,213=>600,214=>600,215=>600,216=>600,217=>600,218=>600,219=>600,220=>600,221=>600,222=>600,223=>600,224=>600,225=>600,226=>600,227=>600,228=>600,229=>600,230=>600,231=>600,232=>600,233=>600,234=>600,235=>600,236=>600,237=>600,238=>600,239=>600,240=>600,241=>600,242=>600,243=>600,244=>600,245=>600,246=>600,247=>600,248=>600,249=>600,250=>600,251=>600,252=>600,253=>600,254=>600,255=>600);
12// --- EOF ---
diff --git a/inc/3rdparty/libraries/tcpdf/fonts/helvetica.php b/inc/3rdparty/libraries/tcpdf/fonts/helvetica.php
new file mode 100644
index 00000000..d1aa6d85
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/fonts/helvetica.php
@@ -0,0 +1,13 @@
1<?php
2// TCPDF FONT FILE DESCRIPTION
3$type='core';
4$name='Helvetica';
5$up=-100;
6$ut=50;
7$dw=513;
8$diff='';
9$enc='';
10$desc=array('Flags'=>32,'FontBBox'=>'[-166 -225 1000 931]','ItalicAngle'=>0,'Ascent'=>931,'Descent'=>-225,'Leading'=>0,'CapHeight'=>718,'XHeight'=>523,'StemV'=>88,'StemH'=>76,'AvgWidth'=>513,'MaxWidth'=>1015,'MissingWidth'=>513);
11$cw=array(0=>500,1=>500,2=>500,3=>500,4=>500,5=>500,6=>500,7=>500,8=>500,9=>500,10=>500,11=>500,12=>500,13=>500,14=>500,15=>500,16=>500,17=>500,18=>500,19=>500,20=>500,21=>500,22=>500,23=>500,24=>500,25=>500,26=>500,27=>500,28=>500,29=>500,30=>500,31=>500,32=>278,33=>278,34=>355,35=>556,36=>556,37=>889,38=>667,39=>191,40=>333,41=>333,42=>389,43=>584,44=>278,45=>333,46=>278,47=>278,48=>556,49=>556,50=>556,51=>556,52=>556,53=>556,54=>556,55=>556,56=>556,57=>556,58=>278,59=>278,60=>584,61=>584,62=>584,63=>556,64=>1015,65=>667,66=>667,67=>722,68=>722,69=>667,70=>611,71=>778,72=>722,73=>278,74=>500,75=>667,76=>556,77=>833,78=>722,79=>778,80=>667,81=>778,82=>722,83=>667,84=>611,85=>722,86=>667,87=>944,88=>667,89=>667,90=>611,91=>278,92=>278,93=>277,94=>469,95=>556,96=>333,97=>556,98=>556,99=>500,100=>556,101=>556,102=>278,103=>556,104=>556,105=>222,106=>222,107=>500,108=>222,109=>833,110=>556,111=>556,112=>556,113=>556,114=>333,115=>500,116=>278,117=>556,118=>500,119=>722,120=>500,121=>500,122=>500,123=>334,124=>260,125=>334,126=>584,127=>500,128=>655,129=>500,130=>222,131=>278,132=>333,133=>1000,134=>556,135=>556,136=>333,137=>1000,138=>667,139=>250,140=>1000,141=>500,142=>611,143=>500,144=>500,145=>222,146=>221,147=>333,148=>333,149=>350,150=>556,151=>1000,152=>333,153=>1000,154=>500,155=>250,156=>938,157=>500,158=>500,159=>667,160=>278,161=>278,162=>556,163=>556,164=>556,165=>556,166=>260,167=>556,168=>333,169=>737,170=>370,171=>448,172=>584,173=>333,174=>737,175=>333,176=>606,177=>584,178=>350,179=>350,180=>333,181=>556,182=>537,183=>278,184=>333,185=>350,186=>365,187=>448,188=>869,189=>869,190=>879,191=>556,192=>667,193=>667,194=>667,195=>667,196=>667,197=>667,198=>1000,199=>722,200=>667,201=>667,202=>667,203=>667,204=>278,205=>278,206=>278,207=>278,208=>722,209=>722,210=>778,211=>778,212=>778,213=>778,214=>778,215=>584,216=>778,217=>722,218=>722,219=>722,220=>722,221=>667,222=>666,223=>611,224=>556,225=>556,226=>556,227=>556,228=>556,229=>556,230=>896,231=>500,232=>556,233=>556,234=>556,235=>556,236=>251,237=>251,238=>251,239=>251,240=>556,241=>556,242=>556,243=>556,244=>556,245=>556,246=>556,247=>584,248=>611,249=>556,250=>556,251=>556,252=>556,253=>500,254=>555,255=>500);
12
13// --- EOF ---
diff --git a/inc/3rdparty/libraries/tcpdf/fonts/helveticab.php b/inc/3rdparty/libraries/tcpdf/fonts/helveticab.php
new file mode 100644
index 00000000..8d6047f6
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/fonts/helveticab.php
@@ -0,0 +1,12 @@
1<?php
2// TCPDF FONT FILE DESCRIPTION
3$type='core';
4$name='Helvetica-Bold';
5$up=-100;
6$ut=50;
7$dw=535;
8$diff='';
9$enc='';
10$desc=array('Flags'=>32,'FontBBox'=>'[-170 -228 1003 962]','ItalicAngle'=>0,'Ascent'=>962,'Descent'=>-228,'Leading'=>0,'CapHeight'=>718,'XHeight'=>532,'StemV'=>140,'StemH'=>118,'AvgWidth'=>535,'MaxWidth'=>1000,'MissingWidth'=>535);
11$cw=array(0=>278,1=>278,2=>278,3=>278,4=>278,5=>278,6=>278,7=>278,8=>278,9=>278,10=>278,11=>278,12=>278,13=>278,14=>278,15=>278,16=>278,17=>278,18=>278,19=>278,20=>278,21=>278,22=>278,23=>278,24=>278,25=>278,26=>278,27=>278,28=>278,29=>278,30=>278,31=>278,32=>278,33=>333,34=>474,35=>556,36=>556,37=>889,38=>722,39=>238,40=>333,41=>333,42=>389,43=>584,44=>278,45=>333,46=>278,47=>278,48=>556,49=>556,50=>556,51=>556,52=>556,53=>556,54=>556,55=>556,56=>556,57=>556,58=>333,59=>333,60=>584,61=>584,62=>584,63=>611,64=>975,65=>722,66=>722,67=>722,68=>722,69=>667,70=>611,71=>778,72=>722,73=>278,74=>556,75=>722,76=>611,77=>833,78=>722,79=>778,80=>667,81=>778,82=>722,83=>667,84=>611,85=>722,86=>667,87=>944,88=>667,89=>667,90=>611,91=>333,92=>278,93=>333,94=>584,95=>556,96=>333,97=>556,98=>611,99=>556,100=>611,101=>556,102=>333,103=>611,104=>611,105=>278,106=>278,107=>556,108=>278,109=>889,110=>611,111=>611,112=>611,113=>611,114=>389,115=>556,116=>333,117=>611,118=>556,119=>778,120=>556,121=>556,122=>500,123=>389,124=>280,125=>389,126=>584,127=>350,128=>556,129=>350,130=>278,131=>556,132=>500,133=>1000,134=>556,135=>556,136=>333,137=>1000,138=>667,139=>333,140=>1000,141=>350,142=>611,143=>350,144=>350,145=>278,146=>278,147=>500,148=>500,149=>350,150=>556,151=>1000,152=>333,153=>1000,154=>556,155=>333,156=>944,157=>350,158=>500,159=>667,160=>278,161=>333,162=>556,163=>556,164=>556,165=>556,166=>280,167=>556,168=>333,169=>737,170=>370,171=>556,172=>584,173=>333,174=>737,175=>333,176=>400,177=>584,178=>333,179=>333,180=>333,181=>611,182=>556,183=>278,184=>333,185=>333,186=>365,187=>556,188=>834,189=>834,190=>834,191=>611,192=>722,193=>722,194=>722,195=>722,196=>722,197=>722,198=>1000,199=>722,200=>667,201=>667,202=>667,203=>667,204=>278,205=>278,206=>278,207=>278,208=>722,209=>722,210=>778,211=>778,212=>778,213=>778,214=>778,215=>584,216=>778,217=>722,218=>722,219=>722,220=>722,221=>667,222=>667,223=>611,224=>556,225=>556,226=>556,227=>556,228=>556,229=>556,230=>889,231=>556,232=>556,233=>556,234=>556,235=>556,236=>278,237=>278,238=>278,239=>278,240=>611,241=>611,242=>611,243=>611,244=>611,245=>611,246=>611,247=>584,248=>611,249=>611,250=>611,251=>611,252=>611,253=>556,254=>611,255=>556);
12// --- EOF ---
diff --git a/inc/3rdparty/libraries/tcpdf/fonts/helveticabi.php b/inc/3rdparty/libraries/tcpdf/fonts/helveticabi.php
new file mode 100644
index 00000000..e2ecf38d
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/fonts/helveticabi.php
@@ -0,0 +1,12 @@
1<?php
2// TCPDF FONT FILE DESCRIPTION
3$type='core';
4$name='Helvetica-BoldOblique';
5$up=-100;
6$ut=50;
7$dw=535;
8$diff='';
9$enc='';
10$desc=array('Flags'=>96,'FontBBox'=>'[-174 -228 1114 962]','ItalicAngle'=>-12,'Ascent'=>962,'Descent'=>-228,'Leading'=>0,'CapHeight'=>718,'XHeight'=>532,'StemV'=>140,'StemH'=>118,'AvgWidth'=>535,'MaxWidth'=>1000,'MissingWidth'=>535);
11$cw=array(0=>278,1=>278,2=>278,3=>278,4=>278,5=>278,6=>278,7=>278,8=>278,9=>278,10=>278,11=>278,12=>278,13=>278,14=>278,15=>278,16=>278,17=>278,18=>278,19=>278,20=>278,21=>278,22=>278,23=>278,24=>278,25=>278,26=>278,27=>278,28=>278,29=>278,30=>278,31=>278,32=>278,33=>333,34=>474,35=>556,36=>556,37=>889,38=>722,39=>238,40=>333,41=>333,42=>389,43=>584,44=>278,45=>333,46=>278,47=>278,48=>556,49=>556,50=>556,51=>556,52=>556,53=>556,54=>556,55=>556,56=>556,57=>556,58=>333,59=>333,60=>584,61=>584,62=>584,63=>611,64=>975,65=>722,66=>722,67=>722,68=>722,69=>667,70=>611,71=>778,72=>722,73=>278,74=>556,75=>722,76=>611,77=>833,78=>722,79=>778,80=>667,81=>778,82=>722,83=>667,84=>611,85=>722,86=>667,87=>944,88=>667,89=>667,90=>611,91=>333,92=>278,93=>333,94=>584,95=>556,96=>333,97=>556,98=>611,99=>556,100=>611,101=>556,102=>333,103=>611,104=>611,105=>278,106=>278,107=>556,108=>278,109=>889,110=>611,111=>611,112=>611,113=>611,114=>389,115=>556,116=>333,117=>611,118=>556,119=>778,120=>556,121=>556,122=>500,123=>389,124=>280,125=>389,126=>584,127=>350,128=>556,129=>350,130=>278,131=>556,132=>500,133=>1000,134=>556,135=>556,136=>333,137=>1000,138=>667,139=>333,140=>1000,141=>350,142=>611,143=>350,144=>350,145=>278,146=>278,147=>500,148=>500,149=>350,150=>556,151=>1000,152=>333,153=>1000,154=>556,155=>333,156=>944,157=>350,158=>500,159=>667,160=>278,161=>333,162=>556,163=>556,164=>556,165=>556,166=>280,167=>556,168=>333,169=>737,170=>370,171=>556,172=>584,173=>333,174=>737,175=>333,176=>400,177=>584,178=>333,179=>333,180=>333,181=>611,182=>556,183=>278,184=>333,185=>333,186=>365,187=>556,188=>834,189=>834,190=>834,191=>611,192=>722,193=>722,194=>722,195=>722,196=>722,197=>722,198=>1000,199=>722,200=>667,201=>667,202=>667,203=>667,204=>278,205=>278,206=>278,207=>278,208=>722,209=>722,210=>778,211=>778,212=>778,213=>778,214=>778,215=>584,216=>778,217=>722,218=>722,219=>722,220=>722,221=>667,222=>667,223=>611,224=>556,225=>556,226=>556,227=>556,228=>556,229=>556,230=>889,231=>556,232=>556,233=>556,234=>556,235=>556,236=>278,237=>278,238=>278,239=>278,240=>611,241=>611,242=>611,243=>611,244=>611,245=>611,246=>611,247=>584,248=>611,249=>611,250=>611,251=>611,252=>611,253=>556,254=>611,255=>556);
12// --- EOF ---
diff --git a/inc/3rdparty/libraries/tcpdf/fonts/helveticai.php b/inc/3rdparty/libraries/tcpdf/fonts/helveticai.php
new file mode 100644
index 00000000..0404aebd
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/fonts/helveticai.php
@@ -0,0 +1,12 @@
1<?php
2// TCPDF FONT FILE DESCRIPTION
3$type='core';
4$name='Helvetica-Oblique';
5$up=-100;
6$ut=50;
7$dw=513;
8$diff='';
9$enc='';
10$desc=array('Flags'=>96,'FontBBox'=>'[-170 -225 1116 931]','ItalicAngle'=>-12,'Ascent'=>931,'Descent'=>-225,'Leading'=>0,'CapHeight'=>718,'XHeight'=>523,'StemV'=>88,'StemH'=>76,'AvgWidth'=>513,'MaxWidth'=>1015,'MissingWidth'=>513);
11$cw=array(0=>278,1=>278,2=>278,3=>278,4=>278,5=>278,6=>278,7=>278,8=>278,9=>278,10=>278,11=>278,12=>278,13=>278,14=>278,15=>278,16=>278,17=>278,18=>278,19=>278,20=>278,21=>278,22=>278,23=>278,24=>278,25=>278,26=>278,27=>278,28=>278,29=>278,30=>278,31=>278,32=>278,33=>278,34=>355,35=>556,36=>556,37=>889,38=>667,39=>191,40=>333,41=>333,42=>389,43=>584,44=>278,45=>333,46=>278,47=>278,48=>556,49=>556,50=>556,51=>556,52=>556,53=>556,54=>556,55=>556,56=>556,57=>556,58=>278,59=>278,60=>584,61=>584,62=>584,63=>556,64=>1015,65=>667,66=>667,67=>722,68=>722,69=>667,70=>611,71=>778,72=>722,73=>278,74=>500,75=>667,76=>556,77=>833,78=>722,79=>778,80=>667,81=>778,82=>722,83=>667,84=>611,85=>722,86=>667,87=>944,88=>667,89=>667,90=>611,91=>278,92=>278,93=>278,94=>469,95=>556,96=>333,97=>556,98=>556,99=>500,100=>556,101=>556,102=>278,103=>556,104=>556,105=>222,106=>222,107=>500,108=>222,109=>833,110=>556,111=>556,112=>556,113=>556,114=>333,115=>500,116=>278,117=>556,118=>500,119=>722,120=>500,121=>500,122=>500,123=>334,124=>260,125=>334,126=>584,127=>350,128=>556,129=>350,130=>222,131=>556,132=>333,133=>1000,134=>556,135=>556,136=>333,137=>1000,138=>667,139=>333,140=>1000,141=>350,142=>611,143=>350,144=>350,145=>222,146=>222,147=>333,148=>333,149=>350,150=>556,151=>1000,152=>333,153=>1000,154=>500,155=>333,156=>944,157=>350,158=>500,159=>667,160=>278,161=>333,162=>556,163=>556,164=>556,165=>556,166=>260,167=>556,168=>333,169=>737,170=>370,171=>556,172=>584,173=>333,174=>737,175=>333,176=>400,177=>584,178=>333,179=>333,180=>333,181=>556,182=>537,183=>278,184=>333,185=>333,186=>365,187=>556,188=>834,189=>834,190=>834,191=>611,192=>667,193=>667,194=>667,195=>667,196=>667,197=>667,198=>1000,199=>722,200=>667,201=>667,202=>667,203=>667,204=>278,205=>278,206=>278,207=>278,208=>722,209=>722,210=>778,211=>778,212=>778,213=>778,214=>778,215=>584,216=>778,217=>722,218=>722,219=>722,220=>722,221=>667,222=>667,223=>611,224=>556,225=>556,226=>556,227=>556,228=>556,229=>556,230=>889,231=>500,232=>556,233=>556,234=>556,235=>556,236=>278,237=>278,238=>278,239=>278,240=>556,241=>556,242=>556,243=>556,244=>556,245=>556,246=>556,247=>584,248=>611,249=>556,250=>556,251=>556,252=>556,253=>500,254=>556,255=>500);
12// --- EOF ---
diff --git a/inc/3rdparty/libraries/tcpdf/fonts/symbol.php b/inc/3rdparty/libraries/tcpdf/fonts/symbol.php
new file mode 100644
index 00000000..15f7f1dd
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/fonts/symbol.php
@@ -0,0 +1,12 @@
1<?php
2// TCPDF FONT FILE DESCRIPTION
3$type='core';
4$name='Symbol';
5$up=-100;
6$ut=50;
7$dw=587;
8$diff='';
9$enc='';
10$desc=array('Flags'=>4,'FontBBox'=>'[-180 -293 1090 1010]','ItalicAngle'=>0,'Ascent'=>1010,'Descent'=>-293,'Leading'=>0,'CapHeight'=>1010,'StemV'=>85,'StemH'=>92,'AvgWidth'=>587,'MaxWidth'=>1042,'MissingWidth'=>587);
11$cw=array(0=>587,1=>587,2=>587,3=>587,4=>587,5=>587,6=>587,7=>587,8=>587,9=>587,10=>587,11=>587,12=>587,13=>587,14=>587,15=>587,16=>587,17=>587,18=>587,19=>587,20=>587,21=>587,22=>587,23=>587,24=>587,25=>587,26=>587,27=>587,28=>587,29=>587,30=>587,31=>587,32=>250,33=>333,34=>713,35=>500,36=>549,37=>833,38=>778,39=>439,40=>333,41=>333,42=>500,43=>549,44=>250,45=>549,46=>250,47=>278,48=>500,49=>500,50=>500,51=>500,52=>500,53=>500,54=>500,55=>500,56=>500,57=>500,58=>278,59=>278,60=>549,61=>549,62=>549,63=>444,64=>549,65=>722,66=>667,67=>722,68=>612,69=>611,70=>763,71=>603,72=>722,73=>333,74=>631,75=>722,76=>686,77=>889,78=>722,79=>722,80=>768,81=>741,82=>556,83=>592,84=>611,85=>690,86=>439,87=>768,88=>645,89=>795,90=>611,91=>333,92=>863,93=>333,94=>658,95=>500,96=>500,97=>631,98=>549,99=>549,100=>494,101=>439,102=>521,103=>411,104=>603,105=>329,106=>603,107=>549,108=>549,109=>576,110=>521,111=>549,112=>549,113=>521,114=>549,115=>603,116=>439,117=>576,118=>713,119=>686,120=>493,121=>686,122=>494,123=>480,124=>200,125=>480,126=>549,127=>587,128=>587,129=>587,130=>587,131=>587,132=>587,133=>587,134=>587,135=>587,136=>587,137=>587,138=>587,139=>587,140=>587,141=>587,142=>587,143=>587,144=>587,145=>587,146=>587,147=>587,148=>587,149=>587,150=>587,151=>587,152=>587,153=>587,154=>587,155=>587,156=>587,157=>587,158=>587,159=>587,160=>750,161=>620,162=>247,163=>549,164=>167,165=>713,166=>500,167=>753,168=>753,169=>753,170=>753,171=>1042,172=>987,173=>603,174=>987,175=>603,176=>400,177=>549,178=>411,179=>549,180=>549,181=>713,182=>494,183=>460,184=>549,185=>549,186=>549,187=>549,188=>1000,189=>603,190=>1000,191=>658,192=>823,193=>686,194=>795,195=>987,196=>768,197=>768,198=>823,199=>768,200=>768,201=>713,202=>713,203=>713,204=>713,205=>713,206=>713,207=>713,208=>768,209=>713,210=>790,211=>790,212=>890,213=>823,214=>549,215=>250,216=>713,217=>603,218=>603,219=>1042,220=>987,221=>603,222=>987,223=>603,224=>494,225=>329,226=>790,227=>790,228=>786,229=>713,230=>384,231=>384,232=>384,233=>384,234=>384,235=>384,236=>494,237=>494,238=>494,239=>494,240=>587,241=>329,242=>274,243=>686,244=>686,245=>686,246=>384,247=>384,248=>384,249=>384,250=>384,251=>384,252=>494,253=>494,254=>494,255=>587);
12// --- EOF ---
diff --git a/inc/3rdparty/libraries/tcpdf/fonts/times.php b/inc/3rdparty/libraries/tcpdf/fonts/times.php
new file mode 100644
index 00000000..cfcaf06c
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/fonts/times.php
@@ -0,0 +1,12 @@
1<?php
2// TCPDF FONT FILE DESCRIPTION
3$type='core';
4$name='Times-Roman';
5$up=-100;
6$ut=50;
7$dw=495;
8$diff='';
9$enc='';
10$desc=array('Flags'=>32,'FontBBox'=>'[-168 -218 1000 898]','ItalicAngle'=>0,'Ascent'=>898,'Descent'=>-218,'Leading'=>0,'CapHeight'=>662,'XHeight'=>450,'StemV'=>84,'StemH'=>28,'AvgWidth'=>495,'MaxWidth'=>1000,'MissingWidth'=>495);
11$cw=array(0=>250,1=>250,2=>250,3=>250,4=>250,5=>250,6=>250,7=>250,8=>250,9=>250,10=>250,11=>250,12=>250,13=>250,14=>250,15=>250,16=>250,17=>250,18=>250,19=>250,20=>250,21=>250,22=>250,23=>250,24=>250,25=>250,26=>250,27=>250,28=>250,29=>250,30=>250,31=>250,32=>250,33=>333,34=>408,35=>500,36=>500,37=>833,38=>778,39=>180,40=>333,41=>333,42=>500,43=>564,44=>250,45=>333,46=>250,47=>278,48=>500,49=>500,50=>500,51=>500,52=>500,53=>500,54=>500,55=>500,56=>500,57=>500,58=>278,59=>278,60=>564,61=>564,62=>564,63=>444,64=>921,65=>722,66=>667,67=>667,68=>722,69=>611,70=>556,71=>722,72=>722,73=>333,74=>389,75=>722,76=>611,77=>889,78=>722,79=>722,80=>556,81=>722,82=>667,83=>556,84=>611,85=>722,86=>722,87=>944,88=>722,89=>722,90=>611,91=>333,92=>278,93=>333,94=>469,95=>500,96=>333,97=>444,98=>500,99=>444,100=>500,101=>444,102=>333,103=>500,104=>500,105=>278,106=>278,107=>500,108=>278,109=>778,110=>500,111=>500,112=>500,113=>500,114=>333,115=>389,116=>278,117=>500,118=>500,119=>722,120=>500,121=>500,122=>444,123=>480,124=>200,125=>480,126=>541,127=>350,128=>500,129=>350,130=>333,131=>500,132=>444,133=>1000,134=>500,135=>500,136=>333,137=>1000,138=>556,139=>333,140=>889,141=>350,142=>611,143=>350,144=>350,145=>333,146=>333,147=>444,148=>444,149=>350,150=>500,151=>1000,152=>333,153=>980,154=>389,155=>333,156=>722,157=>350,158=>444,159=>722,160=>250,161=>333,162=>500,163=>500,164=>500,165=>500,166=>200,167=>500,168=>333,169=>760,170=>276,171=>500,172=>564,173=>333,174=>760,175=>333,176=>400,177=>564,178=>300,179=>300,180=>333,181=>500,182=>453,183=>250,184=>333,185=>300,186=>310,187=>500,188=>750,189=>750,190=>750,191=>444,192=>722,193=>722,194=>722,195=>722,196=>722,197=>722,198=>889,199=>667,200=>611,201=>611,202=>611,203=>611,204=>333,205=>333,206=>333,207=>333,208=>722,209=>722,210=>722,211=>722,212=>722,213=>722,214=>722,215=>564,216=>722,217=>722,218=>722,219=>722,220=>722,221=>722,222=>556,223=>500,224=>444,225=>444,226=>444,227=>444,228=>444,229=>444,230=>667,231=>444,232=>444,233=>444,234=>444,235=>444,236=>278,237=>278,238=>278,239=>278,240=>500,241=>500,242=>500,243=>500,244=>500,245=>500,246=>500,247=>564,248=>500,249=>500,250=>500,251=>500,252=>500,253=>500,254=>500,255=>500);
12// --- EOF ---
diff --git a/inc/3rdparty/libraries/tcpdf/fonts/timesb.php b/inc/3rdparty/libraries/tcpdf/fonts/timesb.php
new file mode 100644
index 00000000..9c41a7b5
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/fonts/timesb.php
@@ -0,0 +1,12 @@
1<?php
2// TCPDF FONT FILE DESCRIPTION
3$type='core';
4$name='Times-Bold';
5$up=-100;
6$ut=50;
7$dw=516;
8$diff='';
9$enc='';
10$desc=array('Flags'=>32,'FontBBox'=>'[-168 -218 1000 935]','ItalicAngle'=>0,'Ascent'=>935,'Descent'=>-218,'Leading'=>0,'CapHeight'=>676,'XHeight'=>461,'StemV'=>139,'StemH'=>44,'AvgWidth'=>516,'MaxWidth'=>1000,'MissingWidth'=>516);
11$cw=array(0=>250,1=>250,2=>250,3=>250,4=>250,5=>250,6=>250,7=>250,8=>250,9=>250,10=>250,11=>250,12=>250,13=>250,14=>250,15=>250,16=>250,17=>250,18=>250,19=>250,20=>250,21=>250,22=>250,23=>250,24=>250,25=>250,26=>250,27=>250,28=>250,29=>250,30=>250,31=>250,32=>250,33=>333,34=>555,35=>500,36=>500,37=>1000,38=>833,39=>278,40=>333,41=>333,42=>500,43=>570,44=>250,45=>333,46=>250,47=>278,48=>500,49=>500,50=>500,51=>500,52=>500,53=>500,54=>500,55=>500,56=>500,57=>500,58=>333,59=>333,60=>570,61=>570,62=>570,63=>500,64=>930,65=>722,66=>667,67=>722,68=>722,69=>667,70=>611,71=>778,72=>778,73=>389,74=>500,75=>778,76=>667,77=>944,78=>722,79=>778,80=>611,81=>778,82=>722,83=>556,84=>667,85=>722,86=>722,87=>1000,88=>722,89=>722,90=>667,91=>333,92=>278,93=>333,94=>581,95=>500,96=>333,97=>500,98=>556,99=>444,100=>556,101=>444,102=>333,103=>500,104=>556,105=>278,106=>333,107=>556,108=>278,109=>833,110=>556,111=>500,112=>556,113=>556,114=>444,115=>389,116=>333,117=>556,118=>500,119=>722,120=>500,121=>500,122=>444,123=>394,124=>220,125=>394,126=>520,127=>350,128=>500,129=>350,130=>333,131=>500,132=>500,133=>1000,134=>500,135=>500,136=>333,137=>1000,138=>556,139=>333,140=>1000,141=>350,142=>667,143=>350,144=>350,145=>333,146=>333,147=>500,148=>500,149=>350,150=>500,151=>1000,152=>333,153=>1000,154=>389,155=>333,156=>722,157=>350,158=>444,159=>722,160=>250,161=>333,162=>500,163=>500,164=>500,165=>500,166=>220,167=>500,168=>333,169=>747,170=>300,171=>500,172=>570,173=>333,174=>747,175=>333,176=>400,177=>570,178=>300,179=>300,180=>333,181=>556,182=>540,183=>250,184=>333,185=>300,186=>330,187=>500,188=>750,189=>750,190=>750,191=>500,192=>722,193=>722,194=>722,195=>722,196=>722,197=>722,198=>1000,199=>722,200=>667,201=>667,202=>667,203=>667,204=>389,205=>389,206=>389,207=>389,208=>722,209=>722,210=>778,211=>778,212=>778,213=>778,214=>778,215=>570,216=>778,217=>722,218=>722,219=>722,220=>722,221=>722,222=>611,223=>556,224=>500,225=>500,226=>500,227=>500,228=>500,229=>500,230=>722,231=>444,232=>444,233=>444,234=>444,235=>444,236=>278,237=>278,238=>278,239=>278,240=>500,241=>556,242=>500,243=>500,244=>500,245=>500,246=>500,247=>570,248=>500,249=>556,250=>556,251=>556,252=>556,253=>500,254=>556,255=>500);
12// --- EOF ---
diff --git a/inc/3rdparty/libraries/tcpdf/fonts/timesbi.php b/inc/3rdparty/libraries/tcpdf/fonts/timesbi.php
new file mode 100644
index 00000000..4feed748
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/fonts/timesbi.php
@@ -0,0 +1,12 @@
1<?php
2// TCPDF FONT FILE DESCRIPTION
3$type='core';
4$name='Times-BoldItalic';
5$up=-100;
6$ut=50;
7$dw=501;
8$diff='';
9$enc='';
10$desc=array('Flags'=>96,'FontBBox'=>'[-200 -218 996 921]','ItalicAngle'=>-15,'Ascent'=>921,'Descent'=>-218,'Leading'=>0,'CapHeight'=>669,'XHeight'=>462,'StemV'=>121,'StemH'=>42,'AvgWidth'=>501,'MaxWidth'=>1000,'MissingWidth'=>501);
11$cw=array(0=>250,1=>250,2=>250,3=>250,4=>250,5=>250,6=>250,7=>250,8=>250,9=>250,10=>250,11=>250,12=>250,13=>250,14=>250,15=>250,16=>250,17=>250,18=>250,19=>250,20=>250,21=>250,22=>250,23=>250,24=>250,25=>250,26=>250,27=>250,28=>250,29=>250,30=>250,31=>250,32=>250,33=>389,34=>555,35=>500,36=>500,37=>833,38=>778,39=>278,40=>333,41=>333,42=>500,43=>570,44=>250,45=>333,46=>250,47=>278,48=>500,49=>500,50=>500,51=>500,52=>500,53=>500,54=>500,55=>500,56=>500,57=>500,58=>333,59=>333,60=>570,61=>570,62=>570,63=>500,64=>832,65=>667,66=>667,67=>667,68=>722,69=>667,70=>667,71=>722,72=>778,73=>389,74=>500,75=>667,76=>611,77=>889,78=>722,79=>722,80=>611,81=>722,82=>667,83=>556,84=>611,85=>722,86=>667,87=>889,88=>667,89=>611,90=>611,91=>333,92=>278,93=>333,94=>570,95=>500,96=>333,97=>500,98=>500,99=>444,100=>500,101=>444,102=>333,103=>500,104=>556,105=>278,106=>278,107=>500,108=>278,109=>778,110=>556,111=>500,112=>500,113=>500,114=>389,115=>389,116=>278,117=>556,118=>444,119=>667,120=>500,121=>444,122=>389,123=>348,124=>220,125=>348,126=>570,127=>350,128=>500,129=>350,130=>333,131=>500,132=>500,133=>1000,134=>500,135=>500,136=>333,137=>1000,138=>556,139=>333,140=>944,141=>350,142=>611,143=>350,144=>350,145=>333,146=>333,147=>500,148=>500,149=>350,150=>500,151=>1000,152=>333,153=>1000,154=>389,155=>333,156=>722,157=>350,158=>389,159=>611,160=>250,161=>389,162=>500,163=>500,164=>500,165=>500,166=>220,167=>500,168=>333,169=>747,170=>266,171=>500,172=>606,173=>333,174=>747,175=>333,176=>400,177=>570,178=>300,179=>300,180=>333,181=>576,182=>500,183=>250,184=>333,185=>300,186=>300,187=>500,188=>750,189=>750,190=>750,191=>500,192=>667,193=>667,194=>667,195=>667,196=>667,197=>667,198=>944,199=>667,200=>667,201=>667,202=>667,203=>667,204=>389,205=>389,206=>389,207=>389,208=>722,209=>722,210=>722,211=>722,212=>722,213=>722,214=>722,215=>570,216=>722,217=>722,218=>722,219=>722,220=>722,221=>611,222=>611,223=>500,224=>500,225=>500,226=>500,227=>500,228=>500,229=>500,230=>722,231=>444,232=>444,233=>444,234=>444,235=>444,236=>278,237=>278,238=>278,239=>278,240=>500,241=>556,242=>500,243=>500,244=>500,245=>500,246=>500,247=>570,248=>500,249=>556,250=>556,251=>556,252=>556,253=>444,254=>500,255=>444);
12// --- EOF ---
diff --git a/inc/3rdparty/libraries/tcpdf/fonts/timesi.php b/inc/3rdparty/libraries/tcpdf/fonts/timesi.php
new file mode 100644
index 00000000..1e8b6734
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/fonts/timesi.php
@@ -0,0 +1,12 @@
1<?php
2// TCPDF FONT FILE DESCRIPTION
3$type='core';
4$name='Times-Italic';
5$up=-100;
6$ut=50;
7$dw=491;
8$diff='';
9$enc='';
10$desc=array('Flags'=>96,'FontBBox'=>'[-169 -217 1010 883]','ItalicAngle'=>-15.5,'Ascent'=>883,'Descent'=>-217,'Leading'=>0,'CapHeight'=>653,'XHeight'=>441,'StemV'=>76,'StemH'=>32,'AvgWidth'=>491,'MaxWidth'=>1000,'MissingWidth'=>491);
11$cw=array(0=>250,1=>250,2=>250,3=>250,4=>250,5=>250,6=>250,7=>250,8=>250,9=>250,10=>250,11=>250,12=>250,13=>250,14=>250,15=>250,16=>250,17=>250,18=>250,19=>250,20=>250,21=>250,22=>250,23=>250,24=>250,25=>250,26=>250,27=>250,28=>250,29=>250,30=>250,31=>250,32=>250,33=>333,34=>420,35=>500,36=>500,37=>833,38=>778,39=>214,40=>333,41=>333,42=>500,43=>675,44=>250,45=>333,46=>250,47=>278,48=>500,49=>500,50=>500,51=>500,52=>500,53=>500,54=>500,55=>500,56=>500,57=>500,58=>333,59=>333,60=>675,61=>675,62=>675,63=>500,64=>920,65=>611,66=>611,67=>667,68=>722,69=>611,70=>611,71=>722,72=>722,73=>333,74=>444,75=>667,76=>556,77=>833,78=>667,79=>722,80=>611,81=>722,82=>611,83=>500,84=>556,85=>722,86=>611,87=>833,88=>611,89=>556,90=>556,91=>389,92=>278,93=>389,94=>422,95=>500,96=>333,97=>500,98=>500,99=>444,100=>500,101=>444,102=>278,103=>500,104=>500,105=>278,106=>278,107=>444,108=>278,109=>722,110=>500,111=>500,112=>500,113=>500,114=>389,115=>389,116=>278,117=>500,118=>444,119=>667,120=>444,121=>444,122=>389,123=>400,124=>275,125=>400,126=>541,127=>350,128=>500,129=>350,130=>333,131=>500,132=>556,133=>889,134=>500,135=>500,136=>333,137=>1000,138=>500,139=>333,140=>944,141=>350,142=>556,143=>350,144=>350,145=>333,146=>333,147=>556,148=>556,149=>350,150=>500,151=>889,152=>333,153=>980,154=>389,155=>333,156=>667,157=>350,158=>389,159=>556,160=>250,161=>389,162=>500,163=>500,164=>500,165=>500,166=>275,167=>500,168=>333,169=>760,170=>276,171=>500,172=>675,173=>333,174=>760,175=>333,176=>400,177=>675,178=>300,179=>300,180=>333,181=>500,182=>523,183=>250,184=>333,185=>300,186=>310,187=>500,188=>750,189=>750,190=>750,191=>500,192=>611,193=>611,194=>611,195=>611,196=>611,197=>611,198=>889,199=>667,200=>611,201=>611,202=>611,203=>611,204=>333,205=>333,206=>333,207=>333,208=>722,209=>667,210=>722,211=>722,212=>722,213=>722,214=>722,215=>675,216=>722,217=>722,218=>722,219=>722,220=>722,221=>556,222=>611,223=>500,224=>500,225=>500,226=>500,227=>500,228=>500,229=>500,230=>667,231=>444,232=>444,233=>444,234=>444,235=>444,236=>278,237=>278,238=>278,239=>278,240=>500,241=>500,242=>500,243=>500,244=>500,245=>500,246=>500,247=>675,248=>500,249=>500,250=>500,251=>500,252=>500,253=>444,254=>500,255=>444);
12// --- EOF ---
diff --git a/inc/3rdparty/libraries/tcpdf/fonts/zapfdingbats.php b/inc/3rdparty/libraries/tcpdf/fonts/zapfdingbats.php
new file mode 100644
index 00000000..4c0bd75d
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/fonts/zapfdingbats.php
@@ -0,0 +1,12 @@
1<?php
2// TCPDF FONT FILE DESCRIPTION
3$type='core';
4$name='ZapfDingbats';
5$up=-100;
6$ut=50;
7$dw=746;
8$diff='';
9$enc='';
10$desc=array('Flags'=>4,'FontBBox'=>'[-1 -143 981 820]','ItalicAngle'=>0,'Ascent'=>820,'Descent'=>-143,'Leading'=>0,'CapHeight'=>820,'StemV'=>90,'StemH'=>28,'AvgWidth'=>746,'MaxWidth'=>1016,'MissingWidth'=>746);
11$cw=array(0=>746,1=>746,2=>746,3=>746,4=>746,5=>746,6=>746,7=>746,8=>746,9=>746,10=>746,11=>746,12=>746,13=>746,14=>746,15=>746,16=>746,17=>746,18=>746,19=>746,20=>746,21=>746,22=>746,23=>746,24=>746,25=>746,26=>746,27=>746,28=>746,29=>746,30=>746,31=>746,32=>278,33=>974,34=>961,35=>974,36=>980,37=>719,38=>789,39=>790,40=>791,41=>690,42=>960,43=>939,44=>549,45=>855,46=>911,47=>933,48=>911,49=>945,50=>974,51=>755,52=>846,53=>762,54=>761,55=>571,56=>677,57=>763,58=>760,59=>759,60=>754,61=>494,62=>552,63=>537,64=>577,65=>692,66=>786,67=>788,68=>788,69=>790,70=>793,71=>794,72=>816,73=>823,74=>789,75=>841,76=>823,77=>833,78=>816,79=>831,80=>923,81=>744,82=>723,83=>749,84=>790,85=>792,86=>695,87=>776,88=>768,89=>792,90=>759,91=>707,92=>708,93=>682,94=>701,95=>826,96=>815,97=>789,98=>789,99=>707,100=>687,101=>696,102=>689,103=>786,104=>787,105=>713,106=>791,107=>785,108=>791,109=>873,110=>761,111=>762,112=>762,113=>759,114=>759,115=>892,116=>892,117=>788,118=>784,119=>438,120=>138,121=>277,122=>415,123=>392,124=>392,125=>668,126=>668,127=>746,128=>390,129=>390,130=>317,131=>317,132=>276,133=>276,134=>509,135=>509,136=>410,137=>410,138=>234,139=>234,140=>334,141=>334,142=>746,143=>746,144=>746,145=>746,146=>746,147=>746,148=>746,149=>746,150=>746,151=>746,152=>746,153=>746,154=>746,155=>746,156=>746,157=>746,158=>746,159=>746,160=>746,161=>732,162=>544,163=>544,164=>910,165=>667,166=>760,167=>760,168=>776,169=>595,170=>694,171=>626,172=>788,173=>788,174=>788,175=>788,176=>788,177=>788,178=>788,179=>788,180=>788,181=>788,182=>788,183=>788,184=>788,185=>788,186=>788,187=>788,188=>788,189=>788,190=>788,191=>788,192=>788,193=>788,194=>788,195=>788,196=>788,197=>788,198=>788,199=>788,200=>788,201=>788,202=>788,203=>788,204=>788,205=>788,206=>788,207=>788,208=>788,209=>788,210=>788,211=>788,212=>894,213=>838,214=>1016,215=>458,216=>748,217=>924,218=>748,219=>918,220=>927,221=>928,222=>928,223=>834,224=>873,225=>828,226=>924,227=>924,228=>917,229=>930,230=>931,231=>463,232=>883,233=>836,234=>836,235=>867,236=>867,237=>696,238=>696,239=>874,240=>746,241=>874,242=>760,243=>946,244=>771,245=>865,246=>771,247=>888,248=>967,249=>888,250=>831,251=>873,252=>927,253=>970,254=>918,255=>746);
12// --- EOF ---
diff --git a/inc/3rdparty/libraries/tcpdf/include/barcodes/datamatrix.php b/inc/3rdparty/libraries/tcpdf/include/barcodes/datamatrix.php
new file mode 100644
index 00000000..c1067299
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/include/barcodes/datamatrix.php
@@ -0,0 +1,1176 @@
1<?php
2//============================================================+
3// File name : datamatrix.php
4// Version : 1.0.008
5// Begin : 2010-06-07
6// Last Update : 2014-05-06
7// Author : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com
8// License : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html)
9// -------------------------------------------------------------------
10// Copyright (C) 2010-2014 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 GNU Lesser General Public License
25// along with TCPDF. If not, see <http://www.gnu.org/licenses/>.
26//
27// See LICENSE.TXT file for more information.
28// -------------------------------------------------------------------
29//
30// DESCRIPTION :
31//
32// Class to create DataMatrix ECC 200 barcode arrays for TCPDF class.
33// DataMatrix (ISO/IEC 16022:2006) is a 2-dimensional bar code.
34//============================================================+
35
36/**
37* @file
38* Class to create DataMatrix ECC 200 barcode arrays for TCPDF class.
39* DataMatrix (ISO/IEC 16022:2006) is a 2-dimensional bar code.
40*
41* @package com.tecnick.tcpdf
42* @author Nicola Asuni
43* @version 1.0.008
44*/
45
46// custom definitions
47if (!defined('DATAMATRIXDEFS')) {
48
49 /**
50 * Indicate that definitions for this class are set
51 */
52 define('DATAMATRIXDEFS', true);
53
54 // -----------------------------------------------------
55
56} // end of custom definitions
57
58// #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
59
60
61/**
62* ASCII encoding: ASCII character 0 to 127 (1 byte per CW)
63*/
64define('ENC_ASCII', 0);
65
66/**
67* C40 encoding: Upper-case alphanumeric (3/2 bytes per CW)
68*/
69define('ENC_C40', 1);
70
71/**
72* TEXT encoding: Lower-case alphanumeric (3/2 bytes per CW)
73*/
74define('ENC_TXT', 2);
75
76/**
77* X12 encoding: ANSI X12 (3/2 byte per CW)
78*/
79define('ENC_X12', 3);
80
81/**
82* EDIFACT encoding: ASCII character 32 to 94 (4/3 bytes per CW)
83*/
84define('ENC_EDF', 4);
85
86/**
87* BASE 256 encoding: ASCII character 0 to 255 (1 byte per CW)
88*/
89define('ENC_BASE256', 5);
90
91/**
92* ASCII extended encoding: ASCII character 128 to 255 (1/2 byte per CW)
93*/
94define('ENC_ASCII_EXT', 6);
95
96/**
97* ASCII number encoding: ASCII digits (2 bytes per CW)
98*/
99define('ENC_ASCII_NUM', 7);
100
101/**
102* @class Datamatrix
103* Class to create DataMatrix ECC 200 barcode arrays for TCPDF class.
104* DataMatrix (ISO/IEC 16022:2006) is a 2-dimensional bar code.
105*
106* @package com.tecnick.tcpdf
107* @author Nicola Asuni
108* @version 1.0.004
109*/
110class Datamatrix {
111
112 /**
113 * Barcode array to be returned which is readable by TCPDF.
114 * @protected
115 */
116 protected $barcode_array = array();
117
118 /**
119 * Store last used encoding for data codewords.
120 * @protected
121 */
122 protected $last_enc = ENC_ASCII;
123
124 /**
125 * Table of Data Matrix ECC 200 Symbol Attributes:<ul>
126 * <li>total matrix rows (including finder pattern)</li>
127 * <li>total matrix cols (including finder pattern)</li>
128 * <li>total matrix rows (without finder pattern)</li>
129 * <li>total matrix cols (without finder pattern)</li>
130 * <li>region data rows (with finder pattern)</li>
131 * <li>region data col (with finder pattern)</li>
132 * <li>region data rows (without finder pattern)</li>
133 * <li>region data col (without finder pattern)</li>
134 * <li>horizontal regions</li>
135 * <li>vertical regions</li>
136 * <li>regions</li>
137 * <li>data codewords</li>
138 * <li>error codewords</li>
139 * <li>blocks</li>
140 * <li>data codewords per block</li>
141 * <li>error codewords per block</li>
142 * </ul>
143 * @protected
144 */
145 protected $symbattr = array(
146 // square form ---------------------------------------------------------------------------------------
147 array(0x00a,0x00a,0x008,0x008,0x00a,0x00a,0x008,0x008,0x001,0x001,0x001,0x003,0x005,0x001,0x003,0x005), // 10x10
148 array(0x00c,0x00c,0x00a,0x00a,0x00c,0x00c,0x00a,0x00a,0x001,0x001,0x001,0x005,0x007,0x001,0x005,0x007), // 12x12
149 array(0x00e,0x00e,0x00c,0x00c,0x00e,0x00e,0x00c,0x00c,0x001,0x001,0x001,0x008,0x00a,0x001,0x008,0x00a), // 14x14
150 array(0x010,0x010,0x00e,0x00e,0x010,0x010,0x00e,0x00e,0x001,0x001,0x001,0x00c,0x00c,0x001,0x00c,0x00c), // 16x16
151 array(0x012,0x012,0x010,0x010,0x012,0x012,0x010,0x010,0x001,0x001,0x001,0x012,0x00e,0x001,0x012,0x00e), // 18x18
152 array(0x014,0x014,0x012,0x012,0x014,0x014,0x012,0x012,0x001,0x001,0x001,0x016,0x012,0x001,0x016,0x012), // 20x20
153 array(0x016,0x016,0x014,0x014,0x016,0x016,0x014,0x014,0x001,0x001,0x001,0x01e,0x014,0x001,0x01e,0x014), // 22x22
154 array(0x018,0x018,0x016,0x016,0x018,0x018,0x016,0x016,0x001,0x001,0x001,0x024,0x018,0x001,0x024,0x018), // 24x24
155 array(0x01a,0x01a,0x018,0x018,0x01a,0x01a,0x018,0x018,0x001,0x001,0x001,0x02c,0x01c,0x001,0x02c,0x01c), // 26x26
156 array(0x020,0x020,0x01c,0x01c,0x010,0x010,0x00e,0x00e,0x002,0x002,0x004,0x03e,0x024,0x001,0x03e,0x024), // 32x32
157 array(0x024,0x024,0x020,0x020,0x012,0x012,0x010,0x010,0x002,0x002,0x004,0x056,0x02a,0x001,0x056,0x02a), // 36x36
158 array(0x028,0x028,0x024,0x024,0x014,0x014,0x012,0x012,0x002,0x002,0x004,0x072,0x030,0x001,0x072,0x030), // 40x40
159 array(0x02c,0x02c,0x028,0x028,0x016,0x016,0x014,0x014,0x002,0x002,0x004,0x090,0x038,0x001,0x090,0x038), // 44x44
160 array(0x030,0x030,0x02c,0x02c,0x018,0x018,0x016,0x016,0x002,0x002,0x004,0x0ae,0x044,0x001,0x0ae,0x044), // 48x48
161 array(0x034,0x034,0x030,0x030,0x01a,0x01a,0x018,0x018,0x002,0x002,0x004,0x0cc,0x054,0x002,0x066,0x02a), // 52x52
162 array(0x040,0x040,0x038,0x038,0x010,0x010,0x00e,0x00e,0x004,0x004,0x010,0x118,0x070,0x002,0x08c,0x038), // 64x64
163 array(0x048,0x048,0x040,0x040,0x012,0x012,0x010,0x010,0x004,0x004,0x010,0x170,0x090,0x004,0x05c,0x024), // 72x72
164 array(0x050,0x050,0x048,0x048,0x014,0x014,0x012,0x012,0x004,0x004,0x010,0x1c8,0x0c0,0x004,0x072,0x030), // 80x80
165 array(0x058,0x058,0x050,0x050,0x016,0x016,0x014,0x014,0x004,0x004,0x010,0x240,0x0e0,0x004,0x090,0x038), // 88x88
166 array(0x060,0x060,0x058,0x058,0x018,0x018,0x016,0x016,0x004,0x004,0x010,0x2b8,0x110,0x004,0x0ae,0x044), // 96x96
167 array(0x068,0x068,0x060,0x060,0x01a,0x01a,0x018,0x018,0x004,0x004,0x010,0x330,0x150,0x006,0x088,0x038), // 104x104
168 array(0x078,0x078,0x06c,0x06c,0x014,0x014,0x012,0x012,0x006,0x006,0x024,0x41a,0x198,0x006,0x0af,0x044), // 120x120
169 array(0x084,0x084,0x078,0x078,0x016,0x016,0x014,0x014,0x006,0x006,0x024,0x518,0x1f0,0x008,0x0a3,0x03e), // 132x132
170 array(0x090,0x090,0x084,0x084,0x018,0x018,0x016,0x016,0x006,0x006,0x024,0x616,0x26c,0x00a,0x09c,0x03e), // 144x144
171 // rectangular form (currently unused) ---------------------------------------------------------------------------
172 array(0x008,0x012,0x006,0x010,0x008,0x012,0x006,0x010,0x001,0x001,0x001,0x005,0x007,0x001,0x005,0x007), // 8x18
173 array(0x008,0x020,0x006,0x01c,0x008,0x010,0x006,0x00e,0x001,0x002,0x002,0x00a,0x00b,0x001,0x00a,0x00b), // 8x32
174 array(0x00c,0x01a,0x00a,0x018,0x00c,0x01a,0x00a,0x018,0x001,0x001,0x001,0x010,0x00e,0x001,0x010,0x00e), // 12x26
175 array(0x00c,0x024,0x00a,0x020,0x00c,0x012,0x00a,0x010,0x001,0x002,0x002,0x00c,0x012,0x001,0x00c,0x012), // 12x36
176 array(0x010,0x024,0x00e,0x020,0x010,0x012,0x00e,0x010,0x001,0x002,0x002,0x020,0x018,0x001,0x020,0x018), // 16x36
177 array(0x010,0x030,0x00e,0x02c,0x010,0x018,0x00e,0x016,0x001,0x002,0x002,0x031,0x01c,0x001,0x031,0x01c) // 16x48
178 );
179
180 /**
181 * Map encodation modes whit character sets.
182 * @protected
183 */
184 protected $chset_id = array(ENC_C40 => 'C40', ENC_TXT => 'TXT', ENC_X12 =>'X12');
185
186 /**
187 * Basic set of characters for each encodation mode.
188 * @protected
189 */
190 protected $chset = array(
191 'C40' => array( // Basic set for C40 ----------------------------------------------------------------------------
192 'S1'=>0x00,'S2'=>0x01,'S3'=>0x02,0x20=>0x03,0x30=>0x04,0x31=>0x05,0x32=>0x06,0x33=>0x07,0x34=>0x08,0x35=>0x09, //
193 0x36=>0x0a,0x37=>0x0b,0x38=>0x0c,0x39=>0x0d,0x41=>0x0e,0x42=>0x0f,0x43=>0x10,0x44=>0x11,0x45=>0x12,0x46=>0x13, //
194 0x47=>0x14,0x48=>0x15,0x49=>0x16,0x4a=>0x17,0x4b=>0x18,0x4c=>0x19,0x4d=>0x1a,0x4e=>0x1b,0x4f=>0x1c,0x50=>0x1d, //
195 0x51=>0x1e,0x52=>0x1f,0x53=>0x20,0x54=>0x21,0x55=>0x22,0x56=>0x23,0x57=>0x24,0x58=>0x25,0x59=>0x26,0x5a=>0x27),//
196 'TXT' => array( // Basic set for TEXT ---------------------------------------------------------------------------
197 'S1'=>0x00,'S2'=>0x01,'S3'=>0x02,0x20=>0x03,0x30=>0x04,0x31=>0x05,0x32=>0x06,0x33=>0x07,0x34=>0x08,0x35=>0x09, //
198 0x36=>0x0a,0x37=>0x0b,0x38=>0x0c,0x39=>0x0d,0x61=>0x0e,0x62=>0x0f,0x63=>0x10,0x64=>0x11,0x65=>0x12,0x66=>0x13, //
199 0x67=>0x14,0x68=>0x15,0x69=>0x16,0x6a=>0x17,0x6b=>0x18,0x6c=>0x19,0x6d=>0x1a,0x6e=>0x1b,0x6f=>0x1c,0x70=>0x1d, //
200 0x71=>0x1e,0x72=>0x1f,0x73=>0x20,0x74=>0x21,0x75=>0x22,0x76=>0x23,0x77=>0x24,0x78=>0x25,0x79=>0x26,0x7a=>0x27),//
201 'SH1' => array( // Shift 1 set ----------------------------------------------------------------------------------
202 0x00=>0x00,0x01=>0x01,0x02=>0x02,0x03=>0x03,0x04=>0x04,0x05=>0x05,0x06=>0x06,0x07=>0x07,0x08=>0x08,0x09=>0x09, //
203 0x0a=>0x0a,0x0b=>0x0b,0x0c=>0x0c,0x0d=>0x0d,0x0e=>0x0e,0x0f=>0x0f,0x10=>0x10,0x11=>0x11,0x12=>0x12,0x13=>0x13, //
204 0x14=>0x14,0x15=>0x15,0x16=>0x16,0x17=>0x17,0x18=>0x18,0x19=>0x19,0x1a=>0x1a,0x1b=>0x1b,0x1c=>0x1c,0x1d=>0x1d, //
205 0x1e=>0x1e,0x1f=>0x1f), //
206 'SH2' => array( // Shift 2 set ----------------------------------------------------------------------------------
207 0x21=>0x00,0x22=>0x01,0x23=>0x02,0x24=>0x03,0x25=>0x04,0x26=>0x05,0x27=>0x06,0x28=>0x07,0x29=>0x08,0x2a=>0x09, //
208 0x2b=>0x0a,0x2c=>0x0b,0x2d=>0x0c,0x2e=>0x0d,0x2f=>0x0e,0x3a=>0x0f,0x3b=>0x10,0x3c=>0x11,0x3d=>0x12,0x3e=>0x13, //
209 0x3f=>0x14,0x40=>0x15,0x5b=>0x16,0x5c=>0x17,0x5d=>0x18,0x5e=>0x19,0x5f=>0x1a,'F1'=>0x1b,'US'=>0x1e), //
210 'S3C' => array( // Shift 3 set for C40 --------------------------------------------------------------------------
211 0x60=>0x00,0x61=>0x01,0x62=>0x02,0x63=>0x03,0x64=>0x04,0x65=>0x05,0x66=>0x06,0x67=>0x07,0x68=>0x08,0x69=>0x09, //
212 0x6a=>0x0a,0x6b=>0x0b,0x6c=>0x0c,0x6d=>0x0d,0x6e=>0x0e,0x6f=>0x0f,0x70=>0x10,0x71=>0x11,0x72=>0x12,0x73=>0x13, //
213 0x74=>0x14,0x75=>0x15,0x76=>0x16,0x77=>0x17,0x78=>0x18,0x79=>0x19,0x7a=>0x1a,0x7b=>0x1b,0x7c=>0x1c,0x7d=>0x1d, //
214 0x7e=>0x1e,0x7f=>0x1f),
215 'S3T' => array( // Shift 3 set for TEXT -------------------------------------------------------------------------
216 0x60=>0x00,0x41=>0x01,0x42=>0x02,0x43=>0x03,0x44=>0x04,0x45=>0x05,0x46=>0x06,0x47=>0x07,0x48=>0x08,0x49=>0x09, //
217 0x4a=>0x0a,0x4b=>0x0b,0x4c=>0x0c,0x4d=>0x0d,0x4e=>0x0e,0x4f=>0x0f,0x50=>0x10,0x51=>0x11,0x52=>0x12,0x53=>0x13, //
218 0x54=>0x14,0x55=>0x15,0x56=>0x16,0x57=>0x17,0x58=>0x18,0x59=>0x19,0x5a=>0x1a,0x7b=>0x1b,0x7c=>0x1c,0x7d=>0x1d, //
219 0x7e=>0x1e,0x7f=>0x1f), //
220 'X12' => array( // Set for X12 ----------------------------------------------------------------------------------
221 0x0d=>0x00,0x2a=>0x01,0x3e=>0x02,0x20=>0x03,0x30=>0x04,0x31=>0x05,0x32=>0x06,0x33=>0x07,0x34=>0x08,0x35=>0x09, //
222 0x36=>0x0a,0x37=>0x0b,0x38=>0x0c,0x39=>0x0d,0x41=>0x0e,0x42=>0x0f,0x43=>0x10,0x44=>0x11,0x45=>0x12,0x46=>0x13, //
223 0x47=>0x14,0x48=>0x15,0x49=>0x16,0x4a=>0x17,0x4b=>0x18,0x4c=>0x19,0x4d=>0x1a,0x4e=>0x1b,0x4f=>0x1c,0x50=>0x1d, //
224 0x51=>0x1e,0x52=>0x1f,0x53=>0x20,0x54=>0x21,0x55=>0x22,0x56=>0x23,0x57=>0x24,0x58=>0x25,0x59=>0x26,0x5a=>0x27) //
225 );
226
227// -----------------------------------------------------------------------------
228
229 /**
230 * This is the class constructor.
231 * Creates a datamatrix object
232 * @param $code (string) Code to represent using Datamatrix.
233 * @public
234 */
235 public function __construct($code) {
236 $barcode_array = array();
237 if ((is_null($code)) OR ($code == '\0') OR ($code == '')) {
238 return false;
239 }
240 // get data codewords
241 $cw = $this->getHighLevelEncoding($code);
242 // number of data codewords
243 $nd = count($cw);
244 // check size
245 if ($nd > 1558) {
246 return false;
247 }
248 // get minimum required matrix size.
249 foreach ($this->symbattr as $params) {
250 if ($params[11] >= $nd) {
251 break;
252 }
253 }
254 if ($params[11] < $nd) {
255 // too much data
256 return false;
257 } elseif ($params[11] > $nd) {
258 // add padding
259 if ((($params[11] - $nd) > 1) AND ($cw[($nd - 1)] != 254)) {
260 if ($this->last_enc == ENC_EDF) {
261 // switch to ASCII encoding
262 $cw[] = 124;
263 ++$nd;
264 } elseif (($this->last_enc != ENC_ASCII) AND ($this->last_enc != ENC_BASE256)) {
265 // switch to ASCII encoding
266 $cw[] = 254;
267 ++$nd;
268 }
269 }
270 if ($params[11] > $nd) {
271 // add first pad
272 $cw[] = 129;
273 ++$nd;
274 // add remaining pads
275 for ($i = $nd; $i < $params[11]; ++$i) {
276 $cw[] = $this->get253StateCodeword(129, $i);
277 }
278 }
279 }
280 // add error correction codewords
281 $cw = $this->getErrorCorrection($cw, $params[13], $params[14], $params[15]);
282 // initialize empty arrays
283 $grid = array_fill(0, ($params[2] * $params[3]), 0);
284 // get placement map
285 $places = $this->getPlacementMap($params[2], $params[3]);
286 // fill the grid with data
287 $grid = array();
288 $i = 0;
289 // region data row max index
290 $rdri = ($params[4] - 1);
291 // region data column max index
292 $rdci = ($params[5] - 1);
293 // for each vertical region
294 for ($vr = 0; $vr < $params[9]; ++$vr) {
295 // for each row on region
296 for ($r = 0; $r < $params[4]; ++$r) {
297 // get row
298 $row = (($vr * $params[4]) + $r);
299 // for each horizontal region
300 for ($hr = 0; $hr < $params[8]; ++$hr) {
301 // for each column on region
302 for ($c = 0; $c < $params[5]; ++$c) {
303 // get column
304 $col = (($hr * $params[5]) + $c);
305 // braw bits by case
306 if ($r == 0) {
307 // top finder pattern
308 if ($c % 2) {
309 $grid[$row][$col] = 0;
310 } else {
311 $grid[$row][$col] = 1;
312 }
313 } elseif ($r == $rdri) {
314 // bottom finder pattern
315 $grid[$row][$col] = 1;
316 } elseif ($c == 0) {
317 // left finder pattern
318 $grid[$row][$col] = 1;
319 } elseif ($c == $rdci) {
320 // right finder pattern
321 if ($r % 2) {
322 $grid[$row][$col] = 1;
323 } else {
324 $grid[$row][$col] = 0;
325 }
326 } else { // data bit
327 if ($places[$i] < 2) {
328 $grid[$row][$col] = $places[$i];
329 } else {
330 // codeword ID
331 $cw_id = (floor($places[$i] / 10) - 1);
332 // codeword BIT mask
333 $cw_bit = pow(2, (8 - ($places[$i] % 10)));
334 $grid[$row][$col] = (($cw[$cw_id] & $cw_bit) == 0) ? 0 : 1;
335 }
336 ++$i;
337 }
338 }
339 }
340 }
341 }
342 $this->barcode_array['num_rows'] = $params[0];
343 $this->barcode_array['num_cols'] = $params[1];
344 $this->barcode_array['bcode'] = $grid;
345 }
346
347 /**
348 * Returns a barcode array which is readable by TCPDF
349 * @return array barcode array readable by TCPDF;
350 * @public
351 */
352 public function getBarcodeArray() {
353 return $this->barcode_array;
354 }
355
356 /**
357 * Product of two numbers in a Power-of-Two Galois Field
358 * @param $a (int) first number to multiply.
359 * @param $b (int) second number to multiply.
360 * @param $log (array) Log table.
361 * @param $alog (array) Anti-Log table.
362 * @param $gf (array) Number of Factors of the Reed-Solomon polynomial.
363 * @return int product
364 * @protected
365 */
366 protected function getGFProduct($a, $b, $log, $alog, $gf) {
367 if (($a == 0) OR ($b == 0)) {
368 return 0;
369 }
370 return ($alog[($log[$a] + $log[$b]) % ($gf - 1)]);
371 }
372
373 /**
374 * Add error correction codewords to data codewords array (ANNEX E).
375 * @param $wd (array) Array of datacodewords.
376 * @param $nb (int) Number of blocks.
377 * @param $nd (int) Number of data codewords per block.
378 * @param $nc (int) Number of correction codewords per block.
379 * @param $gf (int) numner of fields on log/antilog table (power of 2).
380 * @param $pp (int) The value of its prime modulus polynomial (301 for ECC200).
381 * @return array data codewords + error codewords
382 * @protected
383 */
384 protected function getErrorCorrection($wd, $nb, $nd, $nc, $gf=256, $pp=301) {
385 // generate the log ($log) and antilog ($alog) tables
386 $log[0] = 0;
387 $alog[0] = 1;
388 for ($i = 1; $i < $gf; ++$i) {
389 $alog[$i] = ($alog[($i - 1)] * 2);
390 if ($alog[$i] >= $gf) {
391 $alog[$i] ^= $pp;
392 }
393 $log[$alog[$i]] = $i;
394 }
395 ksort($log);
396 // generate the polynomial coefficients (c)
397 $c = array_fill(0, ($nc + 1), 0);
398 $c[0] = 1;
399 for ($i = 1; $i <= $nc; ++$i) {
400 $c[$i] = $c[($i-1)];
401 for ($j = ($i - 1); $j >= 1; --$j) {
402 $c[$j] = $c[($j - 1)] ^ $this->getGFProduct($c[$j], $alog[$i], $log, $alog, $gf);
403 }
404 $c[0] = $this->getGFProduct($c[0], $alog[$i], $log, $alog, $gf);
405 }
406 ksort($c);
407 // total number of data codewords
408 $num_wd = ($nb * $nd);
409 // total number of error codewords
410 $num_we = ($nb * $nc);
411 // for each block
412 for ($b = 0; $b < $nb; ++$b) {
413 // create interleaved data block
414 $block = array();
415 for ($n = $b; $n < $num_wd; $n += $nb) {
416 $block[] = $wd[$n];
417 }
418 // initialize error codewords
419 $we = array_fill(0, ($nc + 1), 0);
420 // calculate error correction codewords for this block
421 for ($i = 0; $i < $nd; ++$i) {
422 $k = ($we[0] ^ $block[$i]);
423 for ($j = 0; $j < $nc; ++$j) {
424 $we[$j] = ($we[($j + 1)] ^ $this->getGFProduct($k, $c[($nc - $j - 1)], $log, $alog, $gf));
425 }
426 }
427 // add error codewords at the end of data codewords
428 $j = 0;
429 for ($i = $b; $i < $num_we; $i += $nb) {
430 $wd[($num_wd + $i)] = $we[$j];
431 ++$j;
432 }
433 }
434 // reorder codewords
435 ksort($wd);
436 return $wd;
437 }
438
439 /**
440 * Return the 253-state codeword
441 * @param $cwpad (int) Pad codeword.
442 * @param $cwpos (int) Number of data codewords from the beginning of encoded data.
443 * @return pad codeword
444 * @protected
445 */
446 protected function get253StateCodeword($cwpad, $cwpos) {
447 $pad = ($cwpad + (((149 * $cwpos) % 253) + 1));
448 if ($pad > 254) {
449 $pad -= 254;
450 }
451 return $pad;
452 }
453
454 /**
455 * Return the 255-state codeword
456 * @param $cwpad (int) Pad codeword.
457 * @param $cwpos (int) Number of data codewords from the beginning of encoded data.
458 * @return pad codeword
459 * @protected
460 */
461 protected function get255StateCodeword($cwpad, $cwpos) {
462 $pad = ($cwpad + (((149 * $cwpos) % 255) + 1));
463 if ($pad > 255) {
464 $pad -= 256;
465 }
466 return $pad;
467 }
468
469 /**
470 * Returns true if the char belongs to the selected mode
471 * @param $chr (int) Character (byte) to check.
472 * @param $mode (int) Current encoding mode.
473 * @return boolean true if the char is of the selected mode.
474 * @protected
475 */
476 protected function isCharMode($chr, $mode) {
477 $status = false;
478 switch ($mode) {
479 case ENC_ASCII: { // ASCII character 0 to 127
480 $status = (($chr >= 0) AND ($chr <= 127));
481 break;
482 }
483 case ENC_C40: { // Upper-case alphanumeric
484 $status = (($chr == 32) OR (($chr >= 48) AND ($chr <= 57)) OR (($chr >= 65) AND ($chr <= 90)));
485 break;
486 }
487 case ENC_TXT: { // Lower-case alphanumeric
488 $status = (($chr == 32) OR (($chr >= 48) AND ($chr <= 57)) OR (($chr >= 97) AND ($chr <= 122)));
489 break;
490 }
491 case ENC_X12: { // ANSI X12
492 $status = (($chr == 13) OR ($chr == 42) OR ($chr == 62));
493 break;
494 }
495 case ENC_EDF: { // ASCII character 32 to 94
496 $status = (($chr >= 32) AND ($chr <= 94));
497 break;
498 }
499 case ENC_BASE256: { // Function character (FNC1, Structured Append, Reader Program, or Code Page)
500 $status = (($chr == 232) OR ($chr == 233) OR ($chr == 234) OR ($chr == 241));
501 break;
502 }
503 case ENC_ASCII_EXT: { // ASCII character 128 to 255
504 $status = (($chr >= 128) AND ($chr <= 255));
505 break;
506 }
507 case ENC_ASCII_NUM: { // ASCII digits
508 $status = (($chr >= 48) AND ($chr <= 57));
509 break;
510 }
511 }
512 return $status;
513 }
514
515 /**
516 * The look-ahead test scans the data to be encoded to find the best mode (Annex P - steps from J to S).
517 * @param $data (string) data to encode
518 * @param $pos (int) current position
519 * @param $mode (int) current encoding mode
520 * @return int encoding mode
521 * @protected
522 */
523 protected function lookAheadTest($data, $pos, $mode) {
524 $data_length = strlen($data);
525 if ($pos >= $data_length) {
526 return $mode;
527 }
528 $charscount = 0; // count processed chars
529 // STEP J
530 if ($mode == ENC_ASCII) {
531 $numch = array(0, 1, 1, 1, 1, 1.25);
532 } else {
533 $numch = array(1, 2, 2, 2, 2, 2.25);
534 $numch[$mode] = 0;
535 }
536 while (true) {
537 // STEP K
538 if (($pos + $charscount) == $data_length) {
539 if ($numch[ENC_ASCII] <= ceil(min($numch[ENC_C40], $numch[ENC_TXT], $numch[ENC_X12], $numch[ENC_EDF], $numch[ENC_BASE256]))) {
540 return ENC_ASCII;
541 }
542 if ($numch[ENC_BASE256] < ceil(min($numch[ENC_ASCII], $numch[ENC_C40], $numch[ENC_TXT], $numch[ENC_X12], $numch[ENC_EDF]))) {
543 return ENC_BASE256;
544 }
545 if ($numch[ENC_EDF] < ceil(min($numch[ENC_ASCII], $numch[ENC_C40], $numch[ENC_TXT], $numch[ENC_X12], $numch[ENC_BASE256]))) {
546 return ENC_EDF;
547 }
548 if ($numch[ENC_TXT] < ceil(min($numch[ENC_ASCII], $numch[ENC_C40], $numch[ENC_X12], $numch[ENC_EDF], $numch[ENC_BASE256]))) {
549 return ENC_TXT;
550 }
551 if ($numch[ENC_X12] < ceil(min($numch[ENC_ASCII], $numch[ENC_C40], $numch[ENC_TXT], $numch[ENC_EDF], $numch[ENC_BASE256]))) {
552 return ENC_X12;
553 }
554 return ENC_C40;
555 }
556 // get char
557 $chr = ord($data[$pos + $charscount]);
558 $charscount++;
559 // STEP L
560 if ($this->isCharMode($chr, ENC_ASCII_NUM)) {
561 $numch[ENC_ASCII] += (1 / 2);
562 } elseif ($this->isCharMode($chr, ENC_ASCII_EXT)) {
563 $numch[ENC_ASCII] = ceil($numch[ENC_ASCII]);
564 $numch[ENC_ASCII] += 2;
565 } else {
566 $numch[ENC_ASCII] = ceil($numch[ENC_ASCII]);
567 $numch[ENC_ASCII] += 1;
568 }
569 // STEP M
570 if ($this->isCharMode($chr, ENC_C40)) {
571 $numch[ENC_C40] += (2 / 3);
572 } elseif ($this->isCharMode($chr, ENC_ASCII_EXT)) {
573 $numch[ENC_C40] += (8 / 3);
574 } else {
575 $numch[ENC_C40] += (4 / 3);
576 }
577 // STEP N
578 if ($this->isCharMode($chr, ENC_TXT)) {
579 $numch[ENC_TXT] += (2 / 3);
580 } elseif ($this->isCharMode($chr, ENC_ASCII_EXT)) {
581 $numch[ENC_TXT] += (8 / 3);
582 } else {
583 $numch[ENC_TXT] += (4 / 3);
584 }
585 // STEP O
586 if ($this->isCharMode($chr, ENC_X12) OR $this->isCharMode($chr, ENC_C40)) {
587 $numch[ENC_X12] += (2 / 3);
588 } elseif ($this->isCharMode($chr, ENC_ASCII_EXT)) {
589 $numch[ENC_X12] += (13 / 3);
590 } else {
591 $numch[ENC_X12] += (10 / 3);
592 }
593 // STEP P
594 if ($this->isCharMode($chr, ENC_EDF)) {
595 $numch[ENC_EDF] += (3 / 4);
596 } elseif ($this->isCharMode($chr, ENC_ASCII_EXT)) {
597 $numch[ENC_EDF] += (17 / 4);
598 } else {
599 $numch[ENC_EDF] += (13 / 4);
600 }
601 // STEP Q
602 if ($this->isCharMode($chr, ENC_BASE256)) {
603 $numch[ENC_BASE256] += 4;
604 } else {
605 $numch[ENC_BASE256] += 1;
606 }
607 // STEP R
608 if ($charscount >= 4) {
609 if (($numch[ENC_ASCII] + 1) <= min($numch[ENC_C40], $numch[ENC_TXT], $numch[ENC_X12], $numch[ENC_EDF], $numch[ENC_BASE256])) {
610 return ENC_ASCII;
611 }
612 if ((($numch[ENC_BASE256] + 1) <= $numch[ENC_ASCII])
613 OR (($numch[ENC_BASE256] + 1) < min($numch[ENC_C40], $numch[ENC_TXT], $numch[ENC_X12], $numch[ENC_EDF]))) {
614 return ENC_BASE256;
615 }
616 if (($numch[ENC_EDF] + 1) < min($numch[ENC_ASCII], $numch[ENC_C40], $numch[ENC_TXT], $numch[ENC_X12], $numch[ENC_BASE256])) {
617 return ENC_EDF;
618 }
619 if (($numch[ENC_TXT] + 1) < min($numch[ENC_ASCII], $numch[ENC_C40], $numch[ENC_X12], $numch[ENC_EDF], $numch[ENC_BASE256])) {
620 return ENC_TXT;
621 }
622 if (($numch[ENC_X12] + 1) < min($numch[ENC_ASCII], $numch[ENC_C40], $numch[ENC_TXT], $numch[ENC_EDF], $numch[ENC_BASE256])) {
623 return ENC_X12;
624 }
625 if (($numch[ENC_C40] + 1) < min($numch[ENC_ASCII], $numch[ENC_TXT], $numch[ENC_EDF], $numch[ENC_BASE256])) {
626 if ($numch[ENC_C40] < $numch[ENC_X12]) {
627 return ENC_C40;
628 }
629 if ($numch[ENC_C40] == $numch[ENC_X12]) {
630 $k = ($pos + $charscount + 1);
631 while ($k < $data_length) {
632 $tmpchr = ord($data{$k});
633 if ($this->isCharMode($tmpchr, ENC_X12)) {
634 return ENC_X12;
635 } elseif (!($this->isCharMode($tmpchr, ENC_X12) OR $this->isCharMode($tmpchr, ENC_C40))) {
636 break;
637 }
638 ++$k;
639 }
640 return ENC_C40;
641 }
642 }
643 }
644 } // end of while
645 }
646
647 /**
648 * Get the switching codeword to a new encoding mode (latch codeword)
649 * @param $mode (int) New encoding mode.
650 * @return (int) Switch codeword.
651 * @protected
652 */
653 protected function getSwitchEncodingCodeword($mode) {
654 switch ($mode) {
655 case ENC_ASCII: { // ASCII character 0 to 127
656 $cw = 254;
657 if ($this->last_enc == ENC_EDF) {
658 $cw = 124;
659 }
660 break;
661 }
662 case ENC_C40: { // Upper-case alphanumeric
663 $cw = 230;
664 break;
665 }
666 case ENC_TXT: { // Lower-case alphanumeric
667 $cw = 239;
668 break;
669 }
670 case ENC_X12: { // ANSI X12
671 $cw = 238;
672 break;
673 }
674 case ENC_EDF: { // ASCII character 32 to 94
675 $cw = 240;
676 break;
677 }
678 case ENC_BASE256: { // Function character (FNC1, Structured Append, Reader Program, or Code Page)
679 $cw = 231;
680 break;
681 }
682 }
683 return $cw;
684 }
685
686 /**
687 * Choose the minimum matrix size and return the max number of data codewords.
688 * @param $numcw (int) Number of current codewords.
689 * @return number of data codewords in matrix
690 * @protected
691 */
692 protected function getMaxDataCodewords($numcw) {
693 foreach ($this->symbattr as $key => $matrix) {
694 if ($matrix[11] >= $numcw) {
695 return $matrix[11];
696 }
697 }
698 return 0;
699 }
700
701 /**
702 * Get high level encoding using the minimum symbol data characters for ECC 200
703 * @param $data (string) data to encode
704 * @return array of codewords
705 * @protected
706 */
707 protected function getHighLevelEncoding($data) {
708 // STEP A. Start in ASCII encodation.
709 $enc = ENC_ASCII; // current encoding mode
710 $pos = 0; // current position
711 $cw = array(); // array of codewords to be returned
712 $cw_num = 0; // number of data codewords
713 $data_lenght = strlen($data); // number of chars
714 while ($pos < $data_lenght) {
715 // set last used encoding
716 $this->last_enc = $enc;
717 switch ($enc) {
718 case ENC_ASCII: { // STEP B. While in ASCII encodation
719 if (($data_lenght > 1) AND ($pos < ($data_lenght - 1)) AND ($this->isCharMode(ord($data[$pos]), ENC_ASCII_NUM) AND $this->isCharMode(ord($data[$pos + 1]), ENC_ASCII_NUM))) {
720 // 1. If the next data sequence is at least 2 consecutive digits, encode the next two digits as a double digit in ASCII mode.
721 $cw[] = (intval(substr($data, $pos, 2)) + 130);
722 ++$cw_num;
723 $pos += 2;
724 } else {
725 // 2. If the look-ahead test (starting at step J) indicates another mode, switch to that mode.
726 $newenc = $this->lookAheadTest($data, $pos, $enc);
727 if ($newenc != $enc) {
728 // switch to new encoding
729 $enc = $newenc;
730 $cw[] = $this->getSwitchEncodingCodeword($enc);
731 ++$cw_num;
732 } else {
733 // get new byte
734 $chr = ord($data[$pos]);
735 ++$pos;
736 if ($this->isCharMode($chr, ENC_ASCII_EXT)) {
737 // 3. If the next data character is extended ASCII (greater than 127) encode it in ASCII mode first using the Upper Shift (value 235) character.
738 $cw[] = 235;
739 $cw[] = ($chr - 127);
740 $cw_num += 2;
741 } else {
742 // 4. Otherwise process the next data character in ASCII encodation.
743 $cw[] = ($chr + 1);
744 ++$cw_num;
745 }
746 }
747 }
748 break;
749 }
750 case ENC_C40 : // Upper-case alphanumeric
751 case ENC_TXT : // Lower-case alphanumeric
752 case ENC_X12 : { // ANSI X12
753 $temp_cw = array();
754 $p = 0;
755 $epos = $pos;
756 // get charset ID
757 $set_id = $this->chset_id[$enc];
758 // get basic charset for current encoding
759 $charset = $this->chset[$set_id];
760 do {
761 // 2. process the next character in C40 encodation.
762 $chr = ord($data[$epos]);
763 ++$epos;
764 // check for extended character
765 if ($chr & 0x80) {
766 if ($enc == ENC_X12) {
767 return false;
768 }
769 $chr = ($chr & 0x7f);
770 $temp_cw[] = 1; // shift 2
771 $temp_cw[] = 30; // upper shift
772 $p += 2;
773 }
774 if (isset($charset[$chr])) {
775 $temp_cw[] = $charset[$chr];
776 ++$p;
777 } else {
778 if (isset($this->chset['SH1'][$chr])) {
779 $temp_cw[] = 0; // shift 1
780 $shiftset = $this->chset['SH1'];
781 } elseif (isset($chr, $this->chset['SH2'][$chr])) {
782 $temp_cw[] = 1; // shift 2
783 $shiftset = $this->chset['SH2'];
784 } elseif (($enc == ENC_C40) AND isset($this->chset['S3C'][$chr])) {
785 $temp_cw[] = 2; // shift 3
786 $shiftset = $this->chset['S3C'];
787 } elseif (($enc == ENC_TXT) AND isset($this->chset['S3T'][$chr])) {
788 $temp_cw[] = 2; // shift 3
789 $shiftset = $this->chset['S3T'];
790 } else {
791 return false;
792 }
793 $temp_cw[] = $shiftset[$chr];
794 $p += 2;
795 }
796 if ($p >= 3) {
797 $c1 = array_shift($temp_cw);
798 $c2 = array_shift($temp_cw);
799 $c3 = array_shift($temp_cw);
800 $p -= 3;
801 $tmp = ((1600 * $c1) + (40 * $c2) + $c3 + 1);
802 $cw[] = ($tmp >> 8);
803 $cw[] = ($tmp % 256);
804 $cw_num += 2;
805 $pos = $epos;
806 // 1. If the C40 encoding is at the point of starting a new double symbol character and if the look-ahead test (starting at step J) indicates another mode, switch to that mode.
807 $newenc = $this->lookAheadTest($data, $pos, $enc);
808 if ($newenc != $enc) {
809 // switch to new encoding
810 $enc = $newenc;
811 if ($enc != ENC_ASCII) {
812 // set unlatch character
813 $cw[] = $this->getSwitchEncodingCodeword(ENC_ASCII);
814 ++$cw_num;
815 }
816 $cw[] = $this->getSwitchEncodingCodeword($enc);
817 ++$cw_num;
818 $pos -= $p;
819 $p = 0;
820 break;
821 }
822 }
823 } while (($p > 0) AND ($epos < $data_lenght));
824 // process last data (if any)
825 if ($p > 0) {
826 // get remaining number of data symbols
827 $cwr = ($this->getMaxDataCodewords($cw_num) - $cw_num);
828 if (($cwr == 1) AND ($p == 1)) {
829 // d. If one symbol character remains and one C40 value (data character) remains to be encoded
830 $c1 = array_shift($temp_cw);
831 --$p;
832 $cw[] = ($chr + 1);
833 ++$cw_num;
834 $pos = $epos;
835 $enc = ENC_ASCII;
836 $this->last_enc = $enc;
837 } elseif (($cwr == 2) AND ($p == 1)) {
838 // c. If two symbol characters remain and only one C40 value (data character) remains to be encoded
839 $c1 = array_shift($temp_cw);
840 --$p;
841 $cw[] = 254;
842 $cw[] = ($chr + 1);
843 $cw_num += 2;
844 $pos = $epos;
845 $enc = ENC_ASCII;
846 $this->last_enc = $enc;
847 } elseif (($cwr == 2) AND ($p == 2)) {
848 // b. If two symbol characters remain and two C40 values remain to be encoded
849 $c1 = array_shift($temp_cw);
850 $c2 = array_shift($temp_cw);
851 $p -= 2;
852 $tmp = ((1600 * $c1) + (40 * $c2) + 1);
853 $cw[] = ($tmp >> 8);
854 $cw[] = ($tmp % 256);
855 $cw_num += 2;
856 $pos = $epos;
857 $enc = ENC_ASCII;
858 $this->last_enc = $enc;
859 } else {
860 // switch to ASCII encoding
861 if ($enc != ENC_ASCII) {
862 $enc = ENC_ASCII;
863 $this->last_enc = $enc;
864 $cw[] = $this->getSwitchEncodingCodeword($enc);
865 ++$cw_num;
866 $pos = ($epos - $p);
867 }
868 }
869 }
870 break;
871 }
872 case ENC_EDF: { // F. While in EDIFACT (EDF) encodation
873 // initialize temporary array with 0 lenght
874 $temp_cw = array();
875 $epos = $pos;
876 $field_lenght = 0;
877 $newenc = $enc;
878 do {
879 // 2. process the next character in EDIFACT encodation.
880 $chr = ord($data[$epos]);
881 if ($this->isCharMode($chr, ENC_EDF)) {
882 ++$epos;
883 $temp_cw[] = $chr;
884 ++$field_lenght;
885 }
886 if (($field_lenght == 4) OR ($epos == $data_lenght) OR !$this->isCharMode($chr, ENC_EDF)) {
887 if (($epos == $data_lenght) AND ($field_lenght < 3)) {
888 $enc = ENC_ASCII;
889 $cw[] = $this->getSwitchEncodingCodeword($enc);
890 ++$cw_num;
891 break;
892 }
893 if ($field_lenght < 4) {
894 // set unlatch character
895 $temp_cw[] = 0x1f;
896 ++$field_lenght;
897 // fill empty characters
898 for ($i = $field_lenght; $i < 4; ++$i) {
899 $temp_cw[] = 0;
900 }
901 $enc = ENC_ASCII;
902 $this->last_enc = $enc;
903 }
904 // encodes four data characters in three codewords
905 $tcw = (($temp_cw[0] & 0x3F) << 2) + (($temp_cw[1] & 0x30) >> 4);
906 if ($tcw > 0) {
907 $cw[] = $tcw;
908 $cw_num++;
909 }
910 $tcw= (($temp_cw[1] & 0x0F) << 4) + (($temp_cw[2] & 0x3C) >> 2);
911 if ($tcw > 0) {
912 $cw[] = $tcw;
913 $cw_num++;
914 }
915 $tcw = (($temp_cw[2] & 0x03) << 6) + ($temp_cw[3] & 0x3F);
916 if ($tcw > 0) {
917 $cw[] = $tcw;
918 $cw_num++;
919 }
920 $temp_cw = array();
921 $pos = $epos;
922 $field_lenght = 0;
923 if ($enc == ENC_ASCII) {
924 break; // exit from EDIFACT mode
925 }
926 }
927 } while ($epos < $data_lenght);
928 break;
929 }
930 case ENC_BASE256: { // G. While in Base 256 (B256) encodation
931 // initialize temporary array with 0 lenght
932 $temp_cw = array();
933 $field_lenght = 0;
934 while (($pos < $data_lenght) AND ($field_lenght <= 1555)) {
935 $newenc = $this->lookAheadTest($data, $pos, $enc);
936 if ($newenc != $enc) {
937 // 1. If the look-ahead test (starting at step J) indicates another mode, switch to that mode.
938 $enc = $newenc;
939 break; // exit from B256 mode
940 } else {
941 // 2. Otherwise, process the next character in Base 256 encodation.
942 $chr = ord($data[$pos]);
943 ++$pos;
944 $temp_cw[] = $chr;
945 ++$field_lenght;
946 }
947 }
948 // set field lenght
949 if ($field_lenght <= 249) {
950 $cw[] = $this->get255StateCodeword($field_lenght, ($cw_num + 1));
951 ++$cw_num;
952 } else {
953 $cw[] = $this->get255StateCodeword((floor($field_lenght / 250) + 249), ($cw_num + 1));
954 $cw[] = $this->get255StateCodeword(($field_lenght % 250), ($cw_num + 2));
955 $cw_num += 2;
956 }
957 if (!empty($temp_cw)) {
958 // add B256 field
959 foreach ($temp_cw as $p => $cht) {
960 $cw[] = $this->get255StateCodeword($cht, ($cw_num + $p + 1));
961 }
962 }
963 break;
964 }
965 } // end of switch enc
966 } // end of while
967 return $cw;
968 }
969
970 /**
971 * Places "chr+bit" with appropriate wrapping within array[].
972 * (Annex F - ECC 200 symbol character placement)
973 * @param $marr (array) Array of symbols.
974 * @param $nrow (int) Number of rows.
975 * @param $ncol (int) Number of columns.
976 * @param $row (int) Row number.
977 * @param $col (int) Column number.
978 * @param $chr (int) Char byte.
979 * @param $bit (int) Bit.
980 * @return array
981 * @protected
982 */
983 protected function placeModule($marr, $nrow, $ncol, $row, $col, $chr, $bit) {
984 if ($row < 0) {
985 $row += $nrow;
986 $col += (4 - (($nrow + 4) % 8));
987 }
988 if ($col < 0) {
989 $col += $ncol;
990 $row += (4 - (($ncol + 4) % 8));
991 }
992 $marr[(($row * $ncol) + $col)] = ((10 * $chr) + $bit);
993 return $marr;
994 }
995
996 /**
997 * Places the 8 bits of a utah-shaped symbol character.
998 * (Annex F - ECC 200 symbol character placement)
999 * @param $marr (array) Array of symbols.
1000 * @param $nrow (int) Number of rows.
1001 * @param $ncol (int) Number of columns.
1002 * @param $row (int) Row number.
1003 * @param $col (int) Column number.
1004 * @param $chr (int) Char byte.
1005 * @return array
1006 * @protected
1007 */
1008 protected function placeUtah($marr, $nrow, $ncol, $row, $col, $chr) {
1009 $marr = $this->placeModule($marr, $nrow, $ncol, $row-2, $col-2, $chr, 1);
1010 $marr = $this->placeModule($marr, $nrow, $ncol, $row-2, $col-1, $chr, 2);
1011 $marr = $this->placeModule($marr, $nrow, $ncol, $row-1, $col-2, $chr, 3);
1012 $marr = $this->placeModule($marr, $nrow, $ncol, $row-1, $col-1, $chr, 4);
1013 $marr = $this->placeModule($marr, $nrow, $ncol, $row-1, $col, $chr, 5);
1014 $marr = $this->placeModule($marr, $nrow, $ncol, $row, $col-2, $chr, 6);
1015 $marr = $this->placeModule($marr, $nrow, $ncol, $row, $col-1, $chr, 7);
1016 $marr = $this->placeModule($marr, $nrow, $ncol, $row, $col, $chr, 8);
1017 return $marr;
1018 }
1019
1020 /**
1021 * Places the 8 bits of the first special corner case.
1022 * (Annex F - ECC 200 symbol character placement)
1023 * @param $marr (array) Array of symbols.
1024 * @param $nrow (int) Number of rows.
1025 * @param $ncol (int) Number of columns.
1026 * @param $chr (int) Char byte.
1027 * @return array
1028 * @protected
1029 */
1030 protected function placeCornerA($marr, $nrow, $ncol, $chr) {
1031 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 0, $chr, 1);
1032 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 1, $chr, 2);
1033 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 2, $chr, 3);
1034 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-2, $chr, 4);
1035 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-1, $chr, 5);
1036 $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-1, $chr, 6);
1037 $marr = $this->placeModule($marr, $nrow, $ncol, 2, $ncol-1, $chr, 7);
1038 $marr = $this->placeModule($marr, $nrow, $ncol, 3, $ncol-1, $chr, 8);
1039 return $marr;
1040 }
1041
1042 /**
1043 * Places the 8 bits of the second special corner case.
1044 * (Annex F - ECC 200 symbol character placement)
1045 * @param $marr (array) Array of symbols.
1046 * @param $nrow (int) Number of rows.
1047 * @param $ncol (int) Number of columns.
1048 * @param $chr (int) Char byte.
1049 * @return array
1050 * @protected
1051 */
1052 protected function placeCornerB($marr, $nrow, $ncol, $chr) {
1053 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-3, 0, $chr, 1);
1054 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-2, 0, $chr, 2);
1055 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 0, $chr, 3);
1056 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-4, $chr, 4);
1057 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-3, $chr, 5);
1058 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-2, $chr, 6);
1059 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-1, $chr, 7);
1060 $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-1, $chr, 8);
1061 return $marr;
1062 }
1063
1064 /**
1065 * Places the 8 bits of the third special corner case.
1066 * (Annex F - ECC 200 symbol character placement)
1067 * @param $marr (array) Array of symbols.
1068 * @param $nrow (int) Number of rows.
1069 * @param $ncol (int) Number of columns.
1070 * @param $chr (int) Char byte.
1071 * @return array
1072 * @protected
1073 */
1074 protected function placeCornerC($marr, $nrow, $ncol, $chr) {
1075 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-3, 0, $chr, 1);
1076 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-2, 0, $chr, 2);
1077 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 0, $chr, 3);
1078 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-2, $chr, 4);
1079 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-1, $chr, 5);
1080 $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-1, $chr, 6);
1081 $marr = $this->placeModule($marr, $nrow, $ncol, 2, $ncol-1, $chr, 7);
1082 $marr = $this->placeModule($marr, $nrow, $ncol, 3, $ncol-1, $chr, 8);
1083 return $marr;
1084 }
1085
1086 /**
1087 * Places the 8 bits of the fourth special corner case.
1088 * (Annex F - ECC 200 symbol character placement)
1089 * @param $marr (array) Array of symbols.
1090 * @param $nrow (int) Number of rows.
1091 * @param $ncol (int) Number of columns.
1092 * @param $chr (int) Char byte.
1093 * @return array
1094 * @protected
1095 */
1096 protected function placeCornerD($marr, $nrow, $ncol, $chr) {
1097 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, 0, $chr, 1);
1098 $marr = $this->placeModule($marr, $nrow, $ncol, $nrow-1, $ncol-1, $chr, 2);
1099 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-3, $chr, 3);
1100 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-2, $chr, 4);
1101 $marr = $this->placeModule($marr, $nrow, $ncol, 0, $ncol-1, $chr, 5);
1102 $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-3, $chr, 6);
1103 $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-2, $chr, 7);
1104 $marr = $this->placeModule($marr, $nrow, $ncol, 1, $ncol-1, $chr, 8);
1105 return $marr;
1106 }
1107
1108 /**
1109 * Build a placement map.
1110 * (Annex F - ECC 200 symbol character placement)
1111 * @param $nrow (int) Number of rows.
1112 * @param $ncol (int) Number of columns.
1113 * @return array
1114 * @protected
1115 */
1116 protected function getPlacementMap($nrow, $ncol) {
1117 // initialize array with zeros
1118 $marr = array_fill(0, ($nrow * $ncol), 0);
1119 // set starting values
1120 $chr = 1;
1121 $row = 4;
1122 $col = 0;
1123 do {
1124 // repeatedly first check for one of the special corner cases, then
1125 if (($row == $nrow) AND ($col == 0)) {
1126 $marr = $this->placeCornerA($marr, $nrow, $ncol, $chr);
1127 ++$chr;
1128 }
1129 if (($row == ($nrow - 2)) AND ($col == 0) AND ($ncol % 4)) {
1130 $marr = $this->placeCornerB($marr, $nrow, $ncol, $chr);
1131 ++$chr;
1132 }
1133 if (($row == ($nrow - 2)) AND ($col == 0) AND (($ncol % 8) == 4)) {
1134 $marr = $this->placeCornerC($marr, $nrow, $ncol, $chr);
1135 ++$chr;
1136 }
1137 if (($row == ($nrow + 4)) AND ($col == 2) AND (!($ncol % 8))) {
1138 $marr = $this->placeCornerD($marr, $nrow, $ncol, $chr);
1139 ++$chr;
1140 }
1141 // sweep upward diagonally, inserting successive characters,
1142 do {
1143 if (($row < $nrow) AND ($col >= 0) AND (!$marr[(($row * $ncol) + $col)])) {
1144 $marr = $this->placeUtah($marr, $nrow, $ncol, $row, $col, $chr);
1145 ++$chr;
1146 }
1147 $row -= 2;
1148 $col += 2;
1149 } while (($row >= 0) AND ($col < $ncol));
1150 ++$row;
1151 $col += 3;
1152 // & then sweep downward diagonally, inserting successive characters,...
1153 do {
1154 if (($row >= 0) AND ($col < $ncol) AND (!$marr[(($row * $ncol) + $col)])) {
1155 $marr = $this->placeUtah($marr, $nrow, $ncol, $row, $col, $chr);
1156 ++$chr;
1157 }
1158 $row += 2;
1159 $col -= 2;
1160 } while (($row < $nrow) AND ($col >= 0));
1161 $row += 3;
1162 ++$col;
1163 // ... until the entire array is scanned
1164 } while (($row < $nrow) OR ($col < $ncol));
1165 // lastly, if the lower righthand corner is untouched, fill in fixed pattern
1166 if (!$marr[(($nrow * $ncol) - 1)]) {
1167 $marr[(($nrow * $ncol) - 1)] = 1;
1168 $marr[(($nrow * $ncol) - $ncol - 2)] = 1;
1169 }
1170 return $marr;
1171 }
1172
1173} // end DataMatrix class
1174//============================================================+
1175// END OF FILE
1176//============================================================+
diff --git a/inc/3rdparty/libraries/tcpdf/include/barcodes/pdf417.php b/inc/3rdparty/libraries/tcpdf/include/barcodes/pdf417.php
new file mode 100644
index 00000000..07b36b90
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/include/barcodes/pdf417.php
@@ -0,0 +1,996 @@
1<?php
2//============================================================+
3// File name : pdf417.php
4// Version : 1.0.005
5// Begin : 2010-06-03
6// Last Update : 2014-04-25
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) 2010-2013 Nicola Asuni - Tecnick.com LTD
11//
12// This file is part of TCPDF software library.
13//
14// TCPDF is free software: you can redistribute it and/or modify it
15// under the terms of the GNU Lesser General Public License as
16// published by the Free Software Foundation, either version 3 of the
17// License, or (at your option) any later version.
18//
19// TCPDF is distributed in the hope that it will be useful, but
20// WITHOUT ANY WARRANTY; without even the implied warranty of
21// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22// See the GNU Lesser General Public License for more details.
23//
24// You should have received a copy of the GNU Lesser General Public License
25// along with TCPDF. If not, see <http://www.gnu.org/licenses/>.
26//
27// See LICENSE.TXT file for more information.
28// -------------------------------------------------------------------
29//
30// DESCRIPTION :
31//
32// Class to create PDF417 barcode arrays for TCPDF class.
33// PDF417 (ISO/IEC 15438:2006) is a 2-dimensional stacked bar code created by Symbol Technologies in 1991.
34// It is one of the most popular 2D codes because of its ability to be read with slightly modified handheld laser or linear CCD scanners.
35// TECHNICAL DATA / FEATURES OF PDF417:
36// Encodable Character Set: All 128 ASCII Characters (including extended)
37// Code Type: Continuous, Multi-Row
38// Symbol Height: 3 - 90 Rows
39// Symbol Width: 90X - 583X
40// Bidirectional Decoding: Yes
41// Error Correction Characters: 2 - 512
42// Maximum Data Characters: 1850 text, 2710 digits, 1108 bytes
43//
44//============================================================+
45
46/**
47 * @file
48 * Class to create PDF417 barcode arrays for TCPDF class.
49 * PDF417 (ISO/IEC 15438:2006) is a 2-dimensional stacked bar code created by Symbol Technologies in 1991.
50 * (requires PHP bcmath extension)
51 * @package com.tecnick.tcpdf
52 * @author Nicola Asuni
53 * @version 1.0.005
54 */
55
56// definitions
57if (!defined('PDF417DEFS')) {
58
59 /**
60 * Indicate that definitions for this class are set
61 */
62 define('PDF417DEFS', true);
63
64 // -----------------------------------------------------
65
66 /**
67 * Row height respect X dimension of single module
68 */
69 define('ROWHEIGHT', 4);
70
71 /**
72 * Horizontal quiet zone in modules
73 */
74 define('QUIETH', 2);
75
76 /**
77 * Vertical quiet zone in modules
78 */
79 define('QUIETV', 2);
80
81} // end of definitions
82
83// #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
84
85/**
86 * @class PDF417
87 * Class to create PDF417 barcode arrays for TCPDF class.
88 * PDF417 (ISO/IEC 15438:2006) is a 2-dimensional stacked bar code created by Symbol Technologies in 1991.
89 * @package com.tecnick.tcpdf
90 * @author Nicola Asuni
91 * @version 1.0.003
92 */
93class PDF417 {
94
95 /**
96 * Barcode array to be returned which is readable by TCPDF.
97 * @protected
98 */
99 protected $barcode_array = array();
100
101 /**
102 * Start pattern.
103 * @protected
104 */
105 protected $start_pattern = '11111111010101000';
106
107 /**
108 * Stop pattern.
109 * @protected
110 */
111 protected $stop_pattern = '111111101000101001';
112
113 /**
114 * Array of text Compaction Sub-Modes (values 0xFB - 0xFF are used for submode changers).
115 * @protected
116 */
117 protected $textsubmodes = array(
118 array(0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x20,0xFD,0xFE,0xFF), // Alpha
119 array(0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x20,0xFD,0xFE,0xFF), // Lower
120 array(0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x26,0x0d,0x09,0x2c,0x3a,0x23,0x2d,0x2e,0x24,0x2f,0x2b,0x25,0x2a,0x3d,0x5e,0xFB,0x20,0xFD,0xFE,0xFF), // Mixed
121 array(0x3b,0x3c,0x3e,0x40,0x5b,0x5c,0x5d,0x5f,0x60,0x7e,0x21,0x0d,0x09,0x2c,0x3a,0x0a,0x2d,0x2e,0x24,0x2f,0x22,0x7c,0x2a,0x28,0x29,0x3f,0x7b,0x7d,0x27,0xFF) // Puntuaction
122 );
123
124 /**
125 * Array of switching codes for Text Compaction Sub-Modes.
126 * @protected
127 */
128 protected $textlatch = array(
129 '01' => array(27), '02' => array(28), '03' => array(28,25), //
130 '10' => array(28,28), '12' => array(28), '13' => array(28,25), //
131 '20' => array(28), '21' => array(27), '23' => array(25), //
132 '30' => array(29), '31' => array(29,27), '32' => array(29,28) //
133 );
134
135 /**
136 * Clusters of codewords (0, 3, 6)<br/>
137 * Values are hex equivalents of binary representation of bars (1 = bar, 0 = space).<br/>
138 * The codewords numbered from 900 to 928 have special meaning, some enable to switch between modes in order to optimise the code:<ul>
139 * <li>900 : Switch to "Text" mode</li>
140 * <li>901 : Switch to "Byte" mode</li>
141 * <li>902 : Switch to "Numeric" mode</li>
142 * <li>903 - 912 : Reserved</li>
143 * <li>913 : Switch to "Octet" only for the next codeword</li>
144 * <li>914 - 920 : Reserved</li>
145 * <li>921 : Initialization</li>
146 * <li>922 : Terminator codeword for Macro PDF control block</li>
147 * <li>923 : Sequence tag to identify the beginning of optional fields in the Macro PDF control block</li>
148 * <li>924 : Switch to "Byte" mode (If the total number of byte is multiple of 6)</li>
149 * <li>925 : Identifier for a user defined Extended Channel Interpretation (ECI)</li>
150 * <li>926 : Identifier for a general purpose ECI format</li>
151 * <li>927 : Identifier for an ECI of a character set or code page</li>
152 * <li>928 : Macro marker codeword to indicate the beginning of a Macro PDF Control Block</li>
153 * </ul>
154 * @protected
155 */
156 protected $clusters = array(
157 array( // cluster 0 -----------------------------------------------------------------------
158 0x1d5c0,0x1eaf0,0x1f57c,0x1d4e0,0x1ea78,0x1f53e,0x1a8c0,0x1d470,0x1a860,0x15040, // 10
159 0x1a830,0x15020,0x1adc0,0x1d6f0,0x1eb7c,0x1ace0,0x1d678,0x1eb3e,0x158c0,0x1ac70, // 20
160 0x15860,0x15dc0,0x1aef0,0x1d77c,0x15ce0,0x1ae78,0x1d73e,0x15c70,0x1ae3c,0x15ef0, // 30
161 0x1af7c,0x15e78,0x1af3e,0x15f7c,0x1f5fa,0x1d2e0,0x1e978,0x1f4be,0x1a4c0,0x1d270, // 40
162 0x1e93c,0x1a460,0x1d238,0x14840,0x1a430,0x1d21c,0x14820,0x1a418,0x14810,0x1a6e0, // 50
163 0x1d378,0x1e9be,0x14cc0,0x1a670,0x1d33c,0x14c60,0x1a638,0x1d31e,0x14c30,0x1a61c, // 60
164 0x14ee0,0x1a778,0x1d3be,0x14e70,0x1a73c,0x14e38,0x1a71e,0x14f78,0x1a7be,0x14f3c, // 70
165 0x14f1e,0x1a2c0,0x1d170,0x1e8bc,0x1a260,0x1d138,0x1e89e,0x14440,0x1a230,0x1d11c, // 80
166 0x14420,0x1a218,0x14410,0x14408,0x146c0,0x1a370,0x1d1bc,0x14660,0x1a338,0x1d19e, // 90
167 0x14630,0x1a31c,0x14618,0x1460c,0x14770,0x1a3bc,0x14738,0x1a39e,0x1471c,0x147bc, // 100
168 0x1a160,0x1d0b8,0x1e85e,0x14240,0x1a130,0x1d09c,0x14220,0x1a118,0x1d08e,0x14210, // 110
169 0x1a10c,0x14208,0x1a106,0x14360,0x1a1b8,0x1d0de,0x14330,0x1a19c,0x14318,0x1a18e, // 120
170 0x1430c,0x14306,0x1a1de,0x1438e,0x14140,0x1a0b0,0x1d05c,0x14120,0x1a098,0x1d04e, // 130
171 0x14110,0x1a08c,0x14108,0x1a086,0x14104,0x141b0,0x14198,0x1418c,0x140a0,0x1d02e, // 140
172 0x1a04c,0x1a046,0x14082,0x1cae0,0x1e578,0x1f2be,0x194c0,0x1ca70,0x1e53c,0x19460, // 150
173 0x1ca38,0x1e51e,0x12840,0x19430,0x12820,0x196e0,0x1cb78,0x1e5be,0x12cc0,0x19670, // 160
174 0x1cb3c,0x12c60,0x19638,0x12c30,0x12c18,0x12ee0,0x19778,0x1cbbe,0x12e70,0x1973c, // 170
175 0x12e38,0x12e1c,0x12f78,0x197be,0x12f3c,0x12fbe,0x1dac0,0x1ed70,0x1f6bc,0x1da60, // 180
176 0x1ed38,0x1f69e,0x1b440,0x1da30,0x1ed1c,0x1b420,0x1da18,0x1ed0e,0x1b410,0x1da0c, // 190
177 0x192c0,0x1c970,0x1e4bc,0x1b6c0,0x19260,0x1c938,0x1e49e,0x1b660,0x1db38,0x1ed9e, // 200
178 0x16c40,0x12420,0x19218,0x1c90e,0x16c20,0x1b618,0x16c10,0x126c0,0x19370,0x1c9bc, // 210
179 0x16ec0,0x12660,0x19338,0x1c99e,0x16e60,0x1b738,0x1db9e,0x16e30,0x12618,0x16e18, // 220
180 0x12770,0x193bc,0x16f70,0x12738,0x1939e,0x16f38,0x1b79e,0x16f1c,0x127bc,0x16fbc, // 230
181 0x1279e,0x16f9e,0x1d960,0x1ecb8,0x1f65e,0x1b240,0x1d930,0x1ec9c,0x1b220,0x1d918, // 240
182 0x1ec8e,0x1b210,0x1d90c,0x1b208,0x1b204,0x19160,0x1c8b8,0x1e45e,0x1b360,0x19130, // 250
183 0x1c89c,0x16640,0x12220,0x1d99c,0x1c88e,0x16620,0x12210,0x1910c,0x16610,0x1b30c, // 260
184 0x19106,0x12204,0x12360,0x191b8,0x1c8de,0x16760,0x12330,0x1919c,0x16730,0x1b39c, // 270
185 0x1918e,0x16718,0x1230c,0x12306,0x123b8,0x191de,0x167b8,0x1239c,0x1679c,0x1238e, // 280
186 0x1678e,0x167de,0x1b140,0x1d8b0,0x1ec5c,0x1b120,0x1d898,0x1ec4e,0x1b110,0x1d88c, // 290
187 0x1b108,0x1d886,0x1b104,0x1b102,0x12140,0x190b0,0x1c85c,0x16340,0x12120,0x19098, // 300
188 0x1c84e,0x16320,0x1b198,0x1d8ce,0x16310,0x12108,0x19086,0x16308,0x1b186,0x16304, // 310
189 0x121b0,0x190dc,0x163b0,0x12198,0x190ce,0x16398,0x1b1ce,0x1638c,0x12186,0x16386, // 320
190 0x163dc,0x163ce,0x1b0a0,0x1d858,0x1ec2e,0x1b090,0x1d84c,0x1b088,0x1d846,0x1b084, // 330
191 0x1b082,0x120a0,0x19058,0x1c82e,0x161a0,0x12090,0x1904c,0x16190,0x1b0cc,0x19046, // 340
192 0x16188,0x12084,0x16184,0x12082,0x120d8,0x161d8,0x161cc,0x161c6,0x1d82c,0x1d826, // 350
193 0x1b042,0x1902c,0x12048,0x160c8,0x160c4,0x160c2,0x18ac0,0x1c570,0x1e2bc,0x18a60, // 360
194 0x1c538,0x11440,0x18a30,0x1c51c,0x11420,0x18a18,0x11410,0x11408,0x116c0,0x18b70, // 370
195 0x1c5bc,0x11660,0x18b38,0x1c59e,0x11630,0x18b1c,0x11618,0x1160c,0x11770,0x18bbc, // 380
196 0x11738,0x18b9e,0x1171c,0x117bc,0x1179e,0x1cd60,0x1e6b8,0x1f35e,0x19a40,0x1cd30, // 390
197 0x1e69c,0x19a20,0x1cd18,0x1e68e,0x19a10,0x1cd0c,0x19a08,0x1cd06,0x18960,0x1c4b8, // 400
198 0x1e25e,0x19b60,0x18930,0x1c49c,0x13640,0x11220,0x1cd9c,0x1c48e,0x13620,0x19b18, // 410
199 0x1890c,0x13610,0x11208,0x13608,0x11360,0x189b8,0x1c4de,0x13760,0x11330,0x1cdde, // 420
200 0x13730,0x19b9c,0x1898e,0x13718,0x1130c,0x1370c,0x113b8,0x189de,0x137b8,0x1139c, // 430
201 0x1379c,0x1138e,0x113de,0x137de,0x1dd40,0x1eeb0,0x1f75c,0x1dd20,0x1ee98,0x1f74e, // 440
202 0x1dd10,0x1ee8c,0x1dd08,0x1ee86,0x1dd04,0x19940,0x1ccb0,0x1e65c,0x1bb40,0x19920, // 450
203 0x1eedc,0x1e64e,0x1bb20,0x1dd98,0x1eece,0x1bb10,0x19908,0x1cc86,0x1bb08,0x1dd86, // 460
204 0x19902,0x11140,0x188b0,0x1c45c,0x13340,0x11120,0x18898,0x1c44e,0x17740,0x13320, // 470
205 0x19998,0x1ccce,0x17720,0x1bb98,0x1ddce,0x18886,0x17710,0x13308,0x19986,0x17708, // 480
206 0x11102,0x111b0,0x188dc,0x133b0,0x11198,0x188ce,0x177b0,0x13398,0x199ce,0x17798, // 490
207 0x1bbce,0x11186,0x13386,0x111dc,0x133dc,0x111ce,0x177dc,0x133ce,0x1dca0,0x1ee58, // 500
208 0x1f72e,0x1dc90,0x1ee4c,0x1dc88,0x1ee46,0x1dc84,0x1dc82,0x198a0,0x1cc58,0x1e62e, // 510
209 0x1b9a0,0x19890,0x1ee6e,0x1b990,0x1dccc,0x1cc46,0x1b988,0x19884,0x1b984,0x19882, // 520
210 0x1b982,0x110a0,0x18858,0x1c42e,0x131a0,0x11090,0x1884c,0x173a0,0x13190,0x198cc, // 530
211 0x18846,0x17390,0x1b9cc,0x11084,0x17388,0x13184,0x11082,0x13182,0x110d8,0x1886e, // 540
212 0x131d8,0x110cc,0x173d8,0x131cc,0x110c6,0x173cc,0x131c6,0x110ee,0x173ee,0x1dc50, // 550
213 0x1ee2c,0x1dc48,0x1ee26,0x1dc44,0x1dc42,0x19850,0x1cc2c,0x1b8d0,0x19848,0x1cc26, // 560
214 0x1b8c8,0x1dc66,0x1b8c4,0x19842,0x1b8c2,0x11050,0x1882c,0x130d0,0x11048,0x18826, // 570
215 0x171d0,0x130c8,0x19866,0x171c8,0x1b8e6,0x11042,0x171c4,0x130c2,0x171c2,0x130ec, // 580
216 0x171ec,0x171e6,0x1ee16,0x1dc22,0x1cc16,0x19824,0x19822,0x11028,0x13068,0x170e8, // 590
217 0x11022,0x13062,0x18560,0x10a40,0x18530,0x10a20,0x18518,0x1c28e,0x10a10,0x1850c, // 600
218 0x10a08,0x18506,0x10b60,0x185b8,0x1c2de,0x10b30,0x1859c,0x10b18,0x1858e,0x10b0c, // 610
219 0x10b06,0x10bb8,0x185de,0x10b9c,0x10b8e,0x10bde,0x18d40,0x1c6b0,0x1e35c,0x18d20, // 620
220 0x1c698,0x18d10,0x1c68c,0x18d08,0x1c686,0x18d04,0x10940,0x184b0,0x1c25c,0x11b40, // 630
221 0x10920,0x1c6dc,0x1c24e,0x11b20,0x18d98,0x1c6ce,0x11b10,0x10908,0x18486,0x11b08, // 640
222 0x18d86,0x10902,0x109b0,0x184dc,0x11bb0,0x10998,0x184ce,0x11b98,0x18dce,0x11b8c, // 650
223 0x10986,0x109dc,0x11bdc,0x109ce,0x11bce,0x1cea0,0x1e758,0x1f3ae,0x1ce90,0x1e74c, // 660
224 0x1ce88,0x1e746,0x1ce84,0x1ce82,0x18ca0,0x1c658,0x19da0,0x18c90,0x1c64c,0x19d90, // 670
225 0x1cecc,0x1c646,0x19d88,0x18c84,0x19d84,0x18c82,0x19d82,0x108a0,0x18458,0x119a0, // 680
226 0x10890,0x1c66e,0x13ba0,0x11990,0x18ccc,0x18446,0x13b90,0x19dcc,0x10884,0x13b88, // 690
227 0x11984,0x10882,0x11982,0x108d8,0x1846e,0x119d8,0x108cc,0x13bd8,0x119cc,0x108c6, // 700
228 0x13bcc,0x119c6,0x108ee,0x119ee,0x13bee,0x1ef50,0x1f7ac,0x1ef48,0x1f7a6,0x1ef44, // 710
229 0x1ef42,0x1ce50,0x1e72c,0x1ded0,0x1ef6c,0x1e726,0x1dec8,0x1ef66,0x1dec4,0x1ce42, // 720
230 0x1dec2,0x18c50,0x1c62c,0x19cd0,0x18c48,0x1c626,0x1bdd0,0x19cc8,0x1ce66,0x1bdc8, // 730
231 0x1dee6,0x18c42,0x1bdc4,0x19cc2,0x1bdc2,0x10850,0x1842c,0x118d0,0x10848,0x18426, // 740
232 0x139d0,0x118c8,0x18c66,0x17bd0,0x139c8,0x19ce6,0x10842,0x17bc8,0x1bde6,0x118c2, // 750
233 0x17bc4,0x1086c,0x118ec,0x10866,0x139ec,0x118e6,0x17bec,0x139e6,0x17be6,0x1ef28, // 760
234 0x1f796,0x1ef24,0x1ef22,0x1ce28,0x1e716,0x1de68,0x1ef36,0x1de64,0x1ce22,0x1de62, // 770
235 0x18c28,0x1c616,0x19c68,0x18c24,0x1bce8,0x19c64,0x18c22,0x1bce4,0x19c62,0x1bce2, // 780
236 0x10828,0x18416,0x11868,0x18c36,0x138e8,0x11864,0x10822,0x179e8,0x138e4,0x11862, // 790
237 0x179e4,0x138e2,0x179e2,0x11876,0x179f6,0x1ef12,0x1de34,0x1de32,0x19c34,0x1bc74, // 800
238 0x1bc72,0x11834,0x13874,0x178f4,0x178f2,0x10540,0x10520,0x18298,0x10510,0x10508, // 810
239 0x10504,0x105b0,0x10598,0x1058c,0x10586,0x105dc,0x105ce,0x186a0,0x18690,0x1c34c, // 820
240 0x18688,0x1c346,0x18684,0x18682,0x104a0,0x18258,0x10da0,0x186d8,0x1824c,0x10d90, // 830
241 0x186cc,0x10d88,0x186c6,0x10d84,0x10482,0x10d82,0x104d8,0x1826e,0x10dd8,0x186ee, // 840
242 0x10dcc,0x104c6,0x10dc6,0x104ee,0x10dee,0x1c750,0x1c748,0x1c744,0x1c742,0x18650, // 850
243 0x18ed0,0x1c76c,0x1c326,0x18ec8,0x1c766,0x18ec4,0x18642,0x18ec2,0x10450,0x10cd0, // 860
244 0x10448,0x18226,0x11dd0,0x10cc8,0x10444,0x11dc8,0x10cc4,0x10442,0x11dc4,0x10cc2, // 870
245 0x1046c,0x10cec,0x10466,0x11dec,0x10ce6,0x11de6,0x1e7a8,0x1e7a4,0x1e7a2,0x1c728, // 880
246 0x1cf68,0x1e7b6,0x1cf64,0x1c722,0x1cf62,0x18628,0x1c316,0x18e68,0x1c736,0x19ee8, // 890
247 0x18e64,0x18622,0x19ee4,0x18e62,0x19ee2,0x10428,0x18216,0x10c68,0x18636,0x11ce8, // 900
248 0x10c64,0x10422,0x13de8,0x11ce4,0x10c62,0x13de4,0x11ce2,0x10436,0x10c76,0x11cf6, // 910
249 0x13df6,0x1f7d4,0x1f7d2,0x1e794,0x1efb4,0x1e792,0x1efb2,0x1c714,0x1cf34,0x1c712, // 920
250 0x1df74,0x1cf32,0x1df72,0x18614,0x18e34,0x18612,0x19e74,0x18e32,0x1bef4), // 929
251 array( // cluster 3 -----------------------------------------------------------------------
252 0x1f560,0x1fab8,0x1ea40,0x1f530,0x1fa9c,0x1ea20,0x1f518,0x1fa8e,0x1ea10,0x1f50c, // 10
253 0x1ea08,0x1f506,0x1ea04,0x1eb60,0x1f5b8,0x1fade,0x1d640,0x1eb30,0x1f59c,0x1d620, // 20
254 0x1eb18,0x1f58e,0x1d610,0x1eb0c,0x1d608,0x1eb06,0x1d604,0x1d760,0x1ebb8,0x1f5de, // 30
255 0x1ae40,0x1d730,0x1eb9c,0x1ae20,0x1d718,0x1eb8e,0x1ae10,0x1d70c,0x1ae08,0x1d706, // 40
256 0x1ae04,0x1af60,0x1d7b8,0x1ebde,0x15e40,0x1af30,0x1d79c,0x15e20,0x1af18,0x1d78e, // 50
257 0x15e10,0x1af0c,0x15e08,0x1af06,0x15f60,0x1afb8,0x1d7de,0x15f30,0x1af9c,0x15f18, // 60
258 0x1af8e,0x15f0c,0x15fb8,0x1afde,0x15f9c,0x15f8e,0x1e940,0x1f4b0,0x1fa5c,0x1e920, // 70
259 0x1f498,0x1fa4e,0x1e910,0x1f48c,0x1e908,0x1f486,0x1e904,0x1e902,0x1d340,0x1e9b0, // 80
260 0x1f4dc,0x1d320,0x1e998,0x1f4ce,0x1d310,0x1e98c,0x1d308,0x1e986,0x1d304,0x1d302, // 90
261 0x1a740,0x1d3b0,0x1e9dc,0x1a720,0x1d398,0x1e9ce,0x1a710,0x1d38c,0x1a708,0x1d386, // 100
262 0x1a704,0x1a702,0x14f40,0x1a7b0,0x1d3dc,0x14f20,0x1a798,0x1d3ce,0x14f10,0x1a78c, // 110
263 0x14f08,0x1a786,0x14f04,0x14fb0,0x1a7dc,0x14f98,0x1a7ce,0x14f8c,0x14f86,0x14fdc, // 120
264 0x14fce,0x1e8a0,0x1f458,0x1fa2e,0x1e890,0x1f44c,0x1e888,0x1f446,0x1e884,0x1e882, // 130
265 0x1d1a0,0x1e8d8,0x1f46e,0x1d190,0x1e8cc,0x1d188,0x1e8c6,0x1d184,0x1d182,0x1a3a0, // 140
266 0x1d1d8,0x1e8ee,0x1a390,0x1d1cc,0x1a388,0x1d1c6,0x1a384,0x1a382,0x147a0,0x1a3d8, // 150
267 0x1d1ee,0x14790,0x1a3cc,0x14788,0x1a3c6,0x14784,0x14782,0x147d8,0x1a3ee,0x147cc, // 160
268 0x147c6,0x147ee,0x1e850,0x1f42c,0x1e848,0x1f426,0x1e844,0x1e842,0x1d0d0,0x1e86c, // 170
269 0x1d0c8,0x1e866,0x1d0c4,0x1d0c2,0x1a1d0,0x1d0ec,0x1a1c8,0x1d0e6,0x1a1c4,0x1a1c2, // 180
270 0x143d0,0x1a1ec,0x143c8,0x1a1e6,0x143c4,0x143c2,0x143ec,0x143e6,0x1e828,0x1f416, // 190
271 0x1e824,0x1e822,0x1d068,0x1e836,0x1d064,0x1d062,0x1a0e8,0x1d076,0x1a0e4,0x1a0e2, // 200
272 0x141e8,0x1a0f6,0x141e4,0x141e2,0x1e814,0x1e812,0x1d034,0x1d032,0x1a074,0x1a072, // 210
273 0x1e540,0x1f2b0,0x1f95c,0x1e520,0x1f298,0x1f94e,0x1e510,0x1f28c,0x1e508,0x1f286, // 220
274 0x1e504,0x1e502,0x1cb40,0x1e5b0,0x1f2dc,0x1cb20,0x1e598,0x1f2ce,0x1cb10,0x1e58c, // 230
275 0x1cb08,0x1e586,0x1cb04,0x1cb02,0x19740,0x1cbb0,0x1e5dc,0x19720,0x1cb98,0x1e5ce, // 240
276 0x19710,0x1cb8c,0x19708,0x1cb86,0x19704,0x19702,0x12f40,0x197b0,0x1cbdc,0x12f20, // 250
277 0x19798,0x1cbce,0x12f10,0x1978c,0x12f08,0x19786,0x12f04,0x12fb0,0x197dc,0x12f98, // 260
278 0x197ce,0x12f8c,0x12f86,0x12fdc,0x12fce,0x1f6a0,0x1fb58,0x16bf0,0x1f690,0x1fb4c, // 270
279 0x169f8,0x1f688,0x1fb46,0x168fc,0x1f684,0x1f682,0x1e4a0,0x1f258,0x1f92e,0x1eda0, // 280
280 0x1e490,0x1fb6e,0x1ed90,0x1f6cc,0x1f246,0x1ed88,0x1e484,0x1ed84,0x1e482,0x1ed82, // 290
281 0x1c9a0,0x1e4d8,0x1f26e,0x1dba0,0x1c990,0x1e4cc,0x1db90,0x1edcc,0x1e4c6,0x1db88, // 300
282 0x1c984,0x1db84,0x1c982,0x1db82,0x193a0,0x1c9d8,0x1e4ee,0x1b7a0,0x19390,0x1c9cc, // 310
283 0x1b790,0x1dbcc,0x1c9c6,0x1b788,0x19384,0x1b784,0x19382,0x1b782,0x127a0,0x193d8, // 320
284 0x1c9ee,0x16fa0,0x12790,0x193cc,0x16f90,0x1b7cc,0x193c6,0x16f88,0x12784,0x16f84, // 330
285 0x12782,0x127d8,0x193ee,0x16fd8,0x127cc,0x16fcc,0x127c6,0x16fc6,0x127ee,0x1f650, // 340
286 0x1fb2c,0x165f8,0x1f648,0x1fb26,0x164fc,0x1f644,0x1647e,0x1f642,0x1e450,0x1f22c, // 350
287 0x1ecd0,0x1e448,0x1f226,0x1ecc8,0x1f666,0x1ecc4,0x1e442,0x1ecc2,0x1c8d0,0x1e46c, // 360
288 0x1d9d0,0x1c8c8,0x1e466,0x1d9c8,0x1ece6,0x1d9c4,0x1c8c2,0x1d9c2,0x191d0,0x1c8ec, // 370
289 0x1b3d0,0x191c8,0x1c8e6,0x1b3c8,0x1d9e6,0x1b3c4,0x191c2,0x1b3c2,0x123d0,0x191ec, // 380
290 0x167d0,0x123c8,0x191e6,0x167c8,0x1b3e6,0x167c4,0x123c2,0x167c2,0x123ec,0x167ec, // 390
291 0x123e6,0x167e6,0x1f628,0x1fb16,0x162fc,0x1f624,0x1627e,0x1f622,0x1e428,0x1f216, // 400
292 0x1ec68,0x1f636,0x1ec64,0x1e422,0x1ec62,0x1c868,0x1e436,0x1d8e8,0x1c864,0x1d8e4, // 410
293 0x1c862,0x1d8e2,0x190e8,0x1c876,0x1b1e8,0x1d8f6,0x1b1e4,0x190e2,0x1b1e2,0x121e8, // 420
294 0x190f6,0x163e8,0x121e4,0x163e4,0x121e2,0x163e2,0x121f6,0x163f6,0x1f614,0x1617e, // 430
295 0x1f612,0x1e414,0x1ec34,0x1e412,0x1ec32,0x1c834,0x1d874,0x1c832,0x1d872,0x19074, // 440
296 0x1b0f4,0x19072,0x1b0f2,0x120f4,0x161f4,0x120f2,0x161f2,0x1f60a,0x1e40a,0x1ec1a, // 450
297 0x1c81a,0x1d83a,0x1903a,0x1b07a,0x1e2a0,0x1f158,0x1f8ae,0x1e290,0x1f14c,0x1e288, // 460
298 0x1f146,0x1e284,0x1e282,0x1c5a0,0x1e2d8,0x1f16e,0x1c590,0x1e2cc,0x1c588,0x1e2c6, // 470
299 0x1c584,0x1c582,0x18ba0,0x1c5d8,0x1e2ee,0x18b90,0x1c5cc,0x18b88,0x1c5c6,0x18b84, // 480
300 0x18b82,0x117a0,0x18bd8,0x1c5ee,0x11790,0x18bcc,0x11788,0x18bc6,0x11784,0x11782, // 490
301 0x117d8,0x18bee,0x117cc,0x117c6,0x117ee,0x1f350,0x1f9ac,0x135f8,0x1f348,0x1f9a6, // 500
302 0x134fc,0x1f344,0x1347e,0x1f342,0x1e250,0x1f12c,0x1e6d0,0x1e248,0x1f126,0x1e6c8, // 510
303 0x1f366,0x1e6c4,0x1e242,0x1e6c2,0x1c4d0,0x1e26c,0x1cdd0,0x1c4c8,0x1e266,0x1cdc8, // 520
304 0x1e6e6,0x1cdc4,0x1c4c2,0x1cdc2,0x189d0,0x1c4ec,0x19bd0,0x189c8,0x1c4e6,0x19bc8, // 530
305 0x1cde6,0x19bc4,0x189c2,0x19bc2,0x113d0,0x189ec,0x137d0,0x113c8,0x189e6,0x137c8, // 540
306 0x19be6,0x137c4,0x113c2,0x137c2,0x113ec,0x137ec,0x113e6,0x137e6,0x1fba8,0x175f0, // 550
307 0x1bafc,0x1fba4,0x174f8,0x1ba7e,0x1fba2,0x1747c,0x1743e,0x1f328,0x1f996,0x132fc, // 560
308 0x1f768,0x1fbb6,0x176fc,0x1327e,0x1f764,0x1f322,0x1767e,0x1f762,0x1e228,0x1f116, // 570
309 0x1e668,0x1e224,0x1eee8,0x1f776,0x1e222,0x1eee4,0x1e662,0x1eee2,0x1c468,0x1e236, // 580
310 0x1cce8,0x1c464,0x1dde8,0x1cce4,0x1c462,0x1dde4,0x1cce2,0x1dde2,0x188e8,0x1c476, // 590
311 0x199e8,0x188e4,0x1bbe8,0x199e4,0x188e2,0x1bbe4,0x199e2,0x1bbe2,0x111e8,0x188f6, // 600
312 0x133e8,0x111e4,0x177e8,0x133e4,0x111e2,0x177e4,0x133e2,0x177e2,0x111f6,0x133f6, // 610
313 0x1fb94,0x172f8,0x1b97e,0x1fb92,0x1727c,0x1723e,0x1f314,0x1317e,0x1f734,0x1f312, // 620
314 0x1737e,0x1f732,0x1e214,0x1e634,0x1e212,0x1ee74,0x1e632,0x1ee72,0x1c434,0x1cc74, // 630
315 0x1c432,0x1dcf4,0x1cc72,0x1dcf2,0x18874,0x198f4,0x18872,0x1b9f4,0x198f2,0x1b9f2, // 640
316 0x110f4,0x131f4,0x110f2,0x173f4,0x131f2,0x173f2,0x1fb8a,0x1717c,0x1713e,0x1f30a, // 650
317 0x1f71a,0x1e20a,0x1e61a,0x1ee3a,0x1c41a,0x1cc3a,0x1dc7a,0x1883a,0x1987a,0x1b8fa, // 660
318 0x1107a,0x130fa,0x171fa,0x170be,0x1e150,0x1f0ac,0x1e148,0x1f0a6,0x1e144,0x1e142, // 670
319 0x1c2d0,0x1e16c,0x1c2c8,0x1e166,0x1c2c4,0x1c2c2,0x185d0,0x1c2ec,0x185c8,0x1c2e6, // 680
320 0x185c4,0x185c2,0x10bd0,0x185ec,0x10bc8,0x185e6,0x10bc4,0x10bc2,0x10bec,0x10be6, // 690
321 0x1f1a8,0x1f8d6,0x11afc,0x1f1a4,0x11a7e,0x1f1a2,0x1e128,0x1f096,0x1e368,0x1e124, // 700
322 0x1e364,0x1e122,0x1e362,0x1c268,0x1e136,0x1c6e8,0x1c264,0x1c6e4,0x1c262,0x1c6e2, // 710
323 0x184e8,0x1c276,0x18de8,0x184e4,0x18de4,0x184e2,0x18de2,0x109e8,0x184f6,0x11be8, // 720
324 0x109e4,0x11be4,0x109e2,0x11be2,0x109f6,0x11bf6,0x1f9d4,0x13af8,0x19d7e,0x1f9d2, // 730
325 0x13a7c,0x13a3e,0x1f194,0x1197e,0x1f3b4,0x1f192,0x13b7e,0x1f3b2,0x1e114,0x1e334, // 740
326 0x1e112,0x1e774,0x1e332,0x1e772,0x1c234,0x1c674,0x1c232,0x1cef4,0x1c672,0x1cef2, // 750
327 0x18474,0x18cf4,0x18472,0x19df4,0x18cf2,0x19df2,0x108f4,0x119f4,0x108f2,0x13bf4, // 760
328 0x119f2,0x13bf2,0x17af0,0x1bd7c,0x17a78,0x1bd3e,0x17a3c,0x17a1e,0x1f9ca,0x1397c, // 770
329 0x1fbda,0x17b7c,0x1393e,0x17b3e,0x1f18a,0x1f39a,0x1f7ba,0x1e10a,0x1e31a,0x1e73a, // 780
330 0x1ef7a,0x1c21a,0x1c63a,0x1ce7a,0x1defa,0x1843a,0x18c7a,0x19cfa,0x1bdfa,0x1087a, // 790
331 0x118fa,0x139fa,0x17978,0x1bcbe,0x1793c,0x1791e,0x138be,0x179be,0x178bc,0x1789e, // 800
332 0x1785e,0x1e0a8,0x1e0a4,0x1e0a2,0x1c168,0x1e0b6,0x1c164,0x1c162,0x182e8,0x1c176, // 810
333 0x182e4,0x182e2,0x105e8,0x182f6,0x105e4,0x105e2,0x105f6,0x1f0d4,0x10d7e,0x1f0d2, // 820
334 0x1e094,0x1e1b4,0x1e092,0x1e1b2,0x1c134,0x1c374,0x1c132,0x1c372,0x18274,0x186f4, // 830
335 0x18272,0x186f2,0x104f4,0x10df4,0x104f2,0x10df2,0x1f8ea,0x11d7c,0x11d3e,0x1f0ca, // 840
336 0x1f1da,0x1e08a,0x1e19a,0x1e3ba,0x1c11a,0x1c33a,0x1c77a,0x1823a,0x1867a,0x18efa, // 850
337 0x1047a,0x10cfa,0x11dfa,0x13d78,0x19ebe,0x13d3c,0x13d1e,0x11cbe,0x13dbe,0x17d70, // 860
338 0x1bebc,0x17d38,0x1be9e,0x17d1c,0x17d0e,0x13cbc,0x17dbc,0x13c9e,0x17d9e,0x17cb8, // 870
339 0x1be5e,0x17c9c,0x17c8e,0x13c5e,0x17cde,0x17c5c,0x17c4e,0x17c2e,0x1c0b4,0x1c0b2, // 880
340 0x18174,0x18172,0x102f4,0x102f2,0x1e0da,0x1c09a,0x1c1ba,0x1813a,0x1837a,0x1027a, // 890
341 0x106fa,0x10ebe,0x11ebc,0x11e9e,0x13eb8,0x19f5e,0x13e9c,0x13e8e,0x11e5e,0x13ede, // 900
342 0x17eb0,0x1bf5c,0x17e98,0x1bf4e,0x17e8c,0x17e86,0x13e5c,0x17edc,0x13e4e,0x17ece, // 910
343 0x17e58,0x1bf2e,0x17e4c,0x17e46,0x13e2e,0x17e6e,0x17e2c,0x17e26,0x10f5e,0x11f5c, // 920
344 0x11f4e,0x13f58,0x19fae,0x13f4c,0x13f46,0x11f2e,0x13f6e,0x13f2c,0x13f26), // 929
345 array( // cluster 6 -----------------------------------------------------------------------
346 0x1abe0,0x1d5f8,0x153c0,0x1a9f0,0x1d4fc,0x151e0,0x1a8f8,0x1d47e,0x150f0,0x1a87c, // 10
347 0x15078,0x1fad0,0x15be0,0x1adf8,0x1fac8,0x159f0,0x1acfc,0x1fac4,0x158f8,0x1ac7e, // 20
348 0x1fac2,0x1587c,0x1f5d0,0x1faec,0x15df8,0x1f5c8,0x1fae6,0x15cfc,0x1f5c4,0x15c7e, // 30
349 0x1f5c2,0x1ebd0,0x1f5ec,0x1ebc8,0x1f5e6,0x1ebc4,0x1ebc2,0x1d7d0,0x1ebec,0x1d7c8, // 40
350 0x1ebe6,0x1d7c4,0x1d7c2,0x1afd0,0x1d7ec,0x1afc8,0x1d7e6,0x1afc4,0x14bc0,0x1a5f0, // 50
351 0x1d2fc,0x149e0,0x1a4f8,0x1d27e,0x148f0,0x1a47c,0x14878,0x1a43e,0x1483c,0x1fa68, // 60
352 0x14df0,0x1a6fc,0x1fa64,0x14cf8,0x1a67e,0x1fa62,0x14c7c,0x14c3e,0x1f4e8,0x1fa76, // 70
353 0x14efc,0x1f4e4,0x14e7e,0x1f4e2,0x1e9e8,0x1f4f6,0x1e9e4,0x1e9e2,0x1d3e8,0x1e9f6, // 80
354 0x1d3e4,0x1d3e2,0x1a7e8,0x1d3f6,0x1a7e4,0x1a7e2,0x145e0,0x1a2f8,0x1d17e,0x144f0, // 90
355 0x1a27c,0x14478,0x1a23e,0x1443c,0x1441e,0x1fa34,0x146f8,0x1a37e,0x1fa32,0x1467c, // 100
356 0x1463e,0x1f474,0x1477e,0x1f472,0x1e8f4,0x1e8f2,0x1d1f4,0x1d1f2,0x1a3f4,0x1a3f2, // 110
357 0x142f0,0x1a17c,0x14278,0x1a13e,0x1423c,0x1421e,0x1fa1a,0x1437c,0x1433e,0x1f43a, // 120
358 0x1e87a,0x1d0fa,0x14178,0x1a0be,0x1413c,0x1411e,0x141be,0x140bc,0x1409e,0x12bc0, // 130
359 0x195f0,0x1cafc,0x129e0,0x194f8,0x1ca7e,0x128f0,0x1947c,0x12878,0x1943e,0x1283c, // 140
360 0x1f968,0x12df0,0x196fc,0x1f964,0x12cf8,0x1967e,0x1f962,0x12c7c,0x12c3e,0x1f2e8, // 150
361 0x1f976,0x12efc,0x1f2e4,0x12e7e,0x1f2e2,0x1e5e8,0x1f2f6,0x1e5e4,0x1e5e2,0x1cbe8, // 160
362 0x1e5f6,0x1cbe4,0x1cbe2,0x197e8,0x1cbf6,0x197e4,0x197e2,0x1b5e0,0x1daf8,0x1ed7e, // 170
363 0x169c0,0x1b4f0,0x1da7c,0x168e0,0x1b478,0x1da3e,0x16870,0x1b43c,0x16838,0x1b41e, // 180
364 0x1681c,0x125e0,0x192f8,0x1c97e,0x16de0,0x124f0,0x1927c,0x16cf0,0x1b67c,0x1923e, // 190
365 0x16c78,0x1243c,0x16c3c,0x1241e,0x16c1e,0x1f934,0x126f8,0x1937e,0x1fb74,0x1f932, // 200
366 0x16ef8,0x1267c,0x1fb72,0x16e7c,0x1263e,0x16e3e,0x1f274,0x1277e,0x1f6f4,0x1f272, // 210
367 0x16f7e,0x1f6f2,0x1e4f4,0x1edf4,0x1e4f2,0x1edf2,0x1c9f4,0x1dbf4,0x1c9f2,0x1dbf2, // 220
368 0x193f4,0x193f2,0x165c0,0x1b2f0,0x1d97c,0x164e0,0x1b278,0x1d93e,0x16470,0x1b23c, // 230
369 0x16438,0x1b21e,0x1641c,0x1640e,0x122f0,0x1917c,0x166f0,0x12278,0x1913e,0x16678, // 240
370 0x1b33e,0x1663c,0x1221e,0x1661e,0x1f91a,0x1237c,0x1fb3a,0x1677c,0x1233e,0x1673e, // 250
371 0x1f23a,0x1f67a,0x1e47a,0x1ecfa,0x1c8fa,0x1d9fa,0x191fa,0x162e0,0x1b178,0x1d8be, // 260
372 0x16270,0x1b13c,0x16238,0x1b11e,0x1621c,0x1620e,0x12178,0x190be,0x16378,0x1213c, // 270
373 0x1633c,0x1211e,0x1631e,0x121be,0x163be,0x16170,0x1b0bc,0x16138,0x1b09e,0x1611c, // 280
374 0x1610e,0x120bc,0x161bc,0x1209e,0x1619e,0x160b8,0x1b05e,0x1609c,0x1608e,0x1205e, // 290
375 0x160de,0x1605c,0x1604e,0x115e0,0x18af8,0x1c57e,0x114f0,0x18a7c,0x11478,0x18a3e, // 300
376 0x1143c,0x1141e,0x1f8b4,0x116f8,0x18b7e,0x1f8b2,0x1167c,0x1163e,0x1f174,0x1177e, // 310
377 0x1f172,0x1e2f4,0x1e2f2,0x1c5f4,0x1c5f2,0x18bf4,0x18bf2,0x135c0,0x19af0,0x1cd7c, // 320
378 0x134e0,0x19a78,0x1cd3e,0x13470,0x19a3c,0x13438,0x19a1e,0x1341c,0x1340e,0x112f0, // 330
379 0x1897c,0x136f0,0x11278,0x1893e,0x13678,0x19b3e,0x1363c,0x1121e,0x1361e,0x1f89a, // 340
380 0x1137c,0x1f9ba,0x1377c,0x1133e,0x1373e,0x1f13a,0x1f37a,0x1e27a,0x1e6fa,0x1c4fa, // 350
381 0x1cdfa,0x189fa,0x1bae0,0x1dd78,0x1eebe,0x174c0,0x1ba70,0x1dd3c,0x17460,0x1ba38, // 360
382 0x1dd1e,0x17430,0x1ba1c,0x17418,0x1ba0e,0x1740c,0x132e0,0x19978,0x1ccbe,0x176e0, // 370
383 0x13270,0x1993c,0x17670,0x1bb3c,0x1991e,0x17638,0x1321c,0x1761c,0x1320e,0x1760e, // 380
384 0x11178,0x188be,0x13378,0x1113c,0x17778,0x1333c,0x1111e,0x1773c,0x1331e,0x1771e, // 390
385 0x111be,0x133be,0x177be,0x172c0,0x1b970,0x1dcbc,0x17260,0x1b938,0x1dc9e,0x17230, // 400
386 0x1b91c,0x17218,0x1b90e,0x1720c,0x17206,0x13170,0x198bc,0x17370,0x13138,0x1989e, // 410
387 0x17338,0x1b99e,0x1731c,0x1310e,0x1730e,0x110bc,0x131bc,0x1109e,0x173bc,0x1319e, // 420
388 0x1739e,0x17160,0x1b8b8,0x1dc5e,0x17130,0x1b89c,0x17118,0x1b88e,0x1710c,0x17106, // 430
389 0x130b8,0x1985e,0x171b8,0x1309c,0x1719c,0x1308e,0x1718e,0x1105e,0x130de,0x171de, // 440
390 0x170b0,0x1b85c,0x17098,0x1b84e,0x1708c,0x17086,0x1305c,0x170dc,0x1304e,0x170ce, // 450
391 0x17058,0x1b82e,0x1704c,0x17046,0x1302e,0x1706e,0x1702c,0x17026,0x10af0,0x1857c, // 460
392 0x10a78,0x1853e,0x10a3c,0x10a1e,0x10b7c,0x10b3e,0x1f0ba,0x1e17a,0x1c2fa,0x185fa, // 470
393 0x11ae0,0x18d78,0x1c6be,0x11a70,0x18d3c,0x11a38,0x18d1e,0x11a1c,0x11a0e,0x10978, // 480
394 0x184be,0x11b78,0x1093c,0x11b3c,0x1091e,0x11b1e,0x109be,0x11bbe,0x13ac0,0x19d70, // 490
395 0x1cebc,0x13a60,0x19d38,0x1ce9e,0x13a30,0x19d1c,0x13a18,0x19d0e,0x13a0c,0x13a06, // 500
396 0x11970,0x18cbc,0x13b70,0x11938,0x18c9e,0x13b38,0x1191c,0x13b1c,0x1190e,0x13b0e, // 510
397 0x108bc,0x119bc,0x1089e,0x13bbc,0x1199e,0x13b9e,0x1bd60,0x1deb8,0x1ef5e,0x17a40, // 520
398 0x1bd30,0x1de9c,0x17a20,0x1bd18,0x1de8e,0x17a10,0x1bd0c,0x17a08,0x1bd06,0x17a04, // 530
399 0x13960,0x19cb8,0x1ce5e,0x17b60,0x13930,0x19c9c,0x17b30,0x1bd9c,0x19c8e,0x17b18, // 540
400 0x1390c,0x17b0c,0x13906,0x17b06,0x118b8,0x18c5e,0x139b8,0x1189c,0x17bb8,0x1399c, // 550
401 0x1188e,0x17b9c,0x1398e,0x17b8e,0x1085e,0x118de,0x139de,0x17bde,0x17940,0x1bcb0, // 560
402 0x1de5c,0x17920,0x1bc98,0x1de4e,0x17910,0x1bc8c,0x17908,0x1bc86,0x17904,0x17902, // 570
403 0x138b0,0x19c5c,0x179b0,0x13898,0x19c4e,0x17998,0x1bcce,0x1798c,0x13886,0x17986, // 580
404 0x1185c,0x138dc,0x1184e,0x179dc,0x138ce,0x179ce,0x178a0,0x1bc58,0x1de2e,0x17890, // 590
405 0x1bc4c,0x17888,0x1bc46,0x17884,0x17882,0x13858,0x19c2e,0x178d8,0x1384c,0x178cc, // 600
406 0x13846,0x178c6,0x1182e,0x1386e,0x178ee,0x17850,0x1bc2c,0x17848,0x1bc26,0x17844, // 610
407 0x17842,0x1382c,0x1786c,0x13826,0x17866,0x17828,0x1bc16,0x17824,0x17822,0x13816, // 620
408 0x17836,0x10578,0x182be,0x1053c,0x1051e,0x105be,0x10d70,0x186bc,0x10d38,0x1869e, // 630
409 0x10d1c,0x10d0e,0x104bc,0x10dbc,0x1049e,0x10d9e,0x11d60,0x18eb8,0x1c75e,0x11d30, // 640
410 0x18e9c,0x11d18,0x18e8e,0x11d0c,0x11d06,0x10cb8,0x1865e,0x11db8,0x10c9c,0x11d9c, // 650
411 0x10c8e,0x11d8e,0x1045e,0x10cde,0x11dde,0x13d40,0x19eb0,0x1cf5c,0x13d20,0x19e98, // 660
412 0x1cf4e,0x13d10,0x19e8c,0x13d08,0x19e86,0x13d04,0x13d02,0x11cb0,0x18e5c,0x13db0, // 670
413 0x11c98,0x18e4e,0x13d98,0x19ece,0x13d8c,0x11c86,0x13d86,0x10c5c,0x11cdc,0x10c4e, // 680
414 0x13ddc,0x11cce,0x13dce,0x1bea0,0x1df58,0x1efae,0x1be90,0x1df4c,0x1be88,0x1df46, // 690
415 0x1be84,0x1be82,0x13ca0,0x19e58,0x1cf2e,0x17da0,0x13c90,0x19e4c,0x17d90,0x1becc, // 700
416 0x19e46,0x17d88,0x13c84,0x17d84,0x13c82,0x17d82,0x11c58,0x18e2e,0x13cd8,0x11c4c, // 710
417 0x17dd8,0x13ccc,0x11c46,0x17dcc,0x13cc6,0x17dc6,0x10c2e,0x11c6e,0x13cee,0x17dee, // 720
418 0x1be50,0x1df2c,0x1be48,0x1df26,0x1be44,0x1be42,0x13c50,0x19e2c,0x17cd0,0x13c48, // 730
419 0x19e26,0x17cc8,0x1be66,0x17cc4,0x13c42,0x17cc2,0x11c2c,0x13c6c,0x11c26,0x17cec, // 740
420 0x13c66,0x17ce6,0x1be28,0x1df16,0x1be24,0x1be22,0x13c28,0x19e16,0x17c68,0x13c24, // 750
421 0x17c64,0x13c22,0x17c62,0x11c16,0x13c36,0x17c76,0x1be14,0x1be12,0x13c14,0x17c34, // 760
422 0x13c12,0x17c32,0x102bc,0x1029e,0x106b8,0x1835e,0x1069c,0x1068e,0x1025e,0x106de, // 770
423 0x10eb0,0x1875c,0x10e98,0x1874e,0x10e8c,0x10e86,0x1065c,0x10edc,0x1064e,0x10ece, // 780
424 0x11ea0,0x18f58,0x1c7ae,0x11e90,0x18f4c,0x11e88,0x18f46,0x11e84,0x11e82,0x10e58, // 790
425 0x1872e,0x11ed8,0x18f6e,0x11ecc,0x10e46,0x11ec6,0x1062e,0x10e6e,0x11eee,0x19f50, // 800
426 0x1cfac,0x19f48,0x1cfa6,0x19f44,0x19f42,0x11e50,0x18f2c,0x13ed0,0x19f6c,0x18f26, // 810
427 0x13ec8,0x11e44,0x13ec4,0x11e42,0x13ec2,0x10e2c,0x11e6c,0x10e26,0x13eec,0x11e66, // 820
428 0x13ee6,0x1dfa8,0x1efd6,0x1dfa4,0x1dfa2,0x19f28,0x1cf96,0x1bf68,0x19f24,0x1bf64, // 830
429 0x19f22,0x1bf62,0x11e28,0x18f16,0x13e68,0x11e24,0x17ee8,0x13e64,0x11e22,0x17ee4, // 840
430 0x13e62,0x17ee2,0x10e16,0x11e36,0x13e76,0x17ef6,0x1df94,0x1df92,0x19f14,0x1bf34, // 850
431 0x19f12,0x1bf32,0x11e14,0x13e34,0x11e12,0x17e74,0x13e32,0x17e72,0x1df8a,0x19f0a, // 860
432 0x1bf1a,0x11e0a,0x13e1a,0x17e3a,0x1035c,0x1034e,0x10758,0x183ae,0x1074c,0x10746, // 870
433 0x1032e,0x1076e,0x10f50,0x187ac,0x10f48,0x187a6,0x10f44,0x10f42,0x1072c,0x10f6c, // 880
434 0x10726,0x10f66,0x18fa8,0x1c7d6,0x18fa4,0x18fa2,0x10f28,0x18796,0x11f68,0x18fb6, // 890
435 0x11f64,0x10f22,0x11f62,0x10716,0x10f36,0x11f76,0x1cfd4,0x1cfd2,0x18f94,0x19fb4, // 900
436 0x18f92,0x19fb2,0x10f14,0x11f34,0x10f12,0x13f74,0x11f32,0x13f72,0x1cfca,0x18f8a, // 910
437 0x19f9a,0x10f0a,0x11f1a,0x13f3a,0x103ac,0x103a6,0x107a8,0x183d6,0x107a4,0x107a2, // 920
438 0x10396,0x107b6,0x187d4,0x187d2,0x10794,0x10fb4,0x10792,0x10fb2,0x1c7ea) // 929
439 ); // end of $clusters array
440
441 /**
442 * Array of factors of the Reed-Solomon polynomial equations used for error correction; one sub array for each correction level (0-8).
443 * @protected
444 */
445 protected $rsfactors = array(
446 array( // ECL 0 (2 factors) -------------------------------------------------------------------------------
447 0x01b,0x395), // 2
448 array( // ECL 1 (4 factors) -------------------------------------------------------------------------------
449 0x20a,0x238,0x2d3,0x329), // 4
450 array( // ECL 2 (8 factors) -------------------------------------------------------------------------------
451 0x0ed,0x134,0x1b4,0x11c,0x286,0x28d,0x1ac,0x17b), // 8
452 array( // ECL 3 (16 factors) ------------------------------------------------------------------------------
453 0x112,0x232,0x0e8,0x2f3,0x257,0x20c,0x321,0x084,0x127,0x074,0x1ba,0x1ac,0x127,0x02a,0x0b0,0x041),// 16
454 array( // ECL 4 (32 factors) ------------------------------------------------------------------------------
455 0x169,0x23f,0x39a,0x20d,0x0b0,0x24a,0x280,0x141,0x218,0x2e6,0x2a5,0x2e6,0x2af,0x11c,0x0c1,0x205, // 16
456 0x111,0x1ee,0x107,0x093,0x251,0x320,0x23b,0x140,0x323,0x085,0x0e7,0x186,0x2ad,0x14a,0x03f,0x19a),// 32
457 array( // ECL 5 (64 factors) ------------------------------------------------------------------------------
458 0x21b,0x1a6,0x006,0x05d,0x35e,0x303,0x1c5,0x06a,0x262,0x11f,0x06b,0x1f9,0x2dd,0x36d,0x17d,0x264, // 16
459 0x2d3,0x1dc,0x1ce,0x0ac,0x1ae,0x261,0x35a,0x336,0x21f,0x178,0x1ff,0x190,0x2a0,0x2fa,0x11b,0x0b8, // 32
460 0x1b8,0x023,0x207,0x01f,0x1cc,0x252,0x0e1,0x217,0x205,0x160,0x25d,0x09e,0x28b,0x0c9,0x1e8,0x1f6, // 48
461 0x288,0x2dd,0x2cd,0x053,0x194,0x061,0x118,0x303,0x348,0x275,0x004,0x17d,0x34b,0x26f,0x108,0x21f),// 64
462 array( // ECL 6 (128 factors) -----------------------------------------------------------------------------
463 0x209,0x136,0x360,0x223,0x35a,0x244,0x128,0x17b,0x035,0x30b,0x381,0x1bc,0x190,0x39d,0x2ed,0x19f, // 16
464 0x336,0x05d,0x0d9,0x0d0,0x3a0,0x0f4,0x247,0x26c,0x0f6,0x094,0x1bf,0x277,0x124,0x38c,0x1ea,0x2c0, // 32
465 0x204,0x102,0x1c9,0x38b,0x252,0x2d3,0x2a2,0x124,0x110,0x060,0x2ac,0x1b0,0x2ae,0x25e,0x35c,0x239, // 48
466 0x0c1,0x0db,0x081,0x0ba,0x0ec,0x11f,0x0c0,0x307,0x116,0x0ad,0x028,0x17b,0x2c8,0x1cf,0x286,0x308, // 64
467 0x0ab,0x1eb,0x129,0x2fb,0x09c,0x2dc,0x05f,0x10e,0x1bf,0x05a,0x1fb,0x030,0x0e4,0x335,0x328,0x382, // 80
468 0x310,0x297,0x273,0x17a,0x17e,0x106,0x17c,0x25a,0x2f2,0x150,0x059,0x266,0x057,0x1b0,0x29e,0x268, // 96
469 0x09d,0x176,0x0f2,0x2d6,0x258,0x10d,0x177,0x382,0x34d,0x1c6,0x162,0x082,0x32e,0x24b,0x324,0x022, // 112
470 0x0d3,0x14a,0x21b,0x129,0x33b,0x361,0x025,0x205,0x342,0x13b,0x226,0x056,0x321,0x004,0x06c,0x21b),// 128
471 array( // ECL 7 (256 factors) -----------------------------------------------------------------------------
472 0x20c,0x37e,0x04b,0x2fe,0x372,0x359,0x04a,0x0cc,0x052,0x24a,0x2c4,0x0fa,0x389,0x312,0x08a,0x2d0, // 16
473 0x35a,0x0c2,0x137,0x391,0x113,0x0be,0x177,0x352,0x1b6,0x2dd,0x0c2,0x118,0x0c9,0x118,0x33c,0x2f5, // 32
474 0x2c6,0x32e,0x397,0x059,0x044,0x239,0x00b,0x0cc,0x31c,0x25d,0x21c,0x391,0x321,0x2bc,0x31f,0x089, // 48
475 0x1b7,0x1a2,0x250,0x29c,0x161,0x35b,0x172,0x2b6,0x145,0x0f0,0x0d8,0x101,0x11c,0x225,0x0d1,0x374, // 64
476 0x13b,0x046,0x149,0x319,0x1ea,0x112,0x36d,0x0a2,0x2ed,0x32c,0x2ac,0x1cd,0x14e,0x178,0x351,0x209, // 80
477 0x133,0x123,0x323,0x2c8,0x013,0x166,0x18f,0x38c,0x067,0x1ff,0x033,0x008,0x205,0x0e1,0x121,0x1d6, // 96
478 0x27d,0x2db,0x042,0x0ff,0x395,0x10d,0x1cf,0x33e,0x2da,0x1b1,0x350,0x249,0x088,0x21a,0x38a,0x05a, // 112
479 0x002,0x122,0x2e7,0x0c7,0x28f,0x387,0x149,0x031,0x322,0x244,0x163,0x24c,0x0bc,0x1ce,0x00a,0x086, // 128
480 0x274,0x140,0x1df,0x082,0x2e3,0x047,0x107,0x13e,0x176,0x259,0x0c0,0x25d,0x08e,0x2a1,0x2af,0x0ea, // 144
481 0x2d2,0x180,0x0b1,0x2f0,0x25f,0x280,0x1c7,0x0c1,0x2b1,0x2c3,0x325,0x281,0x030,0x03c,0x2dc,0x26d, // 160
482 0x37f,0x220,0x105,0x354,0x28f,0x135,0x2b9,0x2f3,0x2f4,0x03c,0x0e7,0x305,0x1b2,0x1a5,0x2d6,0x210, // 176
483 0x1f7,0x076,0x031,0x31b,0x020,0x090,0x1f4,0x0ee,0x344,0x18a,0x118,0x236,0x13f,0x009,0x287,0x226, // 192
484 0x049,0x392,0x156,0x07e,0x020,0x2a9,0x14b,0x318,0x26c,0x03c,0x261,0x1b9,0x0b4,0x317,0x37d,0x2f2, // 208
485 0x25d,0x17f,0x0e4,0x2ed,0x2f8,0x0d5,0x036,0x129,0x086,0x036,0x342,0x12b,0x39a,0x0bf,0x38e,0x214, // 224
486 0x261,0x33d,0x0bd,0x014,0x0a7,0x01d,0x368,0x1c1,0x053,0x192,0x029,0x290,0x1f9,0x243,0x1e1,0x0ad, // 240
487 0x194,0x0fb,0x2b0,0x05f,0x1f1,0x22b,0x282,0x21f,0x133,0x09f,0x39c,0x22e,0x288,0x037,0x1f1,0x00a),// 256
488 array( // ECL 8 (512 factors) -----------------------------------------------------------------------------
489 0x160,0x04d,0x175,0x1f8,0x023,0x257,0x1ac,0x0cf,0x199,0x23e,0x076,0x1f2,0x11d,0x17c,0x15e,0x1ec, // 16
490 0x0c5,0x109,0x398,0x09b,0x392,0x12b,0x0e5,0x283,0x126,0x367,0x132,0x058,0x057,0x0c1,0x160,0x30d, // 32
491 0x34e,0x04b,0x147,0x208,0x1b3,0x21f,0x0cb,0x29a,0x0f9,0x15a,0x30d,0x26d,0x280,0x10c,0x31a,0x216, // 48
492 0x21b,0x30d,0x198,0x186,0x284,0x066,0x1dc,0x1f3,0x122,0x278,0x221,0x025,0x35a,0x394,0x228,0x029, // 64
493 0x21e,0x121,0x07a,0x110,0x17f,0x320,0x1e5,0x062,0x2f0,0x1d8,0x2f9,0x06b,0x310,0x35c,0x292,0x2e5, // 80
494 0x122,0x0cc,0x2a9,0x197,0x357,0x055,0x063,0x03e,0x1e2,0x0b4,0x014,0x129,0x1c3,0x251,0x391,0x08e, // 96
495 0x328,0x2ac,0x11f,0x218,0x231,0x04c,0x28d,0x383,0x2d9,0x237,0x2e8,0x186,0x201,0x0c0,0x204,0x102, // 112
496 0x0f0,0x206,0x31a,0x18b,0x300,0x350,0x033,0x262,0x180,0x0a8,0x0be,0x33a,0x148,0x254,0x312,0x12f, // 128
497 0x23a,0x17d,0x19f,0x281,0x09c,0x0ed,0x097,0x1ad,0x213,0x0cf,0x2a4,0x2c6,0x059,0x0a8,0x130,0x192, // 144
498 0x028,0x2c4,0x23f,0x0a2,0x360,0x0e5,0x041,0x35d,0x349,0x200,0x0a4,0x1dd,0x0dd,0x05c,0x166,0x311, // 160
499 0x120,0x165,0x352,0x344,0x33b,0x2e0,0x2c3,0x05e,0x008,0x1ee,0x072,0x209,0x002,0x1f3,0x353,0x21f, // 176
500 0x098,0x2d9,0x303,0x05f,0x0f8,0x169,0x242,0x143,0x358,0x31d,0x121,0x033,0x2ac,0x1d2,0x215,0x334, // 192
501 0x29d,0x02d,0x386,0x1c4,0x0a7,0x156,0x0f4,0x0ad,0x023,0x1cf,0x28b,0x033,0x2bb,0x24f,0x1c4,0x242, // 208
502 0x025,0x07c,0x12a,0x14c,0x228,0x02b,0x1ab,0x077,0x296,0x309,0x1db,0x352,0x2fc,0x16c,0x242,0x38f, // 224
503 0x11b,0x2c7,0x1d8,0x1a4,0x0f5,0x120,0x252,0x18a,0x1ff,0x147,0x24d,0x309,0x2bb,0x2b0,0x02b,0x198, // 240
504 0x34a,0x17f,0x2d1,0x209,0x230,0x284,0x2ca,0x22f,0x03e,0x091,0x369,0x297,0x2c9,0x09f,0x2a0,0x2d9, // 256
505 0x270,0x03b,0x0c1,0x1a1,0x09e,0x0d1,0x233,0x234,0x157,0x2b5,0x06d,0x260,0x233,0x16d,0x0b5,0x304, // 272
506 0x2a5,0x136,0x0f8,0x161,0x2c4,0x19a,0x243,0x366,0x269,0x349,0x278,0x35c,0x121,0x218,0x023,0x309, // 288
507 0x26a,0x24a,0x1a8,0x341,0x04d,0x255,0x15a,0x10d,0x2f5,0x278,0x2b7,0x2ef,0x14b,0x0f7,0x0b8,0x02d, // 304
508 0x313,0x2a8,0x012,0x042,0x197,0x171,0x036,0x1ec,0x0e4,0x265,0x33e,0x39a,0x1b5,0x207,0x284,0x389, // 320
509 0x315,0x1a4,0x131,0x1b9,0x0cf,0x12c,0x37c,0x33b,0x08d,0x219,0x17d,0x296,0x201,0x038,0x0fc,0x155, // 336
510 0x0f2,0x31d,0x346,0x345,0x2d0,0x0e0,0x133,0x277,0x03d,0x057,0x230,0x136,0x2f4,0x299,0x18d,0x328, // 352
511 0x353,0x135,0x1d9,0x31b,0x17a,0x01f,0x287,0x393,0x1cb,0x326,0x24e,0x2db,0x1a9,0x0d8,0x224,0x0f9, // 368
512 0x141,0x371,0x2bb,0x217,0x2a1,0x30e,0x0d2,0x32f,0x389,0x12f,0x34b,0x39a,0x119,0x049,0x1d5,0x317, // 384
513 0x294,0x0a2,0x1f2,0x134,0x09b,0x1a6,0x38b,0x331,0x0bb,0x03e,0x010,0x1a9,0x217,0x150,0x11e,0x1b5, // 400
514 0x177,0x111,0x262,0x128,0x0b7,0x39b,0x074,0x29b,0x2ef,0x161,0x03e,0x16e,0x2b3,0x17b,0x2af,0x34a, // 416
515 0x025,0x165,0x2d0,0x2e6,0x14a,0x005,0x027,0x39b,0x137,0x1a8,0x0f2,0x2ed,0x141,0x036,0x29d,0x13c, // 432
516 0x156,0x12b,0x216,0x069,0x29b,0x1e8,0x280,0x2a0,0x240,0x21c,0x13c,0x1e6,0x2d1,0x262,0x02e,0x290, // 448
517 0x1bf,0x0ab,0x268,0x1d0,0x0be,0x213,0x129,0x141,0x2fa,0x2f0,0x215,0x0af,0x086,0x00e,0x17d,0x1b1, // 464
518 0x2cd,0x02d,0x06f,0x014,0x254,0x11c,0x2e0,0x08a,0x286,0x19b,0x36d,0x29d,0x08d,0x397,0x02d,0x30c, // 480
519 0x197,0x0a4,0x14c,0x383,0x0a5,0x2d6,0x258,0x145,0x1f2,0x28f,0x165,0x2f0,0x300,0x0df,0x351,0x287, // 496
520 0x03f,0x136,0x35f,0x0fb,0x16e,0x130,0x11a,0x2e2,0x2a3,0x19a,0x185,0x0f4,0x01f,0x079,0x12f,0x107) // 512
521 );
522
523 /**
524 * This is the class constructor.
525 * Creates a PDF417 object
526 * @param $code (string) code to represent using PDF417
527 * @param $ecl (int) error correction level (0-8); default -1 = automatic correction level
528 * @param $aspectratio (float) the width to height of the symbol (excluding quiet zones)
529 * @param $macro (array) information for macro block
530 * @public
531 */
532 public function __construct($code, $ecl=-1, $aspectratio=2, $macro=array()) {
533 $barcode_array = array();
534 if ((is_null($code)) OR ($code == '\0') OR ($code == '')) {
535 return false;
536 }
537 // get the input sequence array
538 $sequence = $this->getInputSequences($code);
539 $codewords = array(); // array of code-words
540 foreach($sequence as $seq) {
541 $cw = $this->getCompaction($seq[0], $seq[1], true);
542 $codewords = array_merge($codewords, $cw);
543 }
544 if ($codewords[0] == 900) {
545 // Text Alpha is the default mode, so remove the first code
546 array_shift($codewords);
547 }
548 // count number of codewords
549 $numcw = count($codewords);
550 if ($numcw > 925) {
551 // reached maximum data codeword capacity
552 return false;
553 }
554 // build macro control block codewords
555 if (!empty($macro)) {
556 $macrocw = array();
557 // beginning of macro control block
558 $macrocw[] = 928;
559 // segment index
560 $cw = $this->getCompaction(902, sprintf('%05d', $macro['segment_index']), false);
561 $macrocw = array_merge($macrocw, $cw);
562 // file ID
563 $cw = $this->getCompaction(900, $macro['file_id'], false);
564 $macrocw = array_merge($macrocw, $cw);
565 // optional fields
566 $optmodes = array(900,902,902,900,900,902,902);
567 $optsize = array(-1,2,4,-1,-1,-1,2);
568 foreach ($optmodes as $k => $omode) {
569 if (isset($macro['option_'.$k])) {
570 $macrocw[] = 923;
571 $macrocw[] = $k;
572 if ($optsize[$k] == 2) {
573 $macro['option_'.$k] = sprintf('%05d', $macro['option_'.$k]);
574 } elseif ($optsize[$k] == 4) {
575 $macro['option_'.$k] = sprintf('%010d', $macro['option_'.$k]);
576 }
577 $cw = $this->getCompaction($omode, $macro['option_'.$k], false);
578 $macrocw = array_merge($macrocw, $cw);
579 }
580 }
581 if ($macro['segment_index'] == ($macro['segment_total'] - 1)) {
582 // end of control block
583 $macrocw[] = 922;
584 }
585 // update total codewords
586 $numcw += count($macrocw);
587 }
588 // set error correction level
589 $ecl = $this->getErrorCorrectionLevel($ecl, $numcw);
590 // number of codewords for error correction
591 $errsize = (2 << $ecl);
592 // calculate number of columns (number of codewords per row) and rows
593 $nce = ($numcw + $errsize + 1);
594 $cols = round((sqrt(4761 + (68 * $aspectratio * ROWHEIGHT * $nce)) - 69) / 34);
595 // adjust cols
596 if ($cols < 1) {
597 $cols = 1;
598 } elseif ($cols > 30) {
599 $cols = 30;
600 }
601 $rows = ceil($nce / $cols);
602 $size = ($cols * $rows);
603 // adjust rows
604 if (($rows < 3) OR ($rows > 90)) {
605 if ($rows < 3) {
606 $rows = 3;
607 } elseif ($rows > 90) {
608 $rows = 90;
609 }
610 $cols = ceil($size / $rows);
611 $size = ($cols * $rows);
612 }
613 if ($size > 928) {
614 // set dimensions to get maximum capacity
615 if (abs($aspectratio - (17 * 29 / 32)) < abs($aspectratio - (17 * 16 / 58))) {
616 $cols = 29;
617 $rows = 32;
618 } else {
619 $cols = 16;
620 $rows = 58;
621 }
622 $size = 928;
623 }
624 // calculate padding
625 $pad = ($size - $nce);
626 if ($pad > 0) {
627 if (($size - $rows) == $nce) {
628 --$rows;
629 $size -= $rows;
630 } else {
631 // add pading
632 $codewords = array_merge($codewords, array_fill(0, $pad, 900));
633 }
634 }
635 if (!empty($macro)) {
636 // add macro section
637 $codewords = array_merge($codewords, $macrocw);
638 }
639 // Symbol Lenght Descriptor (number of data codewords including Symbol Lenght Descriptor and pad codewords)
640 $sld = $size - $errsize;
641 // add symbol length description
642 array_unshift($codewords, $sld);
643 // calculate error correction
644 $ecw = $this->getErrorCorrection($codewords, $ecl);
645 // add error correction codewords
646 $codewords = array_merge($codewords, $ecw);
647 // add horizontal quiet zones to start and stop patterns
648 $pstart = str_repeat('0', QUIETH).$this->start_pattern;
649 $pstop = $this->stop_pattern.str_repeat('0', QUIETH);
650 $barcode_array['num_rows'] = ($rows * ROWHEIGHT) + (2 * QUIETV);
651 $barcode_array['num_cols'] = (($cols + 2) * 17) + 35 + (2 * QUIETH);
652 $barcode_array['bcode'] = array();
653 // build rows for vertical quiet zone
654 if (QUIETV > 0) {
655 $empty_row = array_fill(0, $barcode_array['num_cols'], 0);
656 for ($i = 0; $i < QUIETV; ++$i) {
657 // add vertical quiet rows
658 $barcode_array['bcode'][] = $empty_row;
659 }
660 }
661 $k = 0; // codeword index
662 $cid = 0; // initial cluster
663 // for each row
664 for ($r = 0; $r < $rows; ++$r) {
665 // row start code
666 $row = $pstart;
667 switch ($cid) {
668 case 0: {
669 $L = ((30 * intval($r / 3)) + intval(($rows - 1) / 3));
670 break;
671 }
672 case 1: {
673 $L = ((30 * intval($r / 3)) + ($ecl * 3) + (($rows - 1) % 3));
674 break;
675 }
676 case 2: {
677 $L = ((30 * intval($r / 3)) + ($cols - 1));
678 break;
679 }
680 }
681 // left row indicator
682 $row .= sprintf('%17b', $this->clusters[$cid][$L]);
683 // for each column
684 for ($c = 0; $c < $cols; ++$c) {
685 $row .= sprintf('%17b', $this->clusters[$cid][$codewords[$k]]);
686 ++$k;
687 }
688 switch ($cid) {
689 case 0: {
690 $L = ((30 * intval($r / 3)) + ($cols - 1));
691 break;
692 }
693 case 1: {
694 $L = ((30 * intval($r / 3)) + intval(($rows - 1) / 3));
695 break;
696 }
697 case 2: {
698 $L = ((30 * intval($r / 3)) + ($ecl * 3) + (($rows - 1) % 3));
699 break;
700 }
701 }
702 // right row indicator
703 $row .= sprintf('%17b', $this->clusters[$cid][$L]);
704 // row stop code
705 $row .= $pstop;
706 // convert the string to array
707 $arow = preg_split('//', $row, -1, PREG_SPLIT_NO_EMPTY);
708 // duplicate row to get the desired height
709 for ($h = 0; $h < ROWHEIGHT; ++$h) {
710 $barcode_array['bcode'][] = $arow;
711 }
712 ++$cid;
713 if ($cid > 2) {
714 $cid = 0;
715 }
716 }
717 if (QUIETV > 0) {
718 for ($i = 0; $i < QUIETV; ++$i) {
719 // add vertical quiet rows
720 $barcode_array['bcode'][] = $empty_row;
721 }
722 }
723 $this->barcode_array = $barcode_array;
724 }
725
726 /**
727 * Returns a barcode array which is readable by TCPDF
728 * @return array barcode array readable by TCPDF;
729 * @public
730 */
731 public function getBarcodeArray() {
732 return $this->barcode_array;
733 }
734
735 /**
736 * Returns the error correction level (0-8) to be used
737 * @param $ecl (int) error correction level
738 * @param $numcw (int) number of data codewords
739 * @return int error correction level
740 * @protected
741 */
742 protected function getErrorCorrectionLevel($ecl, $numcw) {
743 // get maximum correction level
744 $maxecl = 8; // starting error level
745 $maxerrsize = (928 - $numcw); // available codewords for error
746 while ($maxecl > 0) {
747 $errsize = (2 << $ecl);
748 if ($maxerrsize >= $errsize) {
749 break;
750 }
751 --$maxecl;
752 }
753 // check for automatic levels
754 if (($ecl < 0) OR ($ecl > 8)) {
755 if ($numcw < 41) {
756 $ecl = 2;
757 } elseif ($numcw < 161) {
758 $ecl = 3;
759 } elseif ($numcw < 321) {
760 $ecl = 4;
761 } elseif ($numcw < 864) {
762 $ecl = 5;
763 } else {
764 $ecl = $maxecl;
765 }
766 }
767 if ($ecl > $maxecl) {
768 $ecl = $maxecl;
769 }
770 return $ecl;
771 }
772
773 /**
774 * Returns the error correction codewords
775 * @param $cw (array) array of codewords including Symbol Lenght Descriptor and pad
776 * @param $ecl (int) error correction level 0-8
777 * @return array of error correction codewords
778 * @protected
779 */
780 protected function getErrorCorrection($cw, $ecl) {
781 // get error correction coefficients
782 $ecc = $this->rsfactors[$ecl];
783 // number of error correction factors
784 $eclsize = (2 << $ecl);
785 // maximum index for $rsfactors[$ecl]
786 $eclmaxid = ($eclsize - 1);
787 // initialize array of error correction codewords
788 $ecw = array_fill(0, $eclsize, 0);
789 // for each data codeword
790 foreach($cw as $k => $d) {
791 $t1 = ($d + $ecw[$eclmaxid]) % 929;
792 for ($j = $eclmaxid; $j > 0; --$j) {
793 $t2 = ($t1 * $ecc[$j]) % 929;
794 $t3 = 929 - $t2;
795 $ecw[$j] = ($ecw[($j - 1)] + $t3) % 929;
796 }
797 $t2 = ($t1 * $ecc[0]) % 929;
798 $t3 = 929 - $t2;
799 $ecw[0] = $t3 % 929;
800 }
801 foreach($ecw as $j => $e) {
802 if ($e != 0) {
803 $ecw[$j] = 929 - $e;
804 }
805 }
806 $ecw = array_reverse($ecw);
807 return $ecw;
808 }
809
810 /**
811 * Create array of sequences from input
812 * @param $code (string) code
813 * @return bidimensional array containing characters and classification
814 * @protected
815 */
816 protected function getInputSequences($code) {
817 $sequence_array = array(); // array to be returned
818 $numseq = array();
819 // get numeric sequences
820 preg_match_all('/([0-9]{13,44})/', $code, $numseq, PREG_OFFSET_CAPTURE);
821 $numseq[1][] = array('', strlen($code));
822 $offset = 0;
823 foreach($numseq[1] as $seq) {
824 $seqlen = strlen($seq[0]);
825 if ($seq[1] > 0) {
826 // extract text sequence before the number sequence
827 $prevseq = substr($code, $offset, ($seq[1] - $offset));
828 $textseq = array();
829 // get text sequences
830 preg_match_all('/([\x09\x0a\x0d\x20-\x7e]{5,})/', $prevseq, $textseq, PREG_OFFSET_CAPTURE);
831 $textseq[1][] = array('', strlen($prevseq));
832 $txtoffset = 0;
833 foreach($textseq[1] as $txtseq) {
834 $txtseqlen = strlen($txtseq[0]);
835 if ($txtseq[1] > 0) {
836 // extract byte sequence before the text sequence
837 $prevtxtseq = substr($prevseq, $txtoffset, ($txtseq[1] - $txtoffset));
838 if (strlen($prevtxtseq) > 0) {
839 // add BYTE sequence
840 if ((strlen($prevtxtseq) == 1) AND ((count($sequence_array) > 0) AND ($sequence_array[(count($sequence_array) - 1)][0] == 900))) {
841 $sequence_array[] = array(913, $prevtxtseq);
842 } elseif ((strlen($prevtxtseq) % 6) == 0) {
843 $sequence_array[] = array(924, $prevtxtseq);
844 } else {
845 $sequence_array[] = array(901, $prevtxtseq);
846 }
847 }
848 }
849 if ($txtseqlen > 0) {
850 // add numeric sequence
851 $sequence_array[] = array(900, $txtseq[0]);
852 }
853 $txtoffset = $txtseq[1] + $txtseqlen;
854 }
855 }
856 if ($seqlen > 0) {
857 // add numeric sequence
858 $sequence_array[] = array(902, $seq[0]);
859 }
860 $offset = $seq[1] + $seqlen;
861 }
862 return $sequence_array;
863 }
864
865 /**
866 * Compact data by mode.
867 * @param $mode (int) compaction mode number
868 * @param $code (string) data to compact
869 * @param $addmode (boolean) if true add the mode codeword at first position
870 * @return array of codewords
871 * @protected
872 */
873 protected function getCompaction($mode, $code, $addmode=true) {
874 $cw = array(); // array of codewords to return
875 switch($mode) {
876 case 900: { // Text Compaction mode latch
877 $submode = 0; // default Alpha sub-mode
878 $txtarr = array(); // array of characters and sub-mode switching characters
879 $codelen = strlen($code);
880 for ($i = 0; $i < $codelen; ++$i) {
881 $chval = ord($code{$i});
882 if (($k = array_search($chval, $this->textsubmodes[$submode])) !== false) {
883 // we are on the same sub-mode
884 $txtarr[] = $k;
885 } else {
886 // the sub-mode is changed
887 for ($s = 0; $s < 4; ++$s) {
888 // search new sub-mode
889 if (($s != $submode) AND (($k = array_search($chval, $this->textsubmodes[$s])) !== false)) {
890 // $s is the new submode
891 if (((($i + 1) == $codelen) OR ((($i + 1) < $codelen) AND (array_search(ord($code{($i + 1)}), $this->textsubmodes[$submode]) !== false))) AND (($s == 3) OR (($s == 0) AND ($submode == 1)))) {
892 // shift (temporary change only for this char)
893 if ($s == 3) {
894 // shift to puntuaction
895 $txtarr[] = 29;
896 } else {
897 // shift from lower to alpha
898 $txtarr[] = 27;
899 }
900 } else {
901 // latch
902 $txtarr = array_merge($txtarr, $this->textlatch[''.$submode.$s]);
903 // set new submode
904 $submode = $s;
905 }
906 // add characted code to array
907 $txtarr[] = $k;
908 break;
909 }
910 }
911 }
912 }
913 $txtarrlen = count($txtarr);
914 if (($txtarrlen % 2) != 0) {
915 // add padding
916 $txtarr[] = 29;
917 ++$txtarrlen;
918 }
919 // calculate codewords
920 for ($i = 0; $i < $txtarrlen; $i += 2) {
921 $cw[] = (30 * $txtarr[$i]) + $txtarr[($i + 1)];
922 }
923 break;
924 }
925 case 901:
926 case 924: { // Byte Compaction mode latch
927 while (($codelen = strlen($code)) > 0) {
928 if ($codelen > 6) {
929 $rest = substr($code, 6);
930 $code = substr($code, 0, 6);
931 $sublen = 6;
932 } else {
933 $rest = '';
934 $sublen = strlen($code);
935 }
936 if ($sublen == 6) {
937 $t = bcmul(''.ord($code[0]), '1099511627776');
938 $t = bcadd($t, bcmul(''.ord($code[1]), '4294967296'));
939 $t = bcadd($t, bcmul(''.ord($code[2]), '16777216'));
940 $t = bcadd($t, bcmul(''.ord($code[3]), '65536'));
941 $t = bcadd($t, bcmul(''.ord($code[4]), '256'));
942 $t = bcadd($t, ''.ord($code[5]));
943 // tmp array for the 6 bytes block
944 $cw6 = array();
945 do {
946 $d = bcmod($t, '900');
947 $t = bcdiv($t, '900');
948 // prepend the value to the beginning of the array
949 array_unshift($cw6, $d);
950 } while ($t != '0');
951 // append the result array at the end
952 $cw = array_merge($cw, $cw6);
953 } else {
954 for ($i = 0; $i < $sublen; ++$i) {
955 $cw[] = ord($code{$i});
956 }
957 }
958 $code = $rest;
959 }
960 break;
961 }
962 case 902: { // Numeric Compaction mode latch
963 while (($codelen = strlen($code)) > 0) {
964 if ($codelen > 44) {
965 $rest = substr($code, 44);
966 $code = substr($code, 0, 44);
967 } else {
968 $rest = '';
969 }
970 $t = '1'.$code;
971 do {
972 $d = bcmod($t, '900');
973 $t = bcdiv($t, '900');
974 array_unshift($cw, $d);
975 } while ($t != '0');
976 $code = $rest;
977 }
978 break;
979 }
980 case 913: { // Byte Compaction mode shift
981 $cw[] = ord($code);
982 break;
983 }
984 }
985 if ($addmode) {
986 // add the compaction mode codeword at the beginning
987 array_unshift($cw, $mode);
988 }
989 return $cw;
990 }
991
992} // end PDF417 class
993
994//============================================================+
995// END OF FILE
996//============================================================+
diff --git a/inc/3rdparty/libraries/tcpdf/include/barcodes/qrcode.php b/inc/3rdparty/libraries/tcpdf/include/barcodes/qrcode.php
new file mode 100644
index 00000000..3127fe68
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/include/barcodes/qrcode.php
@@ -0,0 +1,2866 @@
1<?php
2//============================================================+
3// File name : qrcode.php
4// Version : 1.0.010
5// Begin : 2010-03-22
6// Last Update : 2012-07-25
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) 2010-2012 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 GNU Lesser General Public License
25// along with TCPDF. If not, see <http://www.gnu.org/licenses/>.
26//
27// See LICENSE.TXT file for more information.
28// -------------------------------------------------------------------
29//
30// DESCRIPTION :
31//
32// Class to create QR-code arrays for TCPDF class.
33// QR Code symbol is a 2D barcode that can be scanned by
34// handy terminals such as a mobile phone with CCD.
35// The capacity of QR Code is up to 7000 digits or 4000
36// characters, and has high robustness.
37// This class supports QR Code model 2, described in
38// JIS (Japanese Industrial Standards) X0510:2004
39// or ISO/IEC 18004.
40// Currently the following features are not supported:
41// ECI and FNC1 mode, Micro QR Code, QR Code model 1,
42// Structured mode.
43//
44// This class is derived from the following projects:
45// ---------------------------------------------------------
46// "PHP QR Code encoder"
47// License: GNU-LGPLv3
48// Copyright (C) 2010 by Dominik Dzienia <deltalab at poczta dot fm>
49// http://phpqrcode.sourceforge.net/
50// https://sourceforge.net/projects/phpqrcode/
51//
52// The "PHP QR Code encoder" is based on
53// "C libqrencode library" (ver. 3.1.1)
54// License: GNU-LGPL 2.1
55// Copyright (C) 2006-2010 by Kentaro Fukuchi
56// http://megaui.net/fukuchi/works/qrencode/index.en.html
57//
58// Reed-Solomon code encoder is written by Phil Karn, KA9Q.
59// Copyright (C) 2002-2006 Phil Karn, KA9Q
60//
61// QR Code is registered trademark of DENSO WAVE INCORPORATED
62// http://www.denso-wave.com/qrcode/index-e.html
63// ---------------------------------------------------------
64//============================================================+
65
66/**
67 * @file
68 * Class to create QR-code arrays for TCPDF class.
69 * QR Code symbol is a 2D barcode that can be scanned by handy terminals such as a mobile phone with CCD.
70 * The capacity of QR Code is up to 7000 digits or 4000 characters, and has high robustness.
71 * This class supports QR Code model 2, described in JIS (Japanese Industrial Standards) X0510:2004 or ISO/IEC 18004.
72 * Currently the following features are not supported: ECI and FNC1 mode, Micro QR Code, QR Code model 1, Structured mode.
73 *
74 * This class is derived from "PHP QR Code encoder" by Dominik Dzienia (http://phpqrcode.sourceforge.net/) based on "libqrencode C library 3.1.1." by Kentaro Fukuchi (http://megaui.net/fukuchi/works/qrencode/index.en.html), contains Reed-Solomon code written by Phil Karn, KA9Q. QR Code is registered trademark of DENSO WAVE INCORPORATED (http://www.denso-wave.com/qrcode/index-e.html).
75 * Please read comments on this class source file for full copyright and license information.
76 *
77 * @package com.tecnick.tcpdf
78 * @author Nicola Asuni
79 * @version 1.0.010
80 */
81
82// definitions
83if (!defined('QRCODEDEFS')) {
84
85 /**
86 * Indicate that definitions for this class are set
87 */
88 define('QRCODEDEFS', true);
89
90 // -----------------------------------------------------
91
92 // Encoding modes (characters which can be encoded in QRcode)
93
94 /**
95 * Encoding mode
96 */
97 define('QR_MODE_NL', -1);
98
99 /**
100 * Encoding mode numeric (0-9). 3 characters are encoded to 10bit length. In theory, 7089 characters or less can be stored in a QRcode.
101 */
102 define('QR_MODE_NM', 0);
103
104 /**
105 * Encoding mode alphanumeric (0-9A-Z $%*+-./:) 45characters. 2 characters are encoded to 11bit length. In theory, 4296 characters or less can be stored in a QRcode.
106 */
107 define('QR_MODE_AN', 1);
108
109 /**
110 * Encoding mode 8bit byte data. In theory, 2953 characters or less can be stored in a QRcode.
111 */
112 define('QR_MODE_8B', 2);
113
114 /**
115 * Encoding mode KANJI. A KANJI character (multibyte character) is encoded to 13bit length. In theory, 1817 characters or less can be stored in a QRcode.
116 */
117 define('QR_MODE_KJ', 3);
118
119 /**
120 * Encoding mode STRUCTURED (currently unsupported)
121 */
122 define('QR_MODE_ST', 4);
123
124 // -----------------------------------------------------
125
126 // Levels of error correction.
127 // QRcode has a function of an error correcting for miss reading that white is black.
128 // Error correcting is defined in 4 level as below.
129
130 /**
131 * Error correction level L : About 7% or less errors can be corrected.
132 */
133 define('QR_ECLEVEL_L', 0);
134
135 /**
136 * Error correction level M : About 15% or less errors can be corrected.
137 */
138 define('QR_ECLEVEL_M', 1);
139
140 /**
141 * Error correction level Q : About 25% or less errors can be corrected.
142 */
143 define('QR_ECLEVEL_Q', 2);
144
145 /**
146 * Error correction level H : About 30% or less errors can be corrected.
147 */
148 define('QR_ECLEVEL_H', 3);
149
150 // -----------------------------------------------------
151
152 // Version. Size of QRcode is defined as version.
153 // Version is from 1 to 40.
154 // Version 1 is 21*21 matrix. And 4 modules increases whenever 1 version increases.
155 // So version 40 is 177*177 matrix.
156
157 /**
158 * Maximum QR Code version.
159 */
160 define('QRSPEC_VERSION_MAX', 40);
161
162 /**
163 * Maximum matrix size for maximum version (version 40 is 177*177 matrix).
164 */
165 define('QRSPEC_WIDTH_MAX', 177);
166
167 // -----------------------------------------------------
168
169 /**
170 * Matrix index to get width from $capacity array.
171 */
172 define('QRCAP_WIDTH', 0);
173
174 /**
175 * Matrix index to get number of words from $capacity array.
176 */
177 define('QRCAP_WORDS', 1);
178
179 /**
180 * Matrix index to get remainder from $capacity array.
181 */
182 define('QRCAP_REMINDER', 2);
183
184 /**
185 * Matrix index to get error correction level from $capacity array.
186 */
187 define('QRCAP_EC', 3);
188
189 // -----------------------------------------------------
190
191 // Structure (currently usupported)
192
193 /**
194 * Number of header bits for structured mode
195 */
196 define('STRUCTURE_HEADER_BITS', 20);
197
198 /**
199 * Max number of symbols for structured mode
200 */
201 define('MAX_STRUCTURED_SYMBOLS', 16);
202
203 // -----------------------------------------------------
204
205 // Masks
206
207 /**
208 * Down point base value for case 1 mask pattern (concatenation of same color in a line or a column)
209 */
210 define('N1', 3);
211
212 /**
213 * Down point base value for case 2 mask pattern (module block of same color)
214 */
215 define('N2', 3);
216
217 /**
218 * Down point base value for case 3 mask pattern (1:1:3:1:1(dark:bright:dark:bright:dark)pattern in a line or a column)
219 */
220 define('N3', 40);
221
222 /**
223 * Down point base value for case 4 mask pattern (ration of dark modules in whole)
224 */
225 define('N4', 10);
226
227 // -----------------------------------------------------
228
229 // Optimization settings
230
231 /**
232 * if true, estimates best mask (spec. default, but extremally slow; set to false to significant performance boost but (propably) worst quality code
233 */
234 define('QR_FIND_BEST_MASK', true);
235
236 /**
237 * if false, checks all masks available, otherwise value tells count of masks need to be checked, mask id are got randomly
238 */
239 define('QR_FIND_FROM_RANDOM', 2);
240
241 /**
242 * when QR_FIND_BEST_MASK === false
243 */
244 define('QR_DEFAULT_MASK', 2);
245
246 // -----------------------------------------------------
247
248} // end of definitions
249
250// #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
251
252// for compatibility with PHP4
253if (!function_exists('str_split')) {
254 /**
255 * Convert a string to an array (needed for PHP4 compatibility)
256 * @param $string (string) The input string.
257 * @param $split_length (int) Maximum length of the chunk.
258 * @return If the optional split_length parameter is specified, the returned array will be broken down into chunks with each being split_length in length, otherwise each chunk will be one character in length. FALSE is returned if split_length is less than 1. If the split_length length exceeds the length of string , the entire string is returned as the first (and only) array element.
259 */
260 function str_split($string, $split_length=1) {
261 if ((strlen($string) > $split_length) OR (!$split_length)) {
262 do {
263 $c = strlen($string);
264 $parts[] = substr($string, 0, $split_length);
265 $string = substr($string, $split_length);
266 } while ($string !== false);
267 } else {
268 $parts = array($string);
269 }
270 return $parts;
271 }
272}
273
274// #####################################################
275
276/**
277 * @class QRcode
278 * Class to create QR-code arrays for TCPDF class.
279 * QR Code symbol is a 2D barcode that can be scanned by handy terminals such as a mobile phone with CCD.
280 * The capacity of QR Code is up to 7000 digits or 4000 characters, and has high robustness.
281 * This class supports QR Code model 2, described in JIS (Japanese Industrial Standards) X0510:2004 or ISO/IEC 18004.
282 * Currently the following features are not supported: ECI and FNC1 mode, Micro QR Code, QR Code model 1, Structured mode.
283 *
284 * This class is derived from "PHP QR Code encoder" by Dominik Dzienia (http://phpqrcode.sourceforge.net/) based on "libqrencode C library 3.1.1." by Kentaro Fukuchi (http://megaui.net/fukuchi/works/qrencode/index.en.html), contains Reed-Solomon code written by Phil Karn, KA9Q. QR Code is registered trademark of DENSO WAVE INCORPORATED (http://www.denso-wave.com/qrcode/index-e.html).
285 * Please read comments on this class source file for full copyright and license information.
286 *
287 * @package com.tecnick.tcpdf
288 * @author Nicola Asuni
289 * @version 1.0.010
290 */
291class QRcode {
292
293 /**
294 * Barcode array to be returned which is readable by TCPDF.
295 * @protected
296 */
297 protected $barcode_array = array();
298
299 /**
300 * QR code version. Size of QRcode is defined as version. Version is from 1 to 40. Version 1 is 21*21 matrix. And 4 modules increases whenever 1 version increases. So version 40 is 177*177 matrix.
301 * @protected
302 */
303 protected $version = 0;
304
305 /**
306 * Levels of error correction. See definitions for possible values.
307 * @protected
308 */
309 protected $level = QR_ECLEVEL_L;
310
311 /**
312 * Encoding mode.
313 * @protected
314 */
315 protected $hint = QR_MODE_8B;
316
317 /**
318 * Boolean flag, if true the input string will be converted to uppercase.
319 * @protected
320 */
321 protected $casesensitive = true;
322
323 /**
324 * Structured QR code (not supported yet).
325 * @protected
326 */
327 protected $structured = 0;
328
329 /**
330 * Mask data.
331 * @protected
332 */
333 protected $data;
334
335 // FrameFiller
336
337 /**
338 * Width.
339 * @protected
340 */
341 protected $width;
342
343 /**
344 * Frame.
345 * @protected
346 */
347 protected $frame;
348
349 /**
350 * X position of bit.
351 * @protected
352 */
353 protected $x;
354
355 /**
356 * Y position of bit.
357 * @protected
358 */
359 protected $y;
360
361 /**
362 * Direction.
363 * @protected
364 */
365 protected $dir;
366
367 /**
368 * Single bit value.
369 * @protected
370 */
371 protected $bit;
372
373 // ---- QRrawcode ----
374
375 /**
376 * Data code.
377 * @protected
378 */
379 protected $datacode = array();
380
381 /**
382 * Error correction code.
383 * @protected
384 */
385 protected $ecccode = array();
386
387 /**
388 * Blocks.
389 * @protected
390 */
391 protected $blocks;
392
393 /**
394 * Reed-Solomon blocks.
395 * @protected
396 */
397 protected $rsblocks = array(); //of RSblock
398
399 /**
400 * Counter.
401 * @protected
402 */
403 protected $count;
404
405 /**
406 * Data length.
407 * @protected
408 */
409 protected $dataLength;
410
411 /**
412 * Error correction length.
413 * @protected
414 */
415 protected $eccLength;
416
417 /**
418 * Value b1.
419 * @protected
420 */
421 protected $b1;
422
423 // ---- QRmask ----
424
425 /**
426 * Run length.
427 * @protected
428 */
429 protected $runLength = array();
430
431 // ---- QRsplit ----
432
433 /**
434 * Input data string.
435 * @protected
436 */
437 protected $dataStr = '';
438
439 /**
440 * Input items.
441 * @protected
442 */
443 protected $items;
444
445 // Reed-Solomon items
446
447 /**
448 * Reed-Solomon items.
449 * @protected
450 */
451 protected $rsitems = array();
452
453 /**
454 * Array of frames.
455 * @protected
456 */
457 protected $frames = array();
458
459 /**
460 * Alphabet-numeric convesion table.
461 * @protected
462 */
463 protected $anTable = array(
464 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
465 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
466 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, //
467 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, //
468 -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, //
469 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, //
470 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
471 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 //
472 );
473
474 /**
475 * Array Table of the capacity of symbols.
476 * See Table 1 (pp.13) and Table 12-16 (pp.30-36), JIS X0510:2004.
477 * @protected
478 */
479 protected $capacity = array(
480 array( 0, 0, 0, array( 0, 0, 0, 0)), //
481 array( 21, 26, 0, array( 7, 10, 13, 17)), // 1
482 array( 25, 44, 7, array( 10, 16, 22, 28)), //
483 array( 29, 70, 7, array( 15, 26, 36, 44)), //
484 array( 33, 100, 7, array( 20, 36, 52, 64)), //
485 array( 37, 134, 7, array( 26, 48, 72, 88)), // 5
486 array( 41, 172, 7, array( 36, 64, 96, 112)), //
487 array( 45, 196, 0, array( 40, 72, 108, 130)), //
488 array( 49, 242, 0, array( 48, 88, 132, 156)), //
489 array( 53, 292, 0, array( 60, 110, 160, 192)), //
490 array( 57, 346, 0, array( 72, 130, 192, 224)), // 10
491 array( 61, 404, 0, array( 80, 150, 224, 264)), //
492 array( 65, 466, 0, array( 96, 176, 260, 308)), //
493 array( 69, 532, 0, array( 104, 198, 288, 352)), //
494 array( 73, 581, 3, array( 120, 216, 320, 384)), //
495 array( 77, 655, 3, array( 132, 240, 360, 432)), // 15
496 array( 81, 733, 3, array( 144, 280, 408, 480)), //
497 array( 85, 815, 3, array( 168, 308, 448, 532)), //
498 array( 89, 901, 3, array( 180, 338, 504, 588)), //
499 array( 93, 991, 3, array( 196, 364, 546, 650)), //
500 array( 97, 1085, 3, array( 224, 416, 600, 700)), // 20
501 array(101, 1156, 4, array( 224, 442, 644, 750)), //
502 array(105, 1258, 4, array( 252, 476, 690, 816)), //
503 array(109, 1364, 4, array( 270, 504, 750, 900)), //
504 array(113, 1474, 4, array( 300, 560, 810, 960)), //
505 array(117, 1588, 4, array( 312, 588, 870, 1050)), // 25
506 array(121, 1706, 4, array( 336, 644, 952, 1110)), //
507 array(125, 1828, 4, array( 360, 700, 1020, 1200)), //
508 array(129, 1921, 3, array( 390, 728, 1050, 1260)), //
509 array(133, 2051, 3, array( 420, 784, 1140, 1350)), //
510 array(137, 2185, 3, array( 450, 812, 1200, 1440)), // 30
511 array(141, 2323, 3, array( 480, 868, 1290, 1530)), //
512 array(145, 2465, 3, array( 510, 924, 1350, 1620)), //
513 array(149, 2611, 3, array( 540, 980, 1440, 1710)), //
514 array(153, 2761, 3, array( 570, 1036, 1530, 1800)), //
515 array(157, 2876, 0, array( 570, 1064, 1590, 1890)), // 35
516 array(161, 3034, 0, array( 600, 1120, 1680, 1980)), //
517 array(165, 3196, 0, array( 630, 1204, 1770, 2100)), //
518 array(169, 3362, 0, array( 660, 1260, 1860, 2220)), //
519 array(173, 3532, 0, array( 720, 1316, 1950, 2310)), //
520 array(177, 3706, 0, array( 750, 1372, 2040, 2430)) // 40
521 );
522
523 /**
524 * Array Length indicator.
525 * @protected
526 */
527 protected $lengthTableBits = array(
528 array(10, 12, 14),
529 array( 9, 11, 13),
530 array( 8, 16, 16),
531 array( 8, 10, 12)
532 );
533
534 /**
535 * Array Table of the error correction code (Reed-Solomon block).
536 * See Table 12-16 (pp.30-36), JIS X0510:2004.
537 * @protected
538 */
539 protected $eccTable = array(
540 array(array( 0, 0), array( 0, 0), array( 0, 0), array( 0, 0)), //
541 array(array( 1, 0), array( 1, 0), array( 1, 0), array( 1, 0)), // 1
542 array(array( 1, 0), array( 1, 0), array( 1, 0), array( 1, 0)), //
543 array(array( 1, 0), array( 1, 0), array( 2, 0), array( 2, 0)), //
544 array(array( 1, 0), array( 2, 0), array( 2, 0), array( 4, 0)), //
545 array(array( 1, 0), array( 2, 0), array( 2, 2), array( 2, 2)), // 5
546 array(array( 2, 0), array( 4, 0), array( 4, 0), array( 4, 0)), //
547 array(array( 2, 0), array( 4, 0), array( 2, 4), array( 4, 1)), //
548 array(array( 2, 0), array( 2, 2), array( 4, 2), array( 4, 2)), //
549 array(array( 2, 0), array( 3, 2), array( 4, 4), array( 4, 4)), //
550 array(array( 2, 2), array( 4, 1), array( 6, 2), array( 6, 2)), // 10
551 array(array( 4, 0), array( 1, 4), array( 4, 4), array( 3, 8)), //
552 array(array( 2, 2), array( 6, 2), array( 4, 6), array( 7, 4)), //
553 array(array( 4, 0), array( 8, 1), array( 8, 4), array(12, 4)), //
554 array(array( 3, 1), array( 4, 5), array(11, 5), array(11, 5)), //
555 array(array( 5, 1), array( 5, 5), array( 5, 7), array(11, 7)), // 15
556 array(array( 5, 1), array( 7, 3), array(15, 2), array( 3, 13)), //
557 array(array( 1, 5), array(10, 1), array( 1, 15), array( 2, 17)), //
558 array(array( 5, 1), array( 9, 4), array(17, 1), array( 2, 19)), //
559 array(array( 3, 4), array( 3, 11), array(17, 4), array( 9, 16)), //
560 array(array( 3, 5), array( 3, 13), array(15, 5), array(15, 10)), // 20
561 array(array( 4, 4), array(17, 0), array(17, 6), array(19, 6)), //
562 array(array( 2, 7), array(17, 0), array( 7, 16), array(34, 0)), //
563 array(array( 4, 5), array( 4, 14), array(11, 14), array(16, 14)), //
564 array(array( 6, 4), array( 6, 14), array(11, 16), array(30, 2)), //
565 array(array( 8, 4), array( 8, 13), array( 7, 22), array(22, 13)), // 25
566 array(array(10, 2), array(19, 4), array(28, 6), array(33, 4)), //
567 array(array( 8, 4), array(22, 3), array( 8, 26), array(12, 28)), //
568 array(array( 3, 10), array( 3, 23), array( 4, 31), array(11, 31)), //
569 array(array( 7, 7), array(21, 7), array( 1, 37), array(19, 26)), //
570 array(array( 5, 10), array(19, 10), array(15, 25), array(23, 25)), // 30
571 array(array(13, 3), array( 2, 29), array(42, 1), array(23, 28)), //
572 array(array(17, 0), array(10, 23), array(10, 35), array(19, 35)), //
573 array(array(17, 1), array(14, 21), array(29, 19), array(11, 46)), //
574 array(array(13, 6), array(14, 23), array(44, 7), array(59, 1)), //
575 array(array(12, 7), array(12, 26), array(39, 14), array(22, 41)), // 35
576 array(array( 6, 14), array( 6, 34), array(46, 10), array( 2, 64)), //
577 array(array(17, 4), array(29, 14), array(49, 10), array(24, 46)), //
578 array(array( 4, 18), array(13, 32), array(48, 14), array(42, 32)), //
579 array(array(20, 4), array(40, 7), array(43, 22), array(10, 67)), //
580 array(array(19, 6), array(18, 31), array(34, 34), array(20, 61)) // 40
581 );
582
583 /**
584 * Array Positions of alignment patterns.
585 * This array includes only the second and the third position of the alignment patterns. Rest of them can be calculated from the distance between them.
586 * See Table 1 in Appendix E (pp.71) of JIS X0510:2004.
587 * @protected
588 */
589 protected $alignmentPattern = array(
590 array( 0, 0),
591 array( 0, 0), array(18, 0), array(22, 0), array(26, 0), array(30, 0), // 1- 5
592 array(34, 0), array(22, 38), array(24, 42), array(26, 46), array(28, 50), // 6-10
593 array(30, 54), array(32, 58), array(34, 62), array(26, 46), array(26, 48), // 11-15
594 array(26, 50), array(30, 54), array(30, 56), array(30, 58), array(34, 62), // 16-20
595 array(28, 50), array(26, 50), array(30, 54), array(28, 54), array(32, 58), // 21-25
596 array(30, 58), array(34, 62), array(26, 50), array(30, 54), array(26, 52), // 26-30
597 array(30, 56), array(34, 60), array(30, 58), array(34, 62), array(30, 54), // 31-35
598 array(24, 50), array(28, 54), array(32, 58), array(26, 54), array(30, 58) // 35-40
599 );
600
601 /**
602 * Array Version information pattern (BCH coded).
603 * See Table 1 in Appendix D (pp.68) of JIS X0510:2004.
604 * size: [QRSPEC_VERSION_MAX - 6]
605 * @protected
606 */
607 protected $versionPattern = array(
608 0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d, //
609 0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9, //
610 0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75, //
611 0x1f250, 0x209d5, 0x216f0, 0x228ba, 0x2379f, 0x24b0b, 0x2542e, 0x26a64, //
612 0x27541, 0x28c69
613 );
614
615 /**
616 * Array Format information
617 * @protected
618 */
619 protected $formatInfo = array(
620 array(0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976), //
621 array(0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0), //
622 array(0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed), //
623 array(0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b) //
624 );
625
626
627 // -------------------------------------------------
628 // -------------------------------------------------
629
630
631 /**
632 * This is the class constructor.
633 * Creates a QRcode object
634 * @param $code (string) code to represent using QRcode
635 * @param $eclevel (string) error level: <ul><li>L : About 7% or less errors can be corrected.</li><li>M : About 15% or less errors can be corrected.</li><li>Q : About 25% or less errors can be corrected.</li><li>H : About 30% or less errors can be corrected.</li></ul>
636 * @public
637 * @since 1.0.000
638 */
639 public function __construct($code, $eclevel = 'L') {
640 $barcode_array = array();
641 if ((is_null($code)) OR ($code == '\0') OR ($code == '')) {
642 return false;
643 }
644 // set error correction level
645 $this->level = array_search($eclevel, array('L', 'M', 'Q', 'H'));
646 if ($this->level === false) {
647 $this->level = QR_ECLEVEL_L;
648 }
649 if (($this->hint != QR_MODE_8B) AND ($this->hint != QR_MODE_KJ)) {
650 return false;
651 }
652 if (($this->version < 0) OR ($this->version > QRSPEC_VERSION_MAX)) {
653 return false;
654 }
655 $this->items = array();
656 $this->encodeString($code);
657 if (is_null($this->data)) {
658 return false;
659 }
660 $qrTab = $this->binarize($this->data);
661 $size = count($qrTab);
662 $barcode_array['num_rows'] = $size;
663 $barcode_array['num_cols'] = $size;
664 $barcode_array['bcode'] = array();
665 foreach ($qrTab as $line) {
666 $arrAdd = array();
667 foreach (str_split($line) as $char) {
668 $arrAdd[] = ($char=='1')?1:0;
669 }
670 $barcode_array['bcode'][] = $arrAdd;
671 }
672 $this->barcode_array = $barcode_array;
673 }
674
675 /**
676 * Returns a barcode array which is readable by TCPDF
677 * @return array barcode array readable by TCPDF;
678 * @public
679 */
680 public function getBarcodeArray() {
681 return $this->barcode_array;
682 }
683
684 /**
685 * Convert the frame in binary form
686 * @param $frame (array) array to binarize
687 * @return array frame in binary form
688 */
689 protected function binarize($frame) {
690 $len = count($frame);
691 // the frame is square (width = height)
692 foreach ($frame as &$frameLine) {
693 for ($i=0; $i<$len; $i++) {
694 $frameLine[$i] = (ord($frameLine[$i])&1)?'1':'0';
695 }
696 }
697 return $frame;
698 }
699
700 /**
701 * Encode the input string to QR code
702 * @param $string (string) input string to encode
703 */
704 protected function encodeString($string) {
705 $this->dataStr = $string;
706 if (!$this->casesensitive) {
707 $this->toUpper();
708 }
709 $ret = $this->splitString();
710 if ($ret < 0) {
711 return NULL;
712 }
713 $this->encodeMask(-1);
714 }
715
716 /**
717 * Encode mask
718 * @param $mask (int) masking mode
719 */
720 protected function encodeMask($mask) {
721 $spec = array(0, 0, 0, 0, 0);
722 $this->datacode = $this->getByteStream($this->items);
723 if (is_null($this->datacode)) {
724 return NULL;
725 }
726 $spec = $this->getEccSpec($this->version, $this->level, $spec);
727 $this->b1 = $this->rsBlockNum1($spec);
728 $this->dataLength = $this->rsDataLength($spec);
729 $this->eccLength = $this->rsEccLength($spec);
730 $this->ecccode = array_fill(0, $this->eccLength, 0);
731 $this->blocks = $this->rsBlockNum($spec);
732 $ret = $this->init($spec);
733 if ($ret < 0) {
734 return NULL;
735 }
736 $this->count = 0;
737 $this->width = $this->getWidth($this->version);
738 $this->frame = $this->newFrame($this->version);
739 $this->x = $this->width - 1;
740 $this->y = $this->width - 1;
741 $this->dir = -1;
742 $this->bit = -1;
743 // inteleaved data and ecc codes
744 for ($i=0; $i < ($this->dataLength + $this->eccLength); $i++) {
745 $code = $this->getCode();
746 $bit = 0x80;
747 for ($j=0; $j<8; $j++) {
748 $addr = $this->getNextPosition();
749 $this->setFrameAt($addr, 0x02 | (($bit & $code) != 0));
750 $bit = $bit >> 1;
751 }
752 }
753 // remainder bits
754 $j = $this->getRemainder($this->version);
755 for ($i=0; $i<$j; $i++) {
756 $addr = $this->getNextPosition();
757 $this->setFrameAt($addr, 0x02);
758 }
759 // masking
760 $this->runLength = array_fill(0, QRSPEC_WIDTH_MAX + 1, 0);
761 if ($mask < 0) {
762 if (QR_FIND_BEST_MASK) {
763 $masked = $this->mask($this->width, $this->frame, $this->level);
764 } else {
765 $masked = $this->makeMask($this->width, $this->frame, (intval(QR_DEFAULT_MASK) % 8), $this->level);
766 }
767 } else {
768 $masked = $this->makeMask($this->width, $this->frame, $mask, $this->level);
769 }
770 if ($masked == NULL) {
771 return NULL;
772 }
773 $this->data = $masked;
774 }
775
776 // - - - - - - - - - - - - - - - - - - - - - - - - -
777
778 // FrameFiller
779
780 /**
781 * Set frame value at specified position
782 * @param $at (array) x,y position
783 * @param $val (int) value of the character to set
784 */
785 protected function setFrameAt($at, $val) {
786 $this->frame[$at['y']][$at['x']] = chr($val);
787 }
788
789 /**
790 * Get frame value at specified position
791 * @param $at (array) x,y position
792 * @return value at specified position
793 */
794 protected function getFrameAt($at) {
795 return ord($this->frame[$at['y']][$at['x']]);
796 }
797
798 /**
799 * Return the next frame position
800 * @return array of x,y coordinates
801 */
802 protected function getNextPosition() {
803 do {
804 if ($this->bit == -1) {
805 $this->bit = 0;
806 return array('x'=>$this->x, 'y'=>$this->y);
807 }
808 $x = $this->x;
809 $y = $this->y;
810 $w = $this->width;
811 if ($this->bit == 0) {
812 $x--;
813 $this->bit++;
814 } else {
815 $x++;
816 $y += $this->dir;
817 $this->bit--;
818 }
819 if ($this->dir < 0) {
820 if ($y < 0) {
821 $y = 0;
822 $x -= 2;
823 $this->dir = 1;
824 if ($x == 6) {
825 $x--;
826 $y = 9;
827 }
828 }
829 } else {
830 if ($y == $w) {
831 $y = $w - 1;
832 $x -= 2;
833 $this->dir = -1;
834 if ($x == 6) {
835 $x--;
836 $y -= 8;
837 }
838 }
839 }
840 if (($x < 0) OR ($y < 0)) {
841 return NULL;
842 }
843 $this->x = $x;
844 $this->y = $y;
845 } while(ord($this->frame[$y][$x]) & 0x80);
846 return array('x'=>$x, 'y'=>$y);
847 }
848
849 // - - - - - - - - - - - - - - - - - - - - - - - - -
850
851 // QRrawcode
852
853 /**
854 * Initialize code.
855 * @param $spec (array) array of ECC specification
856 * @return 0 in case of success, -1 in case of error
857 */
858 protected function init($spec) {
859 $dl = $this->rsDataCodes1($spec);
860 $el = $this->rsEccCodes1($spec);
861 $rs = $this->init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
862 $blockNo = 0;
863 $dataPos = 0;
864 $eccPos = 0;
865 $endfor = $this->rsBlockNum1($spec);
866 for ($i=0; $i < $endfor; ++$i) {
867 $ecc = array_slice($this->ecccode, $eccPos);
868 $this->rsblocks[$blockNo] = array();
869 $this->rsblocks[$blockNo]['dataLength'] = $dl;
870 $this->rsblocks[$blockNo]['data'] = array_slice($this->datacode, $dataPos);
871 $this->rsblocks[$blockNo]['eccLength'] = $el;
872 $ecc = $this->encode_rs_char($rs, $this->rsblocks[$blockNo]['data'], $ecc);
873 $this->rsblocks[$blockNo]['ecc'] = $ecc;
874 $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc);
875 $dataPos += $dl;
876 $eccPos += $el;
877 $blockNo++;
878 }
879 if ($this->rsBlockNum2($spec) == 0) {
880 return 0;
881 }
882 $dl = $this->rsDataCodes2($spec);
883 $el = $this->rsEccCodes2($spec);
884 $rs = $this->init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
885 if ($rs == NULL) {
886 return -1;
887 }
888 $endfor = $this->rsBlockNum2($spec);
889 for ($i=0; $i < $endfor; ++$i) {
890 $ecc = array_slice($this->ecccode, $eccPos);
891 $this->rsblocks[$blockNo] = array();
892 $this->rsblocks[$blockNo]['dataLength'] = $dl;
893 $this->rsblocks[$blockNo]['data'] = array_slice($this->datacode, $dataPos);
894 $this->rsblocks[$blockNo]['eccLength'] = $el;
895 $ecc = $this->encode_rs_char($rs, $this->rsblocks[$blockNo]['data'], $ecc);
896 $this->rsblocks[$blockNo]['ecc'] = $ecc;
897 $this->ecccode = array_merge(array_slice($this->ecccode, 0, $eccPos), $ecc);
898 $dataPos += $dl;
899 $eccPos += $el;
900 $blockNo++;
901 }
902 return 0;
903 }
904
905 /**
906 * Return Reed-Solomon block code.
907 * @return array rsblocks
908 */
909 protected function getCode() {
910 if ($this->count < $this->dataLength) {
911 $row = $this->count % $this->blocks;
912 $col = $this->count / $this->blocks;
913 if ($col >= $this->rsblocks[0]['dataLength']) {
914 $row += $this->b1;
915 }
916 $ret = $this->rsblocks[$row]['data'][$col];
917 } elseif ($this->count < $this->dataLength + $this->eccLength) {
918 $row = ($this->count - $this->dataLength) % $this->blocks;
919 $col = ($this->count - $this->dataLength) / $this->blocks;
920 $ret = $this->rsblocks[$row]['ecc'][$col];
921 } else {
922 return 0;
923 }
924 $this->count++;
925 return $ret;
926 }
927
928 // - - - - - - - - - - - - - - - - - - - - - - - - -
929
930 // QRmask
931
932 /**
933 * Write Format Information on frame and returns the number of black bits
934 * @param $width (int) frame width
935 * @param $frame (array) frame
936 * @param $mask (array) masking mode
937 * @param $level (int) error correction level
938 * @return int blacks
939 */
940 protected function writeFormatInformation($width, &$frame, $mask, $level) {
941 $blacks = 0;
942 $format = $this->getFormatInfo($mask, $level);
943 for ($i=0; $i<8; ++$i) {
944 if ($format & 1) {
945 $blacks += 2;
946 $v = 0x85;
947 } else {
948 $v = 0x84;
949 }
950 $frame[8][$width - 1 - $i] = chr($v);
951 if ($i < 6) {
952 $frame[$i][8] = chr($v);
953 } else {
954 $frame[$i + 1][8] = chr($v);
955 }
956 $format = $format >> 1;
957 }
958 for ($i=0; $i<7; ++$i) {
959 if ($format & 1) {
960 $blacks += 2;
961 $v = 0x85;
962 } else {
963 $v = 0x84;
964 }
965 $frame[$width - 7 + $i][8] = chr($v);
966 if ($i == 0) {
967 $frame[8][7] = chr($v);
968 } else {
969 $frame[8][6 - $i] = chr($v);
970 }
971 $format = $format >> 1;
972 }
973 return $blacks;
974 }
975
976 /**
977 * mask0
978 * @param $x (int) X position
979 * @param $y (int) Y position
980 * @return int mask
981 */
982 protected function mask0($x, $y) {
983 return ($x + $y) & 1;
984 }
985
986 /**
987 * mask1
988 * @param $x (int) X position
989 * @param $y (int) Y position
990 * @return int mask
991 */
992 protected function mask1($x, $y) {
993 return ($y & 1);
994 }
995
996 /**
997 * mask2
998 * @param $x (int) X position
999 * @param $y (int) Y position
1000 * @return int mask
1001 */
1002 protected function mask2($x, $y) {
1003 return ($x % 3);
1004 }
1005
1006 /**
1007 * mask3
1008 * @param $x (int) X position
1009 * @param $y (int) Y position
1010 * @return int mask
1011 */
1012 protected function mask3($x, $y) {
1013 return ($x + $y) % 3;
1014 }
1015
1016 /**
1017 * mask4
1018 * @param $x (int) X position
1019 * @param $y (int) Y position
1020 * @return int mask
1021 */
1022 protected function mask4($x, $y) {
1023 return (((int)($y / 2)) + ((int)($x / 3))) & 1;
1024 }
1025
1026 /**
1027 * mask5
1028 * @param $x (int) X position
1029 * @param $y (int) Y position
1030 * @return int mask
1031 */
1032 protected function mask5($x, $y) {
1033 return (($x * $y) & 1) + ($x * $y) % 3;
1034 }
1035
1036 /**
1037 * mask6
1038 * @param $x (int) X position
1039 * @param $y (int) Y position
1040 * @return int mask
1041 */
1042 protected function mask6($x, $y) {
1043 return ((($x * $y) & 1) + ($x * $y) % 3) & 1;
1044 }
1045
1046 /**
1047 * mask7
1048 * @param $x (int) X position
1049 * @param $y (int) Y position
1050 * @return int mask
1051 */
1052 protected function mask7($x, $y) {
1053 return ((($x * $y) % 3) + (($x + $y) & 1)) & 1;
1054 }
1055
1056 /**
1057 * Return bitmask
1058 * @param $maskNo (int) mask number
1059 * @param $width (int) width
1060 * @param $frame (array) frame
1061 * @return array bitmask
1062 */
1063 protected function generateMaskNo($maskNo, $width, $frame) {
1064 $bitMask = array_fill(0, $width, array_fill(0, $width, 0));
1065 for ($y=0; $y<$width; ++$y) {
1066 for ($x=0; $x<$width; ++$x) {
1067 if (ord($frame[$y][$x]) & 0x80) {
1068 $bitMask[$y][$x] = 0;
1069 } else {
1070 $maskFunc = call_user_func(array($this, 'mask'.$maskNo), $x, $y);
1071 $bitMask[$y][$x] = ($maskFunc == 0)?1:0;
1072 }
1073 }
1074 }
1075 return $bitMask;
1076 }
1077
1078 /**
1079 * makeMaskNo
1080 * @param $maskNo (int)
1081 * @param $width (int)
1082 * @param $s (int)
1083 * @param $d (int)
1084 * @param $maskGenOnly (boolean)
1085 * @return int b
1086 */
1087 protected function makeMaskNo($maskNo, $width, $s, &$d, $maskGenOnly=false) {
1088 $b = 0;
1089 $bitMask = array();
1090 $bitMask = $this->generateMaskNo($maskNo, $width, $s, $d);
1091 if ($maskGenOnly) {
1092 return;
1093 }
1094 $d = $s;
1095 for ($y=0; $y<$width; ++$y) {
1096 for ($x=0; $x<$width; ++$x) {
1097 if ($bitMask[$y][$x] == 1) {
1098 $d[$y][$x] = chr(ord($s[$y][$x]) ^ ((int)($bitMask[$y][$x])));
1099 }
1100 $b += (int)(ord($d[$y][$x]) & 1);
1101 }
1102 }
1103 return $b;
1104 }
1105
1106 /**
1107 * makeMask
1108 * @param $width (int)
1109 * @param $frame (array)
1110 * @param $maskNo (int)
1111 * @param $level (int)
1112 * @return array mask
1113 */
1114 protected function makeMask($width, $frame, $maskNo, $level) {
1115 $masked = array_fill(0, $width, str_repeat("\0", $width));
1116 $this->makeMaskNo($maskNo, $width, $frame, $masked);
1117 $this->writeFormatInformation($width, $masked, $maskNo, $level);
1118 return $masked;
1119 }
1120
1121 /**
1122 * calcN1N3
1123 * @param $length (int)
1124 * @return int demerit
1125 */
1126 protected function calcN1N3($length) {
1127 $demerit = 0;
1128 for ($i=0; $i<$length; ++$i) {
1129 if ($this->runLength[$i] >= 5) {
1130 $demerit += (N1 + ($this->runLength[$i] - 5));
1131 }
1132 if ($i & 1) {
1133 if (($i >= 3) AND ($i < ($length-2)) AND ($this->runLength[$i] % 3 == 0)) {
1134 $fact = (int)($this->runLength[$i] / 3);
1135 if (($this->runLength[$i-2] == $fact)
1136 AND ($this->runLength[$i-1] == $fact)
1137 AND ($this->runLength[$i+1] == $fact)
1138 AND ($this->runLength[$i+2] == $fact)) {
1139 if (($this->runLength[$i-3] < 0) OR ($this->runLength[$i-3] >= (4 * $fact))) {
1140 $demerit += N3;
1141 } elseif ((($i+3) >= $length) OR ($this->runLength[$i+3] >= (4 * $fact))) {
1142 $demerit += N3;
1143 }
1144 }
1145 }
1146 }
1147 }
1148 return $demerit;
1149 }
1150
1151 /**
1152 * evaluateSymbol
1153 * @param $width (int)
1154 * @param $frame (array)
1155 * @return int demerit
1156 */
1157 protected function evaluateSymbol($width, $frame) {
1158 $head = 0;
1159 $demerit = 0;
1160 for ($y=0; $y<$width; ++$y) {
1161 $head = 0;
1162 $this->runLength[0] = 1;
1163 $frameY = $frame[$y];
1164 if ($y > 0) {
1165 $frameYM = $frame[$y-1];
1166 }
1167 for ($x=0; $x<$width; ++$x) {
1168 if (($x > 0) AND ($y > 0)) {
1169 $b22 = ord($frameY[$x]) & ord($frameY[$x-1]) & ord($frameYM[$x]) & ord($frameYM[$x-1]);
1170 $w22 = ord($frameY[$x]) | ord($frameY[$x-1]) | ord($frameYM[$x]) | ord($frameYM[$x-1]);
1171 if (($b22 | ($w22 ^ 1)) & 1) {
1172 $demerit += N2;
1173 }
1174 }
1175 if (($x == 0) AND (ord($frameY[$x]) & 1)) {
1176 $this->runLength[0] = -1;
1177 $head = 1;
1178 $this->runLength[$head] = 1;
1179 } elseif ($x > 0) {
1180 if ((ord($frameY[$x]) ^ ord($frameY[$x-1])) & 1) {
1181 $head++;
1182 $this->runLength[$head] = 1;
1183 } else {
1184 $this->runLength[$head]++;
1185 }
1186 }
1187 }
1188 $demerit += $this->calcN1N3($head+1);
1189 }
1190 for ($x=0; $x<$width; ++$x) {
1191 $head = 0;
1192 $this->runLength[0] = 1;
1193 for ($y=0; $y<$width; ++$y) {
1194 if (($y == 0) AND (ord($frame[$y][$x]) & 1)) {
1195 $this->runLength[0] = -1;
1196 $head = 1;
1197 $this->runLength[$head] = 1;
1198 } elseif ($y > 0) {
1199 if ((ord($frame[$y][$x]) ^ ord($frame[$y-1][$x])) & 1) {
1200 $head++;
1201 $this->runLength[$head] = 1;
1202 } else {
1203 $this->runLength[$head]++;
1204 }
1205 }
1206 }
1207 $demerit += $this->calcN1N3($head+1);
1208 }
1209 return $demerit;
1210 }
1211
1212 /**
1213 * mask
1214 * @param $width (int)
1215 * @param $frame (array)
1216 * @param $level (int)
1217 * @return array best mask
1218 */
1219 protected function mask($width, $frame, $level) {
1220 $minDemerit = PHP_INT_MAX;
1221 $bestMaskNum = 0;
1222 $bestMask = array();
1223 $checked_masks = array(0, 1, 2, 3, 4, 5, 6, 7);
1224 if (QR_FIND_FROM_RANDOM !== false) {
1225 $howManuOut = 8 - (QR_FIND_FROM_RANDOM % 9);
1226 for ($i = 0; $i < $howManuOut; ++$i) {
1227 $remPos = rand (0, count($checked_masks)-1);
1228 unset($checked_masks[$remPos]);
1229 $checked_masks = array_values($checked_masks);
1230 }
1231 }
1232 $bestMask = $frame;
1233 foreach ($checked_masks as $i) {
1234 $mask = array_fill(0, $width, str_repeat("\0", $width));
1235 $demerit = 0;
1236 $blacks = 0;
1237 $blacks = $this->makeMaskNo($i, $width, $frame, $mask);
1238 $blacks += $this->writeFormatInformation($width, $mask, $i, $level);
1239 $blacks = (int)(100 * $blacks / ($width * $width));
1240 $demerit = (int)((int)(abs($blacks - 50) / 5) * N4);
1241 $demerit += $this->evaluateSymbol($width, $mask);
1242 if ($demerit < $minDemerit) {
1243 $minDemerit = $demerit;
1244 $bestMask = $mask;
1245 $bestMaskNum = $i;
1246 }
1247 }
1248 return $bestMask;
1249 }
1250
1251 // - - - - - - - - - - - - - - - - - - - - - - - - -
1252
1253 // QRsplit
1254
1255 /**
1256 * Return true if the character at specified position is a number
1257 * @param $str (string) string
1258 * @param $pos (int) characted position
1259 * @return boolean true of false
1260 */
1261 protected function isdigitat($str, $pos) {
1262 if ($pos >= strlen($str)) {
1263 return false;
1264 }
1265 return ((ord($str[$pos]) >= ord('0'))&&(ord($str[$pos]) <= ord('9')));
1266 }
1267
1268 /**
1269 * Return true if the character at specified position is an alphanumeric character
1270 * @param $str (string) string
1271 * @param $pos (int) characted position
1272 * @return boolean true of false
1273 */
1274 protected function isalnumat($str, $pos) {
1275 if ($pos >= strlen($str)) {
1276 return false;
1277 }
1278 return ($this->lookAnTable(ord($str[$pos])) >= 0);
1279 }
1280
1281 /**
1282 * identifyMode
1283 * @param $pos (int)
1284 * @return int mode
1285 */
1286 protected function identifyMode($pos) {
1287 if ($pos >= strlen($this->dataStr)) {
1288 return QR_MODE_NL;
1289 }
1290 $c = $this->dataStr[$pos];
1291 if ($this->isdigitat($this->dataStr, $pos)) {
1292 return QR_MODE_NM;
1293 } elseif ($this->isalnumat($this->dataStr, $pos)) {
1294 return QR_MODE_AN;
1295 } elseif ($this->hint == QR_MODE_KJ) {
1296 if ($pos+1 < strlen($this->dataStr)) {
1297 $d = $this->dataStr[$pos+1];
1298 $word = (ord($c) << 8) | ord($d);
1299 if (($word >= 0x8140 && $word <= 0x9ffc) OR ($word >= 0xe040 && $word <= 0xebbf)) {
1300 return QR_MODE_KJ;
1301 }
1302 }
1303 }
1304 return QR_MODE_8B;
1305 }
1306
1307 /**
1308 * eatNum
1309 * @return int run
1310 */
1311 protected function eatNum() {
1312 $ln = $this->lengthIndicator(QR_MODE_NM, $this->version);
1313 $p = 0;
1314 while($this->isdigitat($this->dataStr, $p)) {
1315 $p++;
1316 }
1317 $run = $p;
1318 $mode = $this->identifyMode($p);
1319 if ($mode == QR_MODE_8B) {
1320 $dif = $this->estimateBitsModeNum($run) + 4 + $ln
1321 + $this->estimateBitsMode8(1) // + 4 + l8
1322 - $this->estimateBitsMode8($run + 1); // - 4 - l8
1323 if ($dif > 0) {
1324 return $this->eat8();
1325 }
1326 }
1327 if ($mode == QR_MODE_AN) {
1328 $dif = $this->estimateBitsModeNum($run) + 4 + $ln
1329 + $this->estimateBitsModeAn(1) // + 4 + la
1330 - $this->estimateBitsModeAn($run + 1);// - 4 - la
1331 if ($dif > 0) {
1332 return $this->eatAn();
1333 }
1334 }
1335 $this->items = $this->appendNewInputItem($this->items, QR_MODE_NM, $run, str_split($this->dataStr));
1336 return $run;
1337 }
1338
1339 /**
1340 * eatAn
1341 * @return int run
1342 */
1343 protected function eatAn() {
1344 $la = $this->lengthIndicator(QR_MODE_AN, $this->version);
1345 $ln = $this->lengthIndicator(QR_MODE_NM, $this->version);
1346 $p =1 ;
1347 while($this->isalnumat($this->dataStr, $p)) {
1348 if ($this->isdigitat($this->dataStr, $p)) {
1349 $q = $p;
1350 while($this->isdigitat($this->dataStr, $q)) {
1351 $q++;
1352 }
1353 $dif = $this->estimateBitsModeAn($p) // + 4 + la
1354 + $this->estimateBitsModeNum($q - $p) + 4 + $ln
1355 - $this->estimateBitsModeAn($q); // - 4 - la
1356 if ($dif < 0) {
1357 break;
1358 } else {
1359 $p = $q;
1360 }
1361 } else {
1362 $p++;
1363 }
1364 }
1365 $run = $p;
1366 if (!$this->isalnumat($this->dataStr, $p)) {
1367 $dif = $this->estimateBitsModeAn($run) + 4 + $la
1368 + $this->estimateBitsMode8(1) // + 4 + l8
1369 - $this->estimateBitsMode8($run + 1); // - 4 - l8
1370 if ($dif > 0) {
1371 return $this->eat8();
1372 }
1373 }
1374 $this->items = $this->appendNewInputItem($this->items, QR_MODE_AN, $run, str_split($this->dataStr));
1375 return $run;
1376 }
1377
1378 /**
1379 * eatKanji
1380 * @return int run
1381 */
1382 protected function eatKanji() {
1383 $p = 0;
1384 while($this->identifyMode($p) == QR_MODE_KJ) {
1385 $p += 2;
1386 }
1387 $this->items = $this->appendNewInputItem($this->items, QR_MODE_KJ, $p, str_split($this->dataStr));
1388 return $run;
1389 }
1390
1391 /**
1392 * eat8
1393 * @return int run
1394 */
1395 protected function eat8() {
1396 $la = $this->lengthIndicator(QR_MODE_AN, $this->version);
1397 $ln = $this->lengthIndicator(QR_MODE_NM, $this->version);
1398 $p = 1;
1399 $dataStrLen = strlen($this->dataStr);
1400 while($p < $dataStrLen) {
1401 $mode = $this->identifyMode($p);
1402 if ($mode == QR_MODE_KJ) {
1403 break;
1404 }
1405 if ($mode == QR_MODE_NM) {
1406 $q = $p;
1407 while($this->isdigitat($this->dataStr, $q)) {
1408 $q++;
1409 }
1410 $dif = $this->estimateBitsMode8($p) // + 4 + l8
1411 + $this->estimateBitsModeNum($q - $p) + 4 + $ln
1412 - $this->estimateBitsMode8($q); // - 4 - l8
1413 if ($dif < 0) {
1414 break;
1415 } else {
1416 $p = $q;
1417 }
1418 } elseif ($mode == QR_MODE_AN) {
1419 $q = $p;
1420 while($this->isalnumat($this->dataStr, $q)) {
1421 $q++;
1422 }
1423 $dif = $this->estimateBitsMode8($p) // + 4 + l8
1424 + $this->estimateBitsModeAn($q - $p) + 4 + $la
1425 - $this->estimateBitsMode8($q); // - 4 - l8
1426 if ($dif < 0) {
1427 break;
1428 } else {
1429 $p = $q;
1430 }
1431 } else {
1432 $p++;
1433 }
1434 }
1435 $run = $p;
1436 $this->items = $this->appendNewInputItem($this->items, QR_MODE_8B, $run, str_split($this->dataStr));
1437 return $run;
1438 }
1439
1440 /**
1441 * splitString
1442 * @return (int)
1443 */
1444 protected function splitString() {
1445 while (strlen($this->dataStr) > 0) {
1446 $mode = $this->identifyMode(0);
1447 switch ($mode) {
1448 case QR_MODE_NM: {
1449 $length = $this->eatNum();
1450 break;
1451 }
1452 case QR_MODE_AN: {
1453 $length = $this->eatAn();
1454 break;
1455 }
1456 case QR_MODE_KJ: {
1457 if ($hint == QR_MODE_KJ) {
1458 $length = $this->eatKanji();
1459 } else {
1460 $length = $this->eat8();
1461 }
1462 break;
1463 }
1464 default: {
1465 $length = $this->eat8();
1466 break;
1467 }
1468 }
1469 if ($length == 0) {
1470 return 0;
1471 }
1472 if ($length < 0) {
1473 return -1;
1474 }
1475 $this->dataStr = substr($this->dataStr, $length);
1476 }
1477 return 0;
1478 }
1479
1480 /**
1481 * toUpper
1482 */
1483 protected function toUpper() {
1484 $stringLen = strlen($this->dataStr);
1485 $p = 0;
1486 while ($p < $stringLen) {
1487 $mode = $this->identifyMode(substr($this->dataStr, $p), $this->hint);
1488 if ($mode == QR_MODE_KJ) {
1489 $p += 2;
1490 } else {
1491 if ((ord($this->dataStr[$p]) >= ord('a')) AND (ord($this->dataStr[$p]) <= ord('z'))) {
1492 $this->dataStr[$p] = chr(ord($this->dataStr[$p]) - 32);
1493 }
1494 $p++;
1495 }
1496 }
1497 return $this->dataStr;
1498 }
1499
1500 // - - - - - - - - - - - - - - - - - - - - - - - - -
1501
1502 // QRinputItem
1503
1504 /**
1505 * newInputItem
1506 * @param $mode (int)
1507 * @param $size (int)
1508 * @param $data (array)
1509 * @param $bstream (array)
1510 * @return array input item
1511 */
1512 protected function newInputItem($mode, $size, $data, $bstream=null) {
1513 $setData = array_slice($data, 0, $size);
1514 if (count($setData) < $size) {
1515 $setData = array_merge($setData, array_fill(0, ($size - count($setData)), 0));
1516 }
1517 if (!$this->check($mode, $size, $setData)) {
1518 return NULL;
1519 }
1520 $inputitem = array();
1521 $inputitem['mode'] = $mode;
1522 $inputitem['size'] = $size;
1523 $inputitem['data'] = $setData;
1524 $inputitem['bstream'] = $bstream;
1525 return $inputitem;
1526 }
1527
1528 /**
1529 * encodeModeNum
1530 * @param $inputitem (array)
1531 * @param $version (int)
1532 * @return array input item
1533 */
1534 protected function encodeModeNum($inputitem, $version) {
1535 $words = (int)($inputitem['size'] / 3);
1536 $inputitem['bstream'] = array();
1537 $val = 0x1;
1538 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, $val);
1539 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], $this->lengthIndicator(QR_MODE_NM, $version), $inputitem['size']);
1540 for ($i=0; $i < $words; ++$i) {
1541 $val = (ord($inputitem['data'][$i*3 ]) - ord('0')) * 100;
1542 $val += (ord($inputitem['data'][$i*3+1]) - ord('0')) * 10;
1543 $val += (ord($inputitem['data'][$i*3+2]) - ord('0'));
1544 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 10, $val);
1545 }
1546 if ($inputitem['size'] - $words * 3 == 1) {
1547 $val = ord($inputitem['data'][$words*3]) - ord('0');
1548 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, $val);
1549 } elseif (($inputitem['size'] - ($words * 3)) == 2) {
1550 $val = (ord($inputitem['data'][$words*3 ]) - ord('0')) * 10;
1551 $val += (ord($inputitem['data'][$words*3+1]) - ord('0'));
1552 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 7, $val);
1553 }
1554 return $inputitem;
1555 }
1556
1557 /**
1558 * encodeModeAn
1559 * @param $inputitem (array)
1560 * @param $version (int)
1561 * @return array input item
1562 */
1563 protected function encodeModeAn($inputitem, $version) {
1564 $words = (int)($inputitem['size'] / 2);
1565 $inputitem['bstream'] = array();
1566 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x02);
1567 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], $this->lengthIndicator(QR_MODE_AN, $version), $inputitem['size']);
1568 for ($i=0; $i < $words; ++$i) {
1569 $val = (int)($this->lookAnTable(ord($inputitem['data'][$i*2])) * 45);
1570 $val += (int)($this->lookAnTable(ord($inputitem['data'][($i*2)+1])));
1571 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 11, $val);
1572 }
1573 if ($inputitem['size'] & 1) {
1574 $val = $this->lookAnTable(ord($inputitem['data'][($words * 2)]));
1575 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 6, $val);
1576 }
1577 return $inputitem;
1578 }
1579
1580 /**
1581 * encodeMode8
1582 * @param $inputitem (array)
1583 * @param $version (int)
1584 * @return array input item
1585 */
1586 protected function encodeMode8($inputitem, $version) {
1587 $inputitem['bstream'] = array();
1588 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x4);
1589 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], $this->lengthIndicator(QR_MODE_8B, $version), $inputitem['size']);
1590 for ($i=0; $i < $inputitem['size']; ++$i) {
1591 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 8, ord($inputitem['data'][$i]));
1592 }
1593 return $inputitem;
1594 }
1595
1596 /**
1597 * encodeModeKanji
1598 * @param $inputitem (array)
1599 * @param $version (int)
1600 * @return array input item
1601 */
1602 protected function encodeModeKanji($inputitem, $version) {
1603 $inputitem['bstream'] = array();
1604 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x8);
1605 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], $this->lengthIndicator(QR_MODE_KJ, $version), (int)($inputitem['size'] / 2));
1606 for ($i=0; $i<$inputitem['size']; $i+=2) {
1607 $val = (ord($inputitem['data'][$i]) << 8) | ord($inputitem['data'][$i+1]);
1608 if ($val <= 0x9ffc) {
1609 $val -= 0x8140;
1610 } else {
1611 $val -= 0xc140;
1612 }
1613 $h = ($val >> 8) * 0xc0;
1614 $val = ($val & 0xff) + $h;
1615 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 13, $val);
1616 }
1617 return $inputitem;
1618 }
1619
1620 /**
1621 * encodeModeStructure
1622 * @param $inputitem (array)
1623 * @return array input item
1624 */
1625 protected function encodeModeStructure($inputitem) {
1626 $inputitem['bstream'] = array();
1627 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x03);
1628 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, ord($inputitem['data'][1]) - 1);
1629 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, ord($inputitem['data'][0]) - 1);
1630 $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 8, ord($inputitem['data'][2]));
1631 return $inputitem;
1632 }
1633
1634 /**
1635 * encodeBitStream
1636 * @param $inputitem (array)
1637 * @param $version (int)
1638 * @return array input item
1639 */
1640 protected function encodeBitStream($inputitem, $version) {
1641 $inputitem['bstream'] = array();
1642 $words = $this->maximumWords($inputitem['mode'], $version);
1643 if ($inputitem['size'] > $words) {
1644 $st1 = $this->newInputItem($inputitem['mode'], $words, $inputitem['data']);
1645 $st2 = $this->newInputItem($inputitem['mode'], $inputitem['size'] - $words, array_slice($inputitem['data'], $words));
1646 $st1 = $this->encodeBitStream($st1, $version);
1647 $st2 = $this->encodeBitStream($st2, $version);
1648 $inputitem['bstream'] = array();
1649 $inputitem['bstream'] = $this->appendBitstream($inputitem['bstream'], $st1['bstream']);
1650 $inputitem['bstream'] = $this->appendBitstream($inputitem['bstream'], $st2['bstream']);
1651 } else {
1652 switch($inputitem['mode']) {
1653 case QR_MODE_NM: {
1654 $inputitem = $this->encodeModeNum($inputitem, $version);
1655 break;
1656 }
1657 case QR_MODE_AN: {
1658 $inputitem = $this->encodeModeAn($inputitem, $version);
1659 break;
1660 }
1661 case QR_MODE_8B: {
1662 $inputitem = $this->encodeMode8($inputitem, $version);
1663 break;
1664 }
1665 case QR_MODE_KJ: {
1666 $inputitem = $this->encodeModeKanji($inputitem, $version);
1667 break;
1668 }
1669 case QR_MODE_ST: {
1670 $inputitem = $this->encodeModeStructure($inputitem);
1671 break;
1672 }
1673 default: {
1674 break;
1675 }
1676 }
1677 }
1678 return $inputitem;
1679 }
1680
1681 // - - - - - - - - - - - - - - - - - - - - - - - - -
1682
1683 // QRinput
1684
1685 /**
1686 * Append data to an input object.
1687 * The data is copied and appended to the input object.
1688 * @param $items (arrray) input items
1689 * @param $mode (int) encoding mode.
1690 * @param $size (int) size of data (byte).
1691 * @param $data (array) array of input data.
1692 * @return items
1693 *
1694 */
1695 protected function appendNewInputItem($items, $mode, $size, $data) {
1696 $newitem = $this->newInputItem($mode, $size, $data);
1697 if (!empty($newitem)) {
1698 $items[] = $newitem;
1699 }
1700 return $items;
1701 }
1702
1703 /**
1704 * insertStructuredAppendHeader
1705 * @param $items (array)
1706 * @param $size (int)
1707 * @param $index (int)
1708 * @param $parity (int)
1709 * @return array items
1710 */
1711 protected function insertStructuredAppendHeader($items, $size, $index, $parity) {
1712 if ($size > MAX_STRUCTURED_SYMBOLS) {
1713 return -1;
1714 }
1715 if (($index <= 0) OR ($index > MAX_STRUCTURED_SYMBOLS)) {
1716 return -1;
1717 }
1718 $buf = array($size, $index, $parity);
1719 $entry = $this->newInputItem(QR_MODE_ST, 3, buf);
1720 array_unshift($items, $entry);
1721 return $items;
1722 }
1723
1724 /**
1725 * calcParity
1726 * @param $items (array)
1727 * @return int parity
1728 */
1729 protected function calcParity($items) {
1730 $parity = 0;
1731 foreach ($items as $item) {
1732 if ($item['mode'] != QR_MODE_ST) {
1733 for ($i=$item['size']-1; $i>=0; --$i) {
1734 $parity ^= $item['data'][$i];
1735 }
1736 }
1737 }
1738 return $parity;
1739 }
1740
1741 /**
1742 * checkModeNum
1743 * @param $size (int)
1744 * @param $data (array)
1745 * @return boolean true or false
1746 */
1747 protected function checkModeNum($size, $data) {
1748 for ($i=0; $i<$size; ++$i) {
1749 if ((ord($data[$i]) < ord('0')) OR (ord($data[$i]) > ord('9'))){
1750 return false;
1751 }
1752 }
1753 return true;
1754 }
1755
1756 /**
1757 * Look up the alphabet-numeric convesion table (see JIS X0510:2004, pp.19).
1758 * @param $c (int) character value
1759 * @return value
1760 */
1761 protected function lookAnTable($c) {
1762 return (($c > 127)?-1:$this->anTable[$c]);
1763 }
1764
1765 /**
1766 * checkModeAn
1767 * @param $size (int)
1768 * @param $data (array)
1769 * @return boolean true or false
1770 */
1771 protected function checkModeAn($size, $data) {
1772 for ($i=0; $i<$size; ++$i) {
1773 if ($this->lookAnTable(ord($data[$i])) == -1) {
1774 return false;
1775 }
1776 }
1777 return true;
1778 }
1779
1780 /**
1781 * estimateBitsModeNum
1782 * @param $size (int)
1783 * @return int number of bits
1784 */
1785 protected function estimateBitsModeNum($size) {
1786 $w = (int)($size / 3);
1787 $bits = ($w * 10);
1788 switch($size - ($w * 3)) {
1789 case 1: {
1790 $bits += 4;
1791 break;
1792 }
1793 case 2: {
1794 $bits += 7;
1795 break;
1796 }
1797 }
1798 return $bits;
1799 }
1800
1801 /**
1802 * estimateBitsModeAn
1803 * @param $size (int)
1804 * @return int number of bits
1805 */
1806 protected function estimateBitsModeAn($size) {
1807 $bits = (int)($size * 5.5); // (size / 2 ) * 11
1808 if ($size & 1) {
1809 $bits += 6;
1810 }
1811 return $bits;
1812 }
1813
1814 /**
1815 * estimateBitsMode8
1816 * @param $size (int)
1817 * @return int number of bits
1818 */
1819 protected function estimateBitsMode8($size) {
1820 return (int)($size * 8);
1821 }
1822
1823 /**
1824 * estimateBitsModeKanji
1825 * @param $size (int)
1826 * @return int number of bits
1827 */
1828 protected function estimateBitsModeKanji($size) {
1829 return (int)($size * 6.5); // (size / 2 ) * 13
1830 }
1831
1832 /**
1833 * checkModeKanji
1834 * @param $size (int)
1835 * @param $data (array)
1836 * @return boolean true or false
1837 */
1838 protected function checkModeKanji($size, $data) {
1839 if ($size & 1) {
1840 return false;
1841 }
1842 for ($i=0; $i<$size; $i+=2) {
1843 $val = (ord($data[$i]) << 8) | ord($data[$i+1]);
1844 if (($val < 0x8140) OR (($val > 0x9ffc) AND ($val < 0xe040)) OR ($val > 0xebbf)) {
1845 return false;
1846 }
1847 }
1848 return true;
1849 }
1850
1851 /**
1852 * Validate the input data.
1853 * @param $mode (int) encoding mode.
1854 * @param $size (int) size of data (byte).
1855 * @param $data (array) data to validate
1856 * @return boolean true in case of valid data, false otherwise
1857 */
1858 protected function check($mode, $size, $data) {
1859 if ($size <= 0) {
1860 return false;
1861 }
1862 switch($mode) {
1863 case QR_MODE_NM: {
1864 return $this->checkModeNum($size, $data);
1865 }
1866 case QR_MODE_AN: {
1867 return $this->checkModeAn($size, $data);
1868 }
1869 case QR_MODE_KJ: {
1870 return $this->checkModeKanji($size, $data);
1871 }
1872 case QR_MODE_8B: {
1873 return true;
1874 }
1875 case QR_MODE_ST: {
1876 return true;
1877 }
1878 default: {
1879 break;
1880 }
1881 }
1882 return false;
1883 }
1884
1885 /**
1886 * estimateBitStreamSize
1887 * @param $items (array)
1888 * @param $version (int)
1889 * @return int bits
1890 */
1891 protected function estimateBitStreamSize($items, $version) {
1892 $bits = 0;
1893 if ($version == 0) {
1894 $version = 1;
1895 }
1896 foreach ($items as $item) {
1897 switch($item['mode']) {
1898 case QR_MODE_NM: {
1899 $bits = $this->estimateBitsModeNum($item['size']);
1900 break;
1901 }
1902 case QR_MODE_AN: {
1903 $bits = $this->estimateBitsModeAn($item['size']);
1904 break;
1905 }
1906 case QR_MODE_8B: {
1907 $bits = $this->estimateBitsMode8($item['size']);
1908 break;
1909 }
1910 case QR_MODE_KJ: {
1911 $bits = $this->estimateBitsModeKanji($item['size']);
1912 break;
1913 }
1914 case QR_MODE_ST: {
1915 return STRUCTURE_HEADER_BITS;
1916 }
1917 default: {
1918 return 0;
1919 }
1920 }
1921 $l = $this->lengthIndicator($item['mode'], $version);
1922 $m = 1 << $l;
1923 $num = (int)(($item['size'] + $m - 1) / $m);
1924 $bits += $num * (4 + $l);
1925 }
1926 return $bits;
1927 }
1928
1929 /**
1930 * estimateVersion
1931 * @param $items (array)
1932 * @return int version
1933 */
1934 protected function estimateVersion($items) {
1935 $version = 0;
1936 $prev = 0;
1937 do {
1938 $prev = $version;
1939 $bits = $this->estimateBitStreamSize($items, $prev);
1940 $version = $this->getMinimumVersion((int)(($bits + 7) / 8), $this->level);
1941 if ($version < 0) {
1942 return -1;
1943 }
1944 } while ($version > $prev);
1945 return $version;
1946 }
1947
1948 /**
1949 * lengthOfCode
1950 * @param $mode (int)
1951 * @param $version (int)
1952 * @param $bits (int)
1953 * @return int size
1954 */
1955 protected function lengthOfCode($mode, $version, $bits) {
1956 $payload = $bits - 4 - $this->lengthIndicator($mode, $version);
1957 switch($mode) {
1958 case QR_MODE_NM: {
1959 $chunks = (int)($payload / 10);
1960 $remain = $payload - $chunks * 10;
1961 $size = $chunks * 3;
1962 if ($remain >= 7) {
1963 $size += 2;
1964 } elseif ($remain >= 4) {
1965 $size += 1;
1966 }
1967 break;
1968 }
1969 case QR_MODE_AN: {
1970 $chunks = (int)($payload / 11);
1971 $remain = $payload - $chunks * 11;
1972 $size = $chunks * 2;
1973 if ($remain >= 6) {
1974 ++$size;
1975 }
1976 break;
1977 }
1978 case QR_MODE_8B: {
1979 $size = (int)($payload / 8);
1980 break;
1981 }
1982 case QR_MODE_KJ: {
1983 $size = (int)(($payload / 13) * 2);
1984 break;
1985 }
1986 case QR_MODE_ST: {
1987 $size = (int)($payload / 8);
1988 break;
1989 }
1990 default: {
1991 $size = 0;
1992 break;
1993 }
1994 }
1995 $maxsize = $this->maximumWords($mode, $version);
1996 if ($size < 0) {
1997 $size = 0;
1998 }
1999 if ($size > $maxsize) {
2000 $size = $maxsize;
2001 }
2002 return $size;
2003 }
2004
2005 /**
2006 * createBitStream
2007 * @param $items (array)
2008 * @return array of items and total bits
2009 */
2010 protected function createBitStream($items) {
2011 $total = 0;
2012 foreach ($items as $key => $item) {
2013 $items[$key] = $this->encodeBitStream($item, $this->version);
2014 $bits = count($items[$key]['bstream']);
2015 $total += $bits;
2016 }
2017 return array($items, $total);
2018 }
2019
2020 /**
2021 * convertData
2022 * @param $items (array)
2023 * @return array items
2024 */
2025 protected function convertData($items) {
2026 $ver = $this->estimateVersion($items);
2027 if ($ver > $this->version) {
2028 $this->version = $ver;
2029 }
2030 while (true) {
2031 $cbs = $this->createBitStream($items);
2032 $items = $cbs[0];
2033 $bits = $cbs[1];
2034 if ($bits < 0) {
2035 return -1;
2036 }
2037 $ver = $this->getMinimumVersion((int)(($bits + 7) / 8), $this->level);
2038 if ($ver < 0) {
2039 return -1;
2040 } elseif ($ver > $this->version) {
2041 $this->version = $ver;
2042 } else {
2043 break;
2044 }
2045 }
2046 return $items;
2047 }
2048
2049 /**
2050 * Append Padding Bit to bitstream
2051 * @param $bstream (array)
2052 * @return array bitstream
2053 */
2054 protected function appendPaddingBit($bstream) {
2055 if (is_null($bstream)) {
2056 return null;
2057 }
2058 $bits = count($bstream);
2059 $maxwords = $this->getDataLength($this->version, $this->level);
2060 $maxbits = $maxwords * 8;
2061 if ($maxbits == $bits) {
2062 return $bstream;
2063 }
2064 if ($maxbits - $bits < 5) {
2065 return $this->appendNum($bstream, $maxbits - $bits, 0);
2066 }
2067 $bits += 4;
2068 $words = (int)(($bits + 7) / 8);
2069 $padding = array();
2070 $padding = $this->appendNum($padding, $words * 8 - $bits + 4, 0);
2071 $padlen = $maxwords - $words;
2072 if ($padlen > 0) {
2073 $padbuf = array();
2074 for ($i=0; $i<$padlen; ++$i) {
2075 $padbuf[$i] = ($i&1)?0x11:0xec;
2076 }
2077 $padding = $this->appendBytes($padding, $padlen, $padbuf);
2078 }
2079 return $this->appendBitstream($bstream, $padding);
2080 }
2081
2082 /**
2083 * mergeBitStream
2084 * @param $items (array) items
2085 * @return array bitstream
2086 */
2087 protected function mergeBitStream($items) {
2088 $items = $this->convertData($items);
2089 if (!is_array($items)) {
2090 return null;
2091 }
2092 $bstream = array();
2093 foreach ($items as $item) {
2094 $bstream = $this->appendBitstream($bstream, $item['bstream']);
2095 }
2096 return $bstream;
2097 }
2098
2099 /**
2100 * Returns a stream of bits.
2101 * @param $items (int)
2102 * @return array padded merged byte stream
2103 */
2104 protected function getBitStream($items) {
2105 $bstream = $this->mergeBitStream($items);
2106 return $this->appendPaddingBit($bstream);
2107 }
2108
2109 /**
2110 * Pack all bit streams padding bits into a byte array.
2111 * @param $items (int)
2112 * @return array padded merged byte stream
2113 */
2114 protected function getByteStream($items) {
2115 $bstream = $this->getBitStream($items);
2116 return $this->bitstreamToByte($bstream);
2117 }
2118
2119 // - - - - - - - - - - - - - - - - - - - - - - - - -
2120
2121 // QRbitstream
2122
2123 /**
2124 * Return an array with zeros
2125 * @param $setLength (int) array size
2126 * @return array
2127 */
2128 protected function allocate($setLength) {
2129 return array_fill(0, $setLength, 0);
2130 }
2131
2132 /**
2133 * Return new bitstream from number
2134 * @param $bits (int) number of bits
2135 * @param $num (int) number
2136 * @return array bitstream
2137 */
2138 protected function newFromNum($bits, $num) {
2139 $bstream = $this->allocate($bits);
2140 $mask = 1 << ($bits - 1);
2141 for ($i=0; $i<$bits; ++$i) {
2142 if ($num & $mask) {
2143 $bstream[$i] = 1;
2144 } else {
2145 $bstream[$i] = 0;
2146 }
2147 $mask = $mask >> 1;
2148 }
2149 return $bstream;
2150 }
2151
2152 /**
2153 * Return new bitstream from bytes
2154 * @param $size (int) size
2155 * @param $data (array) bytes
2156 * @return array bitstream
2157 */
2158 protected function newFromBytes($size, $data) {
2159 $bstream = $this->allocate($size * 8);
2160 $p=0;
2161 for ($i=0; $i<$size; ++$i) {
2162 $mask = 0x80;
2163 for ($j=0; $j<8; ++$j) {
2164 if ($data[$i] & $mask) {
2165 $bstream[$p] = 1;
2166 } else {
2167 $bstream[$p] = 0;
2168 }
2169 $p++;
2170 $mask = $mask >> 1;
2171 }
2172 }
2173 return $bstream;
2174 }
2175
2176 /**
2177 * Append one bitstream to another
2178 * @param $bitstream (array) original bitstream
2179 * @param $append (array) bitstream to append
2180 * @return array bitstream
2181 */
2182 protected function appendBitstream($bitstream, $append) {
2183 if ((!is_array($append)) OR (count($append) == 0)) {
2184 return $bitstream;
2185 }
2186 if (count($bitstream) == 0) {
2187 return $append;
2188 }
2189 return array_values(array_merge($bitstream, $append));
2190 }
2191
2192 /**
2193 * Append one bitstream created from number to another
2194 * @param $bitstream (array) original bitstream
2195 * @param $bits (int) number of bits
2196 * @param $num (int) number
2197 * @return array bitstream
2198 */
2199 protected function appendNum($bitstream, $bits, $num) {
2200 if ($bits == 0) {
2201 return 0;
2202 }
2203 $b = $this->newFromNum($bits, $num);
2204 return $this->appendBitstream($bitstream, $b);
2205 }
2206
2207 /**
2208 * Append one bitstream created from bytes to another
2209 * @param $bitstream (array) original bitstream
2210 * @param $size (int) size
2211 * @param $data (array) bytes
2212 * @return array bitstream
2213 */
2214 protected function appendBytes($bitstream, $size, $data) {
2215 if ($size == 0) {
2216 return 0;
2217 }
2218 $b = $this->newFromBytes($size, $data);
2219 return $this->appendBitstream($bitstream, $b);
2220 }
2221
2222 /**
2223 * Convert bitstream to bytes
2224 * @param $bstream (array) original bitstream
2225 * @return array of bytes
2226 */
2227 protected function bitstreamToByte($bstream) {
2228 if (is_null($bstream)) {
2229 return null;
2230 }
2231 $size = count($bstream);
2232 if ($size == 0) {
2233 return array();
2234 }
2235 $data = array_fill(0, (int)(($size + 7) / 8), 0);
2236 $bytes = (int)($size / 8);
2237 $p = 0;
2238 for ($i=0; $i<$bytes; $i++) {
2239 $v = 0;
2240 for ($j=0; $j<8; $j++) {
2241 $v = $v << 1;
2242 $v |= $bstream[$p];
2243 $p++;
2244 }
2245 $data[$i] = $v;
2246 }
2247 if ($size & 7) {
2248 $v = 0;
2249 for ($j=0; $j<($size & 7); $j++) {
2250 $v = $v << 1;
2251 $v |= $bstream[$p];
2252 $p++;
2253 }
2254 $data[$bytes] = $v;
2255 }
2256 return $data;
2257 }
2258
2259 // - - - - - - - - - - - - - - - - - - - - - - - - -
2260
2261 // QRspec
2262
2263 /**
2264 * Replace a value on the array at the specified position
2265 * @param $srctab (array)
2266 * @param $x (int) X position
2267 * @param $y (int) Y position
2268 * @param $repl (string) value to replace
2269 * @param $replLen (int) length of the repl string
2270 * @return array srctab
2271 */
2272 protected function qrstrset($srctab, $x, $y, $repl, $replLen=false) {
2273 $srctab[$y] = substr_replace($srctab[$y], ($replLen !== false)?substr($repl,0,$replLen):$repl, $x, ($replLen !== false)?$replLen:strlen($repl));
2274 return $srctab;
2275 }
2276
2277 /**
2278 * Return maximum data code length (bytes) for the version.
2279 * @param $version (int) version
2280 * @param $level (int) error correction level
2281 * @return int maximum size (bytes)
2282 */
2283 protected function getDataLength($version, $level) {
2284 return $this->capacity[$version][QRCAP_WORDS] - $this->capacity[$version][QRCAP_EC][$level];
2285 }
2286
2287 /**
2288 * Return maximum error correction code length (bytes) for the version.
2289 * @param $version (int) version
2290 * @param $level (int) error correction level
2291 * @return int ECC size (bytes)
2292 */
2293 protected function getECCLength($version, $level){
2294 return $this->capacity[$version][QRCAP_EC][$level];
2295 }
2296
2297 /**
2298 * Return the width of the symbol for the version.
2299 * @param $version (int) version
2300 * @return int width
2301 */
2302 protected function getWidth($version) {
2303 return $this->capacity[$version][QRCAP_WIDTH];
2304 }
2305
2306 /**
2307 * Return the numer of remainder bits.
2308 * @param $version (int) version
2309 * @return int number of remainder bits
2310 */
2311 protected function getRemainder($version) {
2312 return $this->capacity[$version][QRCAP_REMINDER];
2313 }
2314
2315 /**
2316 * Return a version number that satisfies the input code length.
2317 * @param $size (int) input code length (bytes)
2318 * @param $level (int) error correction level
2319 * @return int version number
2320 */
2321 protected function getMinimumVersion($size, $level) {
2322 for ($i = 1; $i <= QRSPEC_VERSION_MAX; ++$i) {
2323 $words = ($this->capacity[$i][QRCAP_WORDS] - $this->capacity[$i][QRCAP_EC][$level]);
2324 if ($words >= $size) {
2325 return $i;
2326 }
2327 }
2328 // the size of input data is greater than QR capacity, try to lover the error correction mode
2329 return -1;
2330 }
2331
2332 /**
2333 * Return the size of length indicator for the mode and version.
2334 * @param $mode (int) encoding mode
2335 * @param $version (int) version
2336 * @return int the size of the appropriate length indicator (bits).
2337 */
2338 protected function lengthIndicator($mode, $version) {
2339 if ($mode == QR_MODE_ST) {
2340 return 0;
2341 }
2342 if ($version <= 9) {
2343 $l = 0;
2344 } elseif ($version <= 26) {
2345 $l = 1;
2346 } else {
2347 $l = 2;
2348 }
2349 return $this->lengthTableBits[$mode][$l];
2350 }
2351
2352 /**
2353 * Return the maximum length for the mode and version.
2354 * @param $mode (int) encoding mode
2355 * @param $version (int) version
2356 * @return int the maximum length (bytes)
2357 */
2358 protected function maximumWords($mode, $version) {
2359 if ($mode == QR_MODE_ST) {
2360 return 3;
2361 }
2362 if ($version <= 9) {
2363 $l = 0;
2364 } else if ($version <= 26) {
2365 $l = 1;
2366 } else {
2367 $l = 2;
2368 }
2369 $bits = $this->lengthTableBits[$mode][$l];
2370 $words = (1 << $bits) - 1;
2371 if ($mode == QR_MODE_KJ) {
2372 $words *= 2; // the number of bytes is required
2373 }
2374 return $words;
2375 }
2376
2377 /**
2378 * Return an array of ECC specification.
2379 * @param $version (int) version
2380 * @param $level (int) error correction level
2381 * @param $spec (array) an array of ECC specification contains as following: {# of type1 blocks, # of data code, # of ecc code, # of type2 blocks, # of data code}
2382 * @return array spec
2383 */
2384 protected function getEccSpec($version, $level, $spec) {
2385 if (count($spec) < 5) {
2386 $spec = array(0, 0, 0, 0, 0);
2387 }
2388 $b1 = $this->eccTable[$version][$level][0];
2389 $b2 = $this->eccTable[$version][$level][1];
2390 $data = $this->getDataLength($version, $level);
2391 $ecc = $this->getECCLength($version, $level);
2392 if ($b2 == 0) {
2393 $spec[0] = $b1;
2394 $spec[1] = (int)($data / $b1);
2395 $spec[2] = (int)($ecc / $b1);
2396 $spec[3] = 0;
2397 $spec[4] = 0;
2398 } else {
2399 $spec[0] = $b1;
2400 $spec[1] = (int)($data / ($b1 + $b2));
2401 $spec[2] = (int)($ecc / ($b1 + $b2));
2402 $spec[3] = $b2;
2403 $spec[4] = $spec[1] + 1;
2404 }
2405 return $spec;
2406 }
2407
2408 /**
2409 * Put an alignment marker.
2410 * @param $frame (array) frame
2411 * @param $ox (int) X center coordinate of the pattern
2412 * @param $oy (int) Y center coordinate of the pattern
2413 * @return array frame
2414 */
2415 protected function putAlignmentMarker($frame, $ox, $oy) {
2416 $finder = array(
2417 "\xa1\xa1\xa1\xa1\xa1",
2418 "\xa1\xa0\xa0\xa0\xa1",
2419 "\xa1\xa0\xa1\xa0\xa1",
2420 "\xa1\xa0\xa0\xa0\xa1",
2421 "\xa1\xa1\xa1\xa1\xa1"
2422 );
2423 $yStart = $oy - 2;
2424 $xStart = $ox - 2;
2425 for ($y=0; $y < 5; $y++) {
2426 $frame = $this->qrstrset($frame, $xStart, $yStart+$y, $finder[$y]);
2427 }
2428 return $frame;
2429 }
2430
2431 /**
2432 * Put an alignment pattern.
2433 * @param $version (int) version
2434 * @param $frame (array) frame
2435 * @param $width (int) width
2436 * @return array frame
2437 */
2438 protected function putAlignmentPattern($version, $frame, $width) {
2439 if ($version < 2) {
2440 return $frame;
2441 }
2442 $d = $this->alignmentPattern[$version][1] - $this->alignmentPattern[$version][0];
2443 if ($d < 0) {
2444 $w = 2;
2445 } else {
2446 $w = (int)(($width - $this->alignmentPattern[$version][0]) / $d + 2);
2447 }
2448 if ($w * $w - 3 == 1) {
2449 $x = $this->alignmentPattern[$version][0];
2450 $y = $this->alignmentPattern[$version][0];
2451 $frame = $this->putAlignmentMarker($frame, $x, $y);
2452 return $frame;
2453 }
2454 $cx = $this->alignmentPattern[$version][0];
2455 $wo = $w - 1;
2456 for ($x=1; $x < $wo; ++$x) {
2457 $frame = $this->putAlignmentMarker($frame, 6, $cx);
2458 $frame = $this->putAlignmentMarker($frame, $cx, 6);
2459 $cx += $d;
2460 }
2461 $cy = $this->alignmentPattern[$version][0];
2462 for ($y=0; $y < $wo; ++$y) {
2463 $cx = $this->alignmentPattern[$version][0];
2464 for ($x=0; $x < $wo; ++$x) {
2465 $frame = $this->putAlignmentMarker($frame, $cx, $cy);
2466 $cx += $d;
2467 }
2468 $cy += $d;
2469 }
2470 return $frame;
2471 }
2472
2473 /**
2474 * Return BCH encoded version information pattern that is used for the symbol of version 7 or greater. Use lower 18 bits.
2475 * @param $version (int) version
2476 * @return BCH encoded version information pattern
2477 */
2478 protected function getVersionPattern($version) {
2479 if (($version < 7) OR ($version > QRSPEC_VERSION_MAX)) {
2480 return 0;
2481 }
2482 return $this->versionPattern[($version - 7)];
2483 }
2484
2485 /**
2486 * Return BCH encoded format information pattern.
2487 * @param $mask (array)
2488 * @param $level (int) error correction level
2489 * @return BCH encoded format information pattern
2490 */
2491 protected function getFormatInfo($mask, $level) {
2492 if (($mask < 0) OR ($mask > 7)) {
2493 return 0;
2494 }
2495 if (($level < 0) OR ($level > 3)) {
2496 return 0;
2497 }
2498 return $this->formatInfo[$level][$mask];
2499 }
2500
2501 /**
2502 * Put a finder pattern.
2503 * @param $frame (array) frame
2504 * @param $ox (int) X center coordinate of the pattern
2505 * @param $oy (int) Y center coordinate of the pattern
2506 * @return array frame
2507 */
2508 protected function putFinderPattern($frame, $ox, $oy) {
2509 $finder = array(
2510 "\xc1\xc1\xc1\xc1\xc1\xc1\xc1",
2511 "\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
2512 "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
2513 "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
2514 "\xc1\xc0\xc1\xc1\xc1\xc0\xc1",
2515 "\xc1\xc0\xc0\xc0\xc0\xc0\xc1",
2516 "\xc1\xc1\xc1\xc1\xc1\xc1\xc1"
2517 );
2518 for ($y=0; $y < 7; $y++) {
2519 $frame = $this->qrstrset($frame, $ox, ($oy + $y), $finder[$y]);
2520 }
2521 return $frame;
2522 }
2523
2524 /**
2525 * Return a copy of initialized frame.
2526 * @param $version (int) version
2527 * @return Array of unsigned char.
2528 */
2529 protected function createFrame($version) {
2530 $width = $this->capacity[$version][QRCAP_WIDTH];
2531 $frameLine = str_repeat ("\0", $width);
2532 $frame = array_fill(0, $width, $frameLine);
2533 // Finder pattern
2534 $frame = $this->putFinderPattern($frame, 0, 0);
2535 $frame = $this->putFinderPattern($frame, $width - 7, 0);
2536 $frame = $this->putFinderPattern($frame, 0, $width - 7);
2537 // Separator
2538 $yOffset = $width - 7;
2539 for ($y=0; $y < 7; ++$y) {
2540 $frame[$y][7] = "\xc0";
2541 $frame[$y][$width - 8] = "\xc0";
2542 $frame[$yOffset][7] = "\xc0";
2543 ++$yOffset;
2544 }
2545 $setPattern = str_repeat("\xc0", 8);
2546 $frame = $this->qrstrset($frame, 0, 7, $setPattern);
2547 $frame = $this->qrstrset($frame, $width-8, 7, $setPattern);
2548 $frame = $this->qrstrset($frame, 0, $width - 8, $setPattern);
2549 // Format info
2550 $setPattern = str_repeat("\x84", 9);
2551 $frame = $this->qrstrset($frame, 0, 8, $setPattern);
2552 $frame = $this->qrstrset($frame, $width - 8, 8, $setPattern, 8);
2553 $yOffset = $width - 8;
2554 for ($y=0; $y < 8; ++$y,++$yOffset) {
2555 $frame[$y][8] = "\x84";
2556 $frame[$yOffset][8] = "\x84";
2557 }
2558 // Timing pattern
2559 $wo = $width - 15;
2560 for ($i=1; $i < $wo; ++$i) {
2561 $frame[6][7+$i] = chr(0x90 | ($i & 1));
2562 $frame[7+$i][6] = chr(0x90 | ($i & 1));
2563 }
2564 // Alignment pattern
2565 $frame = $this->putAlignmentPattern($version, $frame, $width);
2566 // Version information
2567 if ($version >= 7) {
2568 $vinf = $this->getVersionPattern($version);
2569 $v = $vinf;
2570 for ($x=0; $x<6; ++$x) {
2571 for ($y=0; $y<3; ++$y) {
2572 $frame[($width - 11)+$y][$x] = chr(0x88 | ($v & 1));
2573 $v = $v >> 1;
2574 }
2575 }
2576 $v = $vinf;
2577 for ($y=0; $y<6; ++$y) {
2578 for ($x=0; $x<3; ++$x) {
2579 $frame[$y][$x+($width - 11)] = chr(0x88 | ($v & 1));
2580 $v = $v >> 1;
2581 }
2582 }
2583 }
2584 // and a little bit...
2585 $frame[$width - 8][8] = "\x81";
2586 return $frame;
2587 }
2588
2589 /**
2590 * Set new frame for the specified version.
2591 * @param $version (int) version
2592 * @return Array of unsigned char.
2593 */
2594 protected function newFrame($version) {
2595 if (($version < 1) OR ($version > QRSPEC_VERSION_MAX)) {
2596 return NULL;
2597 }
2598 if (!isset($this->frames[$version])) {
2599 $this->frames[$version] = $this->createFrame($version);
2600 }
2601 if (is_null($this->frames[$version])) {
2602 return NULL;
2603 }
2604 return $this->frames[$version];
2605 }
2606
2607 /**
2608 * Return block number 0
2609 * @param $spec (array)
2610 * @return int value
2611 */
2612 protected function rsBlockNum($spec) {
2613 return ($spec[0] + $spec[3]);
2614 }
2615
2616 /**
2617 * Return block number 1
2618 * @param $spec (array)
2619 * @return int value
2620 */
2621 protected function rsBlockNum1($spec) {
2622 return $spec[0];
2623 }
2624
2625 /**
2626 * Return data codes 1
2627 * @param $spec (array)
2628 * @return int value
2629 */
2630 protected function rsDataCodes1($spec) {
2631 return $spec[1];
2632 }
2633
2634 /**
2635 * Return ecc codes 1
2636 * @param $spec (array)
2637 * @return int value
2638 */
2639 protected function rsEccCodes1($spec) {
2640 return $spec[2];
2641 }
2642
2643 /**
2644 * Return block number 2
2645 * @param $spec (array)
2646 * @return int value
2647 */
2648 protected function rsBlockNum2($spec) {
2649 return $spec[3];
2650 }
2651
2652 /**
2653 * Return data codes 2
2654 * @param $spec (array)
2655 * @return int value
2656 */
2657 protected function rsDataCodes2($spec) {
2658 return $spec[4];
2659 }
2660
2661 /**
2662 * Return ecc codes 2
2663 * @param $spec (array)
2664 * @return int value
2665 */
2666 protected function rsEccCodes2($spec) {
2667 return $spec[2];
2668 }
2669
2670 /**
2671 * Return data length
2672 * @param $spec (array)
2673 * @return int value
2674 */
2675 protected function rsDataLength($spec) {
2676 return ($spec[0] * $spec[1]) + ($spec[3] * $spec[4]);
2677 }
2678
2679 /**
2680 * Return ecc length
2681 * @param $spec (array)
2682 * @return int value
2683 */
2684 protected function rsEccLength($spec) {
2685 return ($spec[0] + $spec[3]) * $spec[2];
2686 }
2687
2688 // - - - - - - - - - - - - - - - - - - - - - - - - -
2689
2690 // QRrs
2691
2692 /**
2693 * Initialize a Reed-Solomon codec and add it to existing rsitems
2694 * @param $symsize (int) symbol size, bits
2695 * @param $gfpoly (int) Field generator polynomial coefficients
2696 * @param $fcr (int) first root of RS code generator polynomial, index form
2697 * @param $prim (int) primitive element to generate polynomial roots
2698 * @param $nroots (int) RS code generator polynomial degree (number of roots)
2699 * @param $pad (int) padding bytes at front of shortened block
2700 * @return array Array of RS values:<ul><li>mm = Bits per symbol;</li><li>nn = Symbols per block;</li><li>alpha_to = log lookup table array;</li><li>index_of = Antilog lookup table array;</li><li>genpoly = Generator polynomial array;</li><li>nroots = Number of generator;</li><li>roots = number of parity symbols;</li><li>fcr = First consecutive root, index form;</li><li>prim = Primitive element, index form;</li><li>iprim = prim-th root of 1, index form;</li><li>pad = Padding bytes in shortened block;</li><li>gfpoly</ul>.
2701 */
2702 protected function init_rs($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) {
2703 foreach ($this->rsitems as $rs) {
2704 if (($rs['pad'] != $pad) OR ($rs['nroots'] != $nroots) OR ($rs['mm'] != $symsize)
2705 OR ($rs['gfpoly'] != $gfpoly) OR ($rs['fcr'] != $fcr) OR ($rs['prim'] != $prim)) {
2706 continue;
2707 }
2708 return $rs;
2709 }
2710 $rs = $this->init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad);
2711 array_unshift($this->rsitems, $rs);
2712 return $rs;
2713 }
2714
2715 // - - - - - - - - - - - - - - - - - - - - - - - - -
2716
2717 // QRrsItem
2718
2719 /**
2720 * modnn
2721 * @param $rs (array) RS values
2722 * @param $x (int) X position
2723 * @return int X osition
2724 */
2725 protected function modnn($rs, $x) {
2726 while ($x >= $rs['nn']) {
2727 $x -= $rs['nn'];
2728 $x = ($x >> $rs['mm']) + ($x & $rs['nn']);
2729 }
2730 return $x;
2731 }
2732
2733 /**
2734 * Initialize a Reed-Solomon codec and returns an array of values.
2735 * @param $symsize (int) symbol size, bits
2736 * @param $gfpoly (int) Field generator polynomial coefficients
2737 * @param $fcr (int) first root of RS code generator polynomial, index form
2738 * @param $prim (int) primitive element to generate polynomial roots
2739 * @param $nroots (int) RS code generator polynomial degree (number of roots)
2740 * @param $pad (int) padding bytes at front of shortened block
2741 * @return array Array of RS values:<ul><li>mm = Bits per symbol;</li><li>nn = Symbols per block;</li><li>alpha_to = log lookup table array;</li><li>index_of = Antilog lookup table array;</li><li>genpoly = Generator polynomial array;</li><li>nroots = Number of generator;</li><li>roots = number of parity symbols;</li><li>fcr = First consecutive root, index form;</li><li>prim = Primitive element, index form;</li><li>iprim = prim-th root of 1, index form;</li><li>pad = Padding bytes in shortened block;</li><li>gfpoly</ul>.
2742 */
2743 protected function init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) {
2744 // Based on Reed solomon encoder by Phil Karn, KA9Q (GNU-LGPLv2)
2745 $rs = null;
2746 // Check parameter ranges
2747 if (($symsize < 0) OR ($symsize > 8)) {
2748 return $rs;
2749 }
2750 if (($fcr < 0) OR ($fcr >= (1<<$symsize))) {
2751 return $rs;
2752 }
2753 if (($prim <= 0) OR ($prim >= (1<<$symsize))) {
2754 return $rs;
2755 }
2756 if (($nroots < 0) OR ($nroots >= (1<<$symsize))) {
2757 return $rs;
2758 }
2759 if (($pad < 0) OR ($pad >= ((1<<$symsize) -1 - $nroots))) {
2760 return $rs;
2761 }
2762 $rs = array();
2763 $rs['mm'] = $symsize;
2764 $rs['nn'] = (1 << $symsize) - 1;
2765 $rs['pad'] = $pad;
2766 $rs['alpha_to'] = array_fill(0, ($rs['nn'] + 1), 0);
2767 $rs['index_of'] = array_fill(0, ($rs['nn'] + 1), 0);
2768 // PHP style macro replacement ;)
2769 $NN =& $rs['nn'];
2770 $A0 =& $NN;
2771 // Generate Galois field lookup tables
2772 $rs['index_of'][0] = $A0; // log(zero) = -inf
2773 $rs['alpha_to'][$A0] = 0; // alpha**-inf = 0
2774 $sr = 1;
2775 for ($i=0; $i<$rs['nn']; ++$i) {
2776 $rs['index_of'][$sr] = $i;
2777 $rs['alpha_to'][$i] = $sr;
2778 $sr <<= 1;
2779 if ($sr & (1 << $symsize)) {
2780 $sr ^= $gfpoly;
2781 }
2782 $sr &= $rs['nn'];
2783 }
2784 if ($sr != 1) {
2785 // field generator polynomial is not primitive!
2786 return NULL;
2787 }
2788 // Form RS code generator polynomial from its roots
2789 $rs['genpoly'] = array_fill(0, ($nroots + 1), 0);
2790 $rs['fcr'] = $fcr;
2791 $rs['prim'] = $prim;
2792 $rs['nroots'] = $nroots;
2793 $rs['gfpoly'] = $gfpoly;
2794 // Find prim-th root of 1, used in decoding
2795 for ($iprim=1; ($iprim % $prim) != 0; $iprim += $rs['nn']) {
2796 ; // intentional empty-body loop!
2797 }
2798 $rs['iprim'] = (int)($iprim / $prim);
2799 $rs['genpoly'][0] = 1;
2800 for ($i = 0,$root=$fcr*$prim; $i < $nroots; $i++, $root += $prim) {
2801 $rs['genpoly'][$i+1] = 1;
2802 // Multiply rs->genpoly[] by @**(root + x)
2803 for ($j = $i; $j > 0; --$j) {
2804 if ($rs['genpoly'][$j] != 0) {
2805 $rs['genpoly'][$j] = $rs['genpoly'][$j-1] ^ $rs['alpha_to'][$this->modnn($rs, $rs['index_of'][$rs['genpoly'][$j]] + $root)];
2806 } else {
2807 $rs['genpoly'][$j] = $rs['genpoly'][$j-1];
2808 }
2809 }
2810 // rs->genpoly[0] can never be zero
2811 $rs['genpoly'][0] = $rs['alpha_to'][$this->modnn($rs, $rs['index_of'][$rs['genpoly'][0]] + $root)];
2812 }
2813 // convert rs->genpoly[] to index form for quicker encoding
2814 for ($i = 0; $i <= $nroots; ++$i) {
2815 $rs['genpoly'][$i] = $rs['index_of'][$rs['genpoly'][$i]];
2816 }
2817 return $rs;
2818 }
2819
2820 /**
2821 * Encode a Reed-Solomon codec and returns the parity array
2822 * @param $rs (array) RS values
2823 * @param $data (array) data
2824 * @param $parity (array) parity
2825 * @return parity array
2826 */
2827 protected function encode_rs_char($rs, $data, $parity) {
2828 $MM =& $rs['mm']; // bits per symbol
2829 $NN =& $rs['nn']; // the total number of symbols in a RS block
2830 $ALPHA_TO =& $rs['alpha_to']; // the address of an array of NN elements to convert Galois field elements in index (log) form to polynomial form
2831 $INDEX_OF =& $rs['index_of']; // the address of an array of NN elements to convert Galois field elements in polynomial form to index (log) form
2832 $GENPOLY =& $rs['genpoly']; // an array of NROOTS+1 elements containing the generator polynomial in index form
2833 $NROOTS =& $rs['nroots']; // the number of roots in the RS code generator polynomial, which is the same as the number of parity symbols in a block
2834 $FCR =& $rs['fcr']; // first consecutive root, index form
2835 $PRIM =& $rs['prim']; // primitive element, index form
2836 $IPRIM =& $rs['iprim']; // prim-th root of 1, index form
2837 $PAD =& $rs['pad']; // the number of pad symbols in a block
2838 $A0 =& $NN;
2839 $parity = array_fill(0, $NROOTS, 0);
2840 for ($i=0; $i < ($NN - $NROOTS - $PAD); $i++) {
2841 $feedback = $INDEX_OF[$data[$i] ^ $parity[0]];
2842 if ($feedback != $A0) {
2843 // feedback term is non-zero
2844 // This line is unnecessary when GENPOLY[NROOTS] is unity, as it must
2845 // always be for the polynomials constructed by init_rs()
2846 $feedback = $this->modnn($rs, $NN - $GENPOLY[$NROOTS] + $feedback);
2847 for ($j=1; $j < $NROOTS; ++$j) {
2848 $parity[$j] ^= $ALPHA_TO[$this->modnn($rs, $feedback + $GENPOLY[($NROOTS - $j)])];
2849 }
2850 }
2851 // Shift
2852 array_shift($parity);
2853 if ($feedback != $A0) {
2854 array_push($parity, $ALPHA_TO[$this->modnn($rs, $feedback + $GENPOLY[0])]);
2855 } else {
2856 array_push($parity, 0);
2857 }
2858 }
2859 return $parity;
2860 }
2861
2862} // end QRcode class
2863
2864//============================================================+
2865// END OF FILE
2866//============================================================+
diff --git a/inc/3rdparty/libraries/tcpdf/include/sRGB.icc b/inc/3rdparty/libraries/tcpdf/include/sRGB.icc
new file mode 100644
index 00000000..1d8f7419
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/include/sRGB.icc
Binary files differ
diff --git a/inc/3rdparty/libraries/tcpdf/include/tcpdf_colors.php b/inc/3rdparty/libraries/tcpdf/include/tcpdf_colors.php
new file mode 100644
index 00000000..77f1c4cc
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/include/tcpdf_colors.php
@@ -0,0 +1,462 @@
1<?php
2//============================================================+
3// File name : tcpdf_colors.php
4// Version : 1.0.004
5// Begin : 2002-04-09
6// Last Update : 2014-04-25
7// Author : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com
8// License : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html)
9// -------------------------------------------------------------------
10// Copyright (C) 2002-2013 Nicola Asuni - Tecnick.com LTD
11//
12// This file is part of TCPDF software library.
13//
14// TCPDF is free software: you can redistribute it and/or modify it
15// under the terms of the GNU Lesser General Public License as
16// published by the Free Software Foundation, either version 3 of the
17// License, or (at your option) any later version.
18//
19// TCPDF is distributed in the hope that it will be useful, but
20// WITHOUT ANY WARRANTY; without even the implied warranty of
21// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22// See the GNU Lesser General Public License for more details.
23//
24// You should have received a copy of the GNU Lesser General Public License
25// along with TCPDF. If not, see <http://www.gnu.org/licenses/>.
26//
27// See LICENSE.TXT file for more information.
28// -------------------------------------------------------------------
29//
30// Description : Array of WEB safe colors
31//
32//============================================================+
33
34/**
35 * @file
36 * PHP color class for TCPDF
37 * @author Nicola Asuni
38 * @package com.tecnick.tcpdf
39 */
40
41/**
42 * @class TCPDF_COLORS
43 * PHP color class for TCPDF
44 * @package com.tecnick.tcpdf
45 * @version 1.0.004
46 * @author Nicola Asuni - info@tecnick.com
47 */
48class TCPDF_COLORS {
49
50 /**
51 * Array of WEB safe colors
52 * @public static
53 */
54 public static $webcolor = array (
55 'aliceblue' => 'f0f8ff',
56 'antiquewhite' => 'faebd7',
57 'aqua' => '00ffff',
58 'aquamarine' => '7fffd4',
59 'azure' => 'f0ffff',
60 'beige' => 'f5f5dc',
61 'bisque' => 'ffe4c4',
62 'black' => '000000',
63 'blanchedalmond' => 'ffebcd',
64 'blue' => '0000ff',
65 'blueviolet' => '8a2be2',
66 'brown' => 'a52a2a',
67 'burlywood' => 'deb887',
68 'cadetblue' => '5f9ea0',
69 'chartreuse' => '7fff00',
70 'chocolate' => 'd2691e',
71 'coral' => 'ff7f50',
72 'cornflowerblue' => '6495ed',
73 'cornsilk' => 'fff8dc',
74 'crimson' => 'dc143c',
75 'cyan' => '00ffff',
76 'darkblue' => '00008b',
77 'darkcyan' => '008b8b',
78 'darkgoldenrod' => 'b8860b',
79 'dkgray' => 'a9a9a9',
80 'darkgray' => 'a9a9a9',
81 'darkgrey' => 'a9a9a9',
82 'darkgreen' => '006400',
83 'darkkhaki' => 'bdb76b',
84 'darkmagenta' => '8b008b',
85 'darkolivegreen' => '556b2f',
86 'darkorange' => 'ff8c00',
87 'darkorchid' => '9932cc',
88 'darkred' => '8b0000',
89 'darksalmon' => 'e9967a',
90 'darkseagreen' => '8fbc8f',
91 'darkslateblue' => '483d8b',
92 'darkslategray' => '2f4f4f',
93 'darkslategrey' => '2f4f4f',
94 'darkturquoise' => '00ced1',
95 'darkviolet' => '9400d3',
96 'deeppink' => 'ff1493',
97 'deepskyblue' => '00bfff',
98 'dimgray' => '696969',
99 'dimgrey' => '696969',
100 'dodgerblue' => '1e90ff',
101 'firebrick' => 'b22222',
102 'floralwhite' => 'fffaf0',
103 'forestgreen' => '228b22',
104 'fuchsia' => 'ff00ff',
105 'gainsboro' => 'dcdcdc',
106 'ghostwhite' => 'f8f8ff',
107 'gold' => 'ffd700',
108 'goldenrod' => 'daa520',
109 'gray' => '808080',
110 'grey' => '808080',
111 'green' => '008000',
112 'greenyellow' => 'adff2f',
113 'honeydew' => 'f0fff0',
114 'hotpink' => 'ff69b4',
115 'indianred' => 'cd5c5c',
116 'indigo' => '4b0082',
117 'ivory' => 'fffff0',
118 'khaki' => 'f0e68c',
119 'lavender' => 'e6e6fa',
120 'lavenderblush' => 'fff0f5',
121 'lawngreen' => '7cfc00',
122 'lemonchiffon' => 'fffacd',
123 'lightblue' => 'add8e6',
124 'lightcoral' => 'f08080',
125 'lightcyan' => 'e0ffff',
126 'lightgoldenrodyellow' => 'fafad2',
127 'ltgray' => 'd3d3d3',
128 'lightgray' => 'd3d3d3',
129 'lightgrey' => 'd3d3d3',
130 'lightgreen' => '90ee90',
131 'lightpink' => 'ffb6c1',
132 'lightsalmon' => 'ffa07a',
133 'lightseagreen' => '20b2aa',
134 'lightskyblue' => '87cefa',
135 'lightslategray' => '778899',
136 'lightslategrey' => '778899',
137 'lightsteelblue' => 'b0c4de',
138 'lightyellow' => 'ffffe0',
139 'lime' => '00ff00',
140 'limegreen' => '32cd32',
141 'linen' => 'faf0e6',
142 'magenta' => 'ff00ff',
143 'maroon' => '800000',
144 'mediumaquamarine' => '66cdaa',
145 'mediumblue' => '0000cd',
146 'mediumorchid' => 'ba55d3',
147 'mediumpurple' => '9370d8',
148 'mediumseagreen' => '3cb371',
149 'mediumslateblue' => '7b68ee',
150 'mediumspringgreen' => '00fa9a',
151 'mediumturquoise' => '48d1cc',
152 'mediumvioletred' => 'c71585',
153 'midnightblue' => '191970',
154 'mintcream' => 'f5fffa',
155 'mistyrose' => 'ffe4e1',
156 'moccasin' => 'ffe4b5',
157 'navajowhite' => 'ffdead',
158 'navy' => '000080',
159 'oldlace' => 'fdf5e6',
160 'olive' => '808000',
161 'olivedrab' => '6b8e23',
162 'orange' => 'ffa500',
163 'orangered' => 'ff4500',
164 'orchid' => 'da70d6',
165 'palegoldenrod' => 'eee8aa',
166 'palegreen' => '98fb98',
167 'paleturquoise' => 'afeeee',
168 'palevioletred' => 'd87093',
169 'papayawhip' => 'ffefd5',
170 'peachpuff' => 'ffdab9',
171 'peru' => 'cd853f',
172 'pink' => 'ffc0cb',
173 'plum' => 'dda0dd',
174 'powderblue' => 'b0e0e6',
175 'purple' => '800080',
176 'red' => 'ff0000',
177 'rosybrown' => 'bc8f8f',
178 'royalblue' => '4169e1',
179 'saddlebrown' => '8b4513',
180 'salmon' => 'fa8072',
181 'sandybrown' => 'f4a460',
182 'seagreen' => '2e8b57',
183 'seashell' => 'fff5ee',
184 'sienna' => 'a0522d',
185 'silver' => 'c0c0c0',
186 'skyblue' => '87ceeb',
187 'slateblue' => '6a5acd',
188 'slategray' => '708090',
189 'slategrey' => '708090',
190 'snow' => 'fffafa',
191 'springgreen' => '00ff7f',
192 'steelblue' => '4682b4',
193 'tan' => 'd2b48c',
194 'teal' => '008080',
195 'thistle' => 'd8bfd8',
196 'tomato' => 'ff6347',
197 'turquoise' => '40e0d0',
198 'violet' => 'ee82ee',
199 'wheat' => 'f5deb3',
200 'white' => 'ffffff',
201 'whitesmoke' => 'f5f5f5',
202 'yellow' => 'ffff00',
203 'yellowgreen' => '9acd32'
204 ); // end of web colors
205
206 /**
207 * Array of valid JavaScript color names
208 * @public static
209 */
210 public static $jscolor = array ('transparent', 'black', 'white', 'red', 'green', 'blue', 'cyan', 'magenta', 'yellow', 'dkGray', 'gray', 'ltGray');
211
212 /**
213 * Array of Spot colors (C,M,Y,K,name)
214 * Color keys must be in lowercase and without spaces.
215 * As long as no open standard for spot colours exists, you have to buy a colour book by one of the colour manufacturers and insert the values and names of spot colours directly.
216 * Common industry standard spot colors are: ANPA-COLOR, DIC, FOCOLTONE, GCMI, HKS, PANTONE, TOYO, TRUMATCH.
217 * @public static
218 */
219 public static $spotcolor = array (
220 // special registration colors
221 'none' => array( 0, 0, 0, 0, 'None'),
222 'all' => array(100, 100, 100, 100, 'All'),
223 // standard CMYK colors
224 'cyan' => array(100, 0, 0, 0, 'Cyan'),
225 'magenta' => array( 0, 100, 0, 0, 'Magenta'),
226 'yellow' => array( 0, 0, 100, 0, 'Yellow'),
227 'key' => array( 0, 0, 0, 100, 'Key'),
228 // alias
229 'white' => array( 0, 0, 0, 0, 'White'),
230 'black' => array( 0, 0, 0, 100, 'Black'),
231 // standard RGB colors
232 'red' => array( 0, 100, 100, 0, 'Red'),
233 'green' => array(100, 0, 100, 0, 'Green'),
234 'blue' => array(100, 100, 0, 0, 'Blue'),
235 // Add here standard spot colors or dynamically define them with AddSpotColor()
236 // ...
237 ); // end of spot colors
238
239 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
240
241 /**
242 * Return the Spot color array.
243 * @param $name (string) Name of the spot color.
244 * @param $spotc (array) Reference to an array of spot colors.
245 * @return (array) Spot color array or false if not defined.
246 * @since 5.9.125 (2011-10-03)
247 * @public static
248 */
249 public static function getSpotColor($name, &$spotc) {
250 if (isset($spotc[$name])) {
251 return $spotc[$name];
252 }
253 $color = preg_replace('/[\s]*/', '', $name); // remove extra spaces
254 $color = strtolower($color);
255 if (isset(self::$spotcolor[$color])) {
256 if (!isset($spotc[$name])) {
257 $i = (1 + count($spotc));
258 $spotc[$name] = array('C' => self::$spotcolor[$color][0], 'M' => self::$spotcolor[$color][1], 'Y' => self::$spotcolor[$color][2], 'K' => self::$spotcolor[$color][3], 'name' => self::$spotcolor[$color][4], 'i' => $i);
259 }
260 return $spotc[self::$spotcolor[$color][4]];
261 }
262 return false;
263 }
264
265 /**
266 * Returns an array (RGB or CMYK) from an html color name, or a six-digit (i.e. #3FE5AA), or three-digit (i.e. #7FF) hexadecimal color, or a javascript color array, or javascript color name.
267 * @param $hcolor (string) HTML color.
268 * @param $spotc (array) Reference to an array of spot colors.
269 * @param $defcol (array) Color to return in case of error.
270 * @return array RGB or CMYK color, or false in case of error.
271 * @public static
272 */
273 public static function convertHTMLColorToDec($hcolor, &$spotc, $defcol=array('R'=>128,'G'=>128,'B'=>128)) {
274 $color = preg_replace('/[\s]*/', '', $hcolor); // remove extra spaces
275 $color = strtolower($color);
276 // check for javascript color array syntax
277 if (strpos($color, '[') !== false) {
278 if (preg_match('/[\[][\"\'](t|g|rgb|cmyk)[\"\'][\,]?([0-9\.]*)[\,]?([0-9\.]*)[\,]?([0-9\.]*)[\,]?([0-9\.]*)[\]]/', $color, $m) > 0) {
279 $returncolor = array();
280 switch ($m[1]) {
281 case 'cmyk': {
282 // RGB
283 $returncolor['C'] = max(0, min(100, (floatval($m[2]) * 100)));
284 $returncolor['M'] = max(0, min(100, (floatval($m[3]) * 100)));
285 $returncolor['Y'] = max(0, min(100, (floatval($m[4]) * 100)));
286 $returncolor['K'] = max(0, min(100, (floatval($m[5]) * 100)));
287 break;
288 }
289 case 'rgb': {
290 // RGB
291 $returncolor['R'] = max(0, min(255, (floatval($m[2]) * 255)));
292 $returncolor['G'] = max(0, min(255, (floatval($m[3]) * 255)));
293 $returncolor['B'] = max(0, min(255, (floatval($m[4]) * 255)));
294 break;
295 }
296 case 'g': {
297 // grayscale
298 $returncolor['G'] = max(0, min(255, (floatval($m[2]) * 255)));
299 break;
300 }
301 case 't':
302 default: {
303 // transparent (empty array)
304 break;
305 }
306 }
307 return $returncolor;
308 }
309 } elseif ((substr($color, 0, 4) != 'cmyk') AND (substr($color, 0, 3) != 'rgb') AND (($dotpos = strpos($color, '.')) !== false)) {
310 // remove class parent (i.e.: color.red)
311 $color = substr($color, ($dotpos + 1));
312 if ($color == 'transparent') {
313 // transparent (empty array)
314 return array();
315 }
316 }
317 if (strlen($color) == 0) {
318 return $defcol;
319 }
320 // RGB ARRAY
321 if (substr($color, 0, 3) == 'rgb') {
322 $codes = substr($color, 4);
323 $codes = str_replace(')', '', $codes);
324 $returncolor = explode(',', $codes);
325 foreach ($returncolor as $key => $val) {
326 if (strpos($val, '%') > 0) {
327 // percentage
328 $returncolor[$key] = (255 * intval($val) / 100);
329 } else {
330 $returncolor[$key] = intval($val);
331 }
332 // normalize value
333 $returncolor[$key] = max(0, min(255, $returncolor[$key]));
334 }
335 return $returncolor;
336 }
337 // CMYK ARRAY
338 if (substr($color, 0, 4) == 'cmyk') {
339 $codes = substr($color, 5);
340 $codes = str_replace(')', '', $codes);
341 $returncolor = explode(',', $codes);
342 foreach ($returncolor as $key => $val) {
343 if (strpos($val, '%') !== false) {
344 // percentage
345 $returncolor[$key] = (100 * intval($val) / 100);
346 } else {
347 $returncolor[$key] = intval($val);
348 }
349 // normalize value
350 $returncolor[$key] = max(0, min(100, $returncolor[$key]));
351 }
352 return $returncolor;
353 }
354 if ($color[0] != '#') {
355 // COLOR NAME
356 if (isset(self::$webcolor[$color])) {
357 // web color
358 $color_code = self::$webcolor[$color];
359 } else {
360 // spot color
361 $returncolor = self::getSpotColor($color, $spotc);
362 if ($returncolor === false) {
363 $returncolor = $defcol;
364 }
365 return $returncolor;
366 }
367 } else {
368 $color_code = substr($color, 1);
369 }
370 // HEXADECIMAL REPRESENTATION
371 switch (strlen($color_code)) {
372 case 3: {
373 // 3-digit RGB hexadecimal representation
374 $r = substr($color_code, 0, 1);
375 $g = substr($color_code, 1, 1);
376 $b = substr($color_code, 2, 1);
377 $returncolor = array();
378 $returncolor['R'] = max(0, min(255, hexdec($r.$r)));
379 $returncolor['G'] = max(0, min(255, hexdec($g.$g)));
380 $returncolor['B'] = max(0, min(255, hexdec($b.$b)));
381 break;
382 }
383 case 6: {
384 // 6-digit RGB hexadecimal representation
385 $returncolor = array();
386 $returncolor['R'] = max(0, min(255, hexdec(substr($color_code, 0, 2))));
387 $returncolor['G'] = max(0, min(255, hexdec(substr($color_code, 2, 2))));
388 $returncolor['B'] = max(0, min(255, hexdec(substr($color_code, 4, 2))));
389 break;
390 }
391 case 8: {
392 // 8-digit CMYK hexadecimal representation
393 $returncolor = array();
394 $returncolor['C'] = max(0, min(100, round(hexdec(substr($color_code, 0, 2)) / 2.55)));
395 $returncolor['M'] = max(0, min(100, round(hexdec(substr($color_code, 2, 2)) / 2.55)));
396 $returncolor['Y'] = max(0, min(100, round(hexdec(substr($color_code, 4, 2)) / 2.55)));
397 $returncolor['K'] = max(0, min(100, round(hexdec(substr($color_code, 6, 2)) / 2.55)));
398 break;
399 }
400 default: {
401 $returncolor = $defcol;
402 break;
403 }
404 }
405 return $returncolor;
406 }
407
408 /**
409 * Convert a color array into a string representation.
410 * @param $c (array) Array of colors.
411 * @return (string) The color array representation.
412 * @since 5.9.137 (2011-12-01)
413 * @public static
414 */
415 public static function getColorStringFromArray($c) {
416 $c = array_values($c);
417 $color = '[';
418 switch (count($c)) {
419 case 4: {
420 // CMYK
421 $color .= sprintf('%F %F %F %F', (max(0, min(100, floatval($c[0]))) / 100), (max(0, min(100, floatval($c[1]))) / 100), (max(0, min(100, floatval($c[2]))) / 100), (max(0, min(100, floatval($c[3]))) / 100));
422 break;
423 }
424 case 3: {
425 // RGB
426 $color .= sprintf('%F %F %F', (max(0, min(255, floatval($c[0]))) / 255), (max(0, min(255, floatval($c[1]))) / 255), (max(0, min(255, floatval($c[2]))) / 255));
427 break;
428 }
429 case 1: {
430 // grayscale
431 $color .= sprintf('%F', (max(0, min(255, floatval($c[0]))) / 255));
432 break;
433 }
434 }
435 $color .= ']';
436 return $color;
437 }
438
439 /**
440 * Convert color to javascript color.
441 * @param $color (string) color name or "#RRGGBB"
442 * @protected
443 * @since 2.1.002 (2008-02-12)
444 * @public static
445 */
446 public static function _JScolor($color) {
447 if (substr($color, 0, 1) == '#') {
448 return sprintf("['RGB',%F,%F,%F]", (hexdec(substr($color, 1, 2)) / 255), (hexdec(substr($color, 3, 2)) / 255), (hexdec(substr($color, 5, 2)) / 255));
449 }
450 if (!in_array($color, self::$jscolor)) {
451 // default transparent color
452 $color = $jscolor[0];
453 }
454 return 'color.'.$color;
455 }
456
457
458} // END OF TCPDF_COLORS CLASS
459
460//============================================================+
461// END OF FILE
462//============================================================+
diff --git a/inc/3rdparty/libraries/tcpdf/include/tcpdf_filters.php b/inc/3rdparty/libraries/tcpdf/include/tcpdf_filters.php
new file mode 100644
index 00000000..96584db5
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/include/tcpdf_filters.php
@@ -0,0 +1,481 @@
1<?php
2//============================================================+
3// File name : tcpdf_filters.php
4// Version : 1.0.001
5// Begin : 2011-05-23
6// Last Update : 2014-04-25
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) 2011-2013 Nicola Asuni - Tecnick.com LTD
11//
12// This file is part of TCPDF software library.
13//
14// TCPDF is free software: you can redistribute it and/or modify it
15// under the terms of the GNU Lesser General Public License as
16// published by the Free Software Foundation, either version 3 of the
17// License, or (at your option) any later version.
18//
19// TCPDF is distributed in the hope that it will be useful, but
20// WITHOUT ANY WARRANTY; without even the implied warranty of
21// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22// See the GNU Lesser General Public License for more details.
23//
24// You should have received a copy of the License
25// along with TCPDF. If not, see
26// <http://www.tecnick.com/pagefiles/tcpdf/LICENSE.TXT>.
27//
28// See LICENSE.TXT file for more information.
29// -------------------------------------------------------------------
30//
31// Description : This is a PHP class for decoding common PDF filters (PDF 32000-2008 - 7.4 Filters).
32//
33//============================================================+
34
35/**
36 * @file
37 * This is a PHP class for decoding common PDF filters (PDF 32000-2008 - 7.4 Filters).<br>
38 * @package com.tecnick.tcpdf
39 * @author Nicola Asuni
40 * @version 1.0.001
41 */
42
43/**
44 * @class TCPDF_FILTERS
45 * This is a PHP class for decoding common PDF filters (PDF 32000-2008 - 7.4 Filters).<br>
46 * @package com.tecnick.tcpdf
47 * @brief This is a PHP class for decoding common PDF filters.
48 * @version 1.0.001
49 * @author Nicola Asuni - info@tecnick.com
50 */
51class TCPDF_FILTERS {
52
53 /**
54 * Define a list of available filter decoders.
55 * @private static
56 */
57 private static $available_filters = array('ASCIIHexDecode', 'ASCII85Decode', 'LZWDecode', 'FlateDecode', 'RunLengthDecode');
58
59// -----------------------------------------------------------------------------
60
61 /**
62 * Get a list of available decoding filters.
63 * @return (array) Array of available filter decoders.
64 * @since 1.0.000 (2011-05-23)
65 * @public static
66 */
67 public static function getAvailableFilters() {
68 return self::$available_filters;
69 }
70
71 /**
72 * Decode data using the specified filter type.
73 * @param $filter (string) Filter name.
74 * @param $data (string) Data to decode.
75 * @return Decoded data string.
76 * @since 1.0.000 (2011-05-23)
77 * @public static
78 */
79 public static function decodeFilter($filter, $data) {
80 switch ($filter) {
81 case 'ASCIIHexDecode': {
82 return self::decodeFilterASCIIHexDecode($data);
83 break;
84 }
85 case 'ASCII85Decode': {
86 return self::decodeFilterASCII85Decode($data);
87 break;
88 }
89 case 'LZWDecode': {
90 return self::decodeFilterLZWDecode($data);
91 break;
92 }
93 case 'FlateDecode': {
94 return self::decodeFilterFlateDecode($data);
95 break;
96 }
97 case 'RunLengthDecode': {
98 return self::decodeFilterRunLengthDecode($data);
99 break;
100 }
101 case 'CCITTFaxDecode': {
102 return self::decodeFilterCCITTFaxDecode($data);
103 break;
104 }
105 case 'JBIG2Decode': {
106 return self::decodeFilterJBIG2Decode($data);
107 break;
108 }
109 case 'DCTDecode': {
110 return self::decodeFilterDCTDecode($data);
111 break;
112 }
113 case 'JPXDecode': {
114 return self::decodeFilterJPXDecode($data);
115 break;
116 }
117 case 'Crypt': {
118 return self::decodeFilterCrypt($data);
119 break;
120 }
121 default: {
122 return self::decodeFilterStandard($data);
123 break;
124 }
125 }
126 }
127
128 // --- FILTERS (PDF 32000-2008 - 7.4 Filters) ------------------------------
129
130 /**
131 * Standard
132 * Default decoding filter (leaves data unchanged).
133 * @param $data (string) Data to decode.
134 * @return Decoded data string.
135 * @since 1.0.000 (2011-05-23)
136 * @public static
137 */
138 public static function decodeFilterStandard($data) {
139 return $data;
140 }
141
142 /**
143 * ASCIIHexDecode
144 * Decodes data encoded in an ASCII hexadecimal representation, reproducing the original binary data.
145 * @param $data (string) Data to decode.
146 * @return Decoded data string.
147 * @since 1.0.000 (2011-05-23)
148 * @public static
149 */
150 public static function decodeFilterASCIIHexDecode($data) {
151 // intialize string to return
152 $decoded = '';
153 // all white-space characters shall be ignored
154 $data = preg_replace('/[\s]/', '', $data);
155 // check for EOD character: GREATER-THAN SIGN (3Eh)
156 $eod = strpos($data, '>');
157 if ($eod !== false) {
158 // remove EOD and extra data (if any)
159 $data = substr($data, 0, $eod);
160 $eod = true;
161 }
162 // get data length
163 $data_length = strlen($data);
164 if (($data_length % 2) != 0) {
165 // odd number of hexadecimal digits
166 if ($eod) {
167 // EOD shall behave as if a 0 (zero) followed the last digit
168 $data = substr($data, 0, -1).'0'.substr($data, -1);
169 } else {
170 self::Error('decodeFilterASCIIHexDecode: invalid code');
171 }
172 }
173 // check for invalid characters
174 if (preg_match('/[^a-fA-F\d]/', $data) > 0) {
175 self::Error('decodeFilterASCIIHexDecode: invalid code');
176 }
177 // get one byte of binary data for each pair of ASCII hexadecimal digits
178 $decoded = pack('H*', $data);
179 return $decoded;
180 }
181
182 /**
183 * ASCII85Decode
184 * Decodes data encoded in an ASCII base-85 representation, reproducing the original binary data.
185 * @param $data (string) Data to decode.
186 * @return Decoded data string.
187 * @since 1.0.000 (2011-05-23)
188 * @public static
189 */
190 public static function decodeFilterASCII85Decode($data) {
191 // intialize string to return
192 $decoded = '';
193 // all white-space characters shall be ignored
194 $data = preg_replace('/[\s]/', '', $data);
195 // remove start sequence 2-character sequence <~ (3Ch)(7Eh)
196 if (strpos($data, '<~') !== false) {
197 // remove EOD and extra data (if any)
198 $data = substr($data, 2);
199 }
200 // check for EOD: 2-character sequence ~> (7Eh)(3Eh)
201 $eod = strpos($data, '~>');
202 if ($eod !== false) {
203 // remove EOD and extra data (if any)
204 $data = substr($data, 0, $eod);
205 }
206 // data length
207 $data_length = strlen($data);
208 // check for invalid characters
209 if (preg_match('/[^\x21-\x75,\x74]/', $data) > 0) {
210 self::Error('decodeFilterASCII85Decode: invalid code');
211 }
212 // z sequence
213 $zseq = chr(0).chr(0).chr(0).chr(0);
214 // position inside a group of 4 bytes (0-3)
215 $group_pos = 0;
216 $tuple = 0;
217 $pow85 = array((85*85*85*85), (85*85*85), (85*85), 85, 1);
218 $last_pos = ($data_length - 1);
219 // for each byte
220 for ($i = 0; $i < $data_length; ++$i) {
221 // get char value
222 $char = ord($data[$i]);
223 if ($char == 122) { // 'z'
224 if ($group_pos == 0) {
225 $decoded .= $zseq;
226 } else {
227 self::Error('decodeFilterASCII85Decode: invalid code');
228 }
229 } else {
230 // the value represented by a group of 5 characters should never be greater than 2^32 - 1
231 $tuple += (($char - 33) * $pow85[$group_pos]);
232 if ($group_pos == 4) {
233 $decoded .= chr($tuple >> 24).chr($tuple >> 16).chr($tuple >> 8).chr($tuple);
234 $tuple = 0;
235 $group_pos = 0;
236 } else {
237 ++$group_pos;
238 }
239 }
240 }
241 if ($group_pos > 1) {
242 $tuple += $pow85[($group_pos - 1)];
243 }
244 // last tuple (if any)
245 switch ($group_pos) {
246 case 4: {
247 $decoded .= chr($tuple >> 24).chr($tuple >> 16).chr($tuple >> 8);
248 break;
249 }
250 case 3: {
251 $decoded .= chr($tuple >> 24).chr($tuple >> 16);
252 break;
253 }
254 case 2: {
255 $decoded .= chr($tuple >> 24);
256 break;
257 }
258 case 1: {
259 self::Error('decodeFilterASCII85Decode: invalid code');
260 break;
261 }
262 }
263 return $decoded;
264 }
265
266 /**
267 * LZWDecode
268 * Decompresses data encoded using the LZW (Lempel-Ziv-Welch) adaptive compression method, reproducing the original text or binary data.
269 * @param $data (string) Data to decode.
270 * @return Decoded data string.
271 * @since 1.0.000 (2011-05-23)
272 * @public static
273 */
274 public static function decodeFilterLZWDecode($data) {
275 // intialize string to return
276 $decoded = '';
277 // data length
278 $data_length = strlen($data);
279 // convert string to binary string
280 $bitstring = '';
281 for ($i = 0; $i < $data_length; ++$i) {
282 $bitstring .= sprintf('%08b', ord($data{$i}));
283 }
284 // get the number of bits
285 $data_length = strlen($bitstring);
286 // initialize code length in bits
287 $bitlen = 9;
288 // initialize dictionary index
289 $dix = 258;
290 // initialize the dictionary (with the first 256 entries).
291 $dictionary = array();
292 for ($i = 0; $i < 256; ++$i) {
293 $dictionary[$i] = chr($i);
294 }
295 // previous val
296 $prev_index = 0;
297 // while we encounter EOD marker (257), read code_length bits
298 while (($data_length > 0) AND (($index = bindec(substr($bitstring, 0, $bitlen))) != 257)) {
299 // remove read bits from string
300 $bitstring = substr($bitstring, $bitlen);
301 // update number of bits
302 $data_length -= $bitlen;
303 if ($index == 256) { // clear-table marker
304 // reset code length in bits
305 $bitlen = 9;
306 // reset dictionary index
307 $dix = 258;
308 $prev_index = 256;
309 // reset the dictionary (with the first 256 entries).
310 $dictionary = array();
311 for ($i = 0; $i < 256; ++$i) {
312 $dictionary[$i] = chr($i);
313 }
314 } elseif ($prev_index == 256) {
315 // first entry
316 $decoded .= $dictionary[$index];
317 $prev_index = $index;
318 } else {
319 // check if index exist in the dictionary
320 if ($index < $dix) {
321 // index exist on dictionary
322 $decoded .= $dictionary[$index];
323 $dic_val = $dictionary[$prev_index].$dictionary[$index][0];
324 // store current index
325 $prev_index = $index;
326 } else {
327 // index do not exist on dictionary
328 $dic_val = $dictionary[$prev_index].$dictionary[$prev_index][0];
329 $decoded .= $dic_val;
330 }
331 // update dictionary
332 $dictionary[$dix] = $dic_val;
333 ++$dix;
334 // change bit length by case
335 if ($dix == 2047) {
336 $bitlen = 12;
337 } elseif ($dix == 1023) {
338 $bitlen = 11;
339 } elseif ($dix == 511) {
340 $bitlen = 10;
341 }
342 }
343 }
344 return $decoded;
345 }
346
347 /**
348 * FlateDecode
349 * Decompresses data encoded using the zlib/deflate compression method, reproducing the original text or binary data.
350 * @param $data (string) Data to decode.
351 * @return Decoded data string.
352 * @since 1.0.000 (2011-05-23)
353 * @public static
354 */
355 public static function decodeFilterFlateDecode($data) {
356 // intialize string to return
357 $decoded = @gzuncompress($data);
358 if ($decoded === false) {
359 self::Error('decodeFilterFlateDecode: invalid code');
360 }
361 return $decoded;
362 }
363
364 /**
365 * RunLengthDecode
366 * Decompresses data encoded using a byte-oriented run-length encoding algorithm.
367 * @param $data (string) Data to decode.
368 * @since 1.0.000 (2011-05-23)
369 * @public static
370 */
371 public static function decodeFilterRunLengthDecode($data) {
372 // intialize string to return
373 $decoded = '';
374 // data length
375 $data_length = strlen($data);
376 $i = 0;
377 while($i < $data_length) {
378 // get current byte value
379 $byte = ord($data{$i});
380 if ($byte == 128) {
381 // a length value of 128 denote EOD
382 break;
383 } elseif ($byte < 128) {
384 // if the length byte is in the range 0 to 127
385 // the following length + 1 (1 to 128) bytes shall be copied literally during decompression
386 $decoded .= substr($data, ($i + 1), ($byte + 1));
387 // move to next block
388 $i += ($byte + 2);
389 } else {
390 // if length is in the range 129 to 255,
391 // the following single byte shall be copied 257 - length (2 to 128) times during decompression
392 $decoded .= str_repeat($data{($i + 1)}, (257 - $byte));
393 // move to next block
394 $i += 2;
395 }
396 }
397 return $decoded;
398 }
399
400 /**
401 * CCITTFaxDecode (NOT IMPLEMETED - RETURN AN EXCEPTION)
402 * Decompresses data encoded using the CCITT facsimile standard, reproducing the original data (typically monochrome image data at 1 bit per pixel).
403 * @param $data (string) Data to decode.
404 * @return Decoded data string.
405 * @since 1.0.000 (2011-05-23)
406 * @public static
407 */
408 public static function decodeFilterCCITTFaxDecode($data) {
409 self::Error('~decodeFilterCCITTFaxDecode: this method has not been yet implemented');
410 //return $data;
411 }
412
413 /**
414 * JBIG2Decode (NOT IMPLEMETED - RETURN AN EXCEPTION)
415 * Decompresses data encoded using the JBIG2 standard, reproducing the original monochrome (1 bit per pixel) image data (or an approximation of that data).
416 * @param $data (string) Data to decode.
417 * @return Decoded data string.
418 * @since 1.0.000 (2011-05-23)
419 * @public static
420 */
421 public static function decodeFilterJBIG2Decode($data) {
422 self::Error('~decodeFilterJBIG2Decode: this method has not been yet implemented');
423 //return $data;
424 }
425
426 /**
427 * DCTDecode (NOT IMPLEMETED - RETURN AN EXCEPTION)
428 * Decompresses data encoded using a DCT (discrete cosine transform) technique based on the JPEG standard, reproducing image sample data that approximates the original data.
429 * @param $data (string) Data to decode.
430 * @return Decoded data string.
431 * @since 1.0.000 (2011-05-23)
432 * @public static
433 */
434 public static function decodeFilterDCTDecode($data) {
435 self::Error('~decodeFilterDCTDecode: this method has not been yet implemented');
436 //return $data;
437 }
438
439 /**
440 * JPXDecode (NOT IMPLEMETED - RETURN AN EXCEPTION)
441 * Decompresses data encoded using the wavelet-based JPEG2000 standard, reproducing the original image data.
442 * @param $data (string) Data to decode.
443 * @return Decoded data string.
444 * @since 1.0.000 (2011-05-23)
445 * @public static
446 */
447 public static function decodeFilterJPXDecode($data) {
448 self::Error('~decodeFilterJPXDecode: this method has not been yet implemented');
449 //return $data;
450 }
451
452 /**
453 * Crypt (NOT IMPLEMETED - RETURN AN EXCEPTION)
454 * Decrypts data encrypted by a security handler, reproducing the data as it was before encryption.
455 * @param $data (string) Data to decode.
456 * @return Decoded data string.
457 * @since 1.0.000 (2011-05-23)
458 * @public static
459 */
460 public static function decodeFilterCrypt($data) {
461 self::Error('~decodeFilterCrypt: this method has not been yet implemented');
462 //return $data;
463 }
464
465 // --- END FILTERS SECTION -------------------------------------------------
466
467 /**
468 * Throw an exception.
469 * @param $msg (string) The error message
470 * @since 1.0.000 (2011-05-23)
471 * @public static
472 */
473 public static function Error($msg) {
474 throw new Exception('TCPDF_PARSER ERROR: '.$msg);
475 }
476
477} // END OF TCPDF_FILTERS CLASS
478
479//============================================================+
480// END OF FILE
481//============================================================+
diff --git a/inc/3rdparty/libraries/tcpdf/include/tcpdf_font_data.php b/inc/3rdparty/libraries/tcpdf/include/tcpdf_font_data.php
new file mode 100644
index 00000000..974e72ec
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/include/tcpdf_font_data.php
@@ -0,0 +1,18447 @@
1<?php
2//============================================================+
3// File name : tcpdf_font_data.php
4// Version : 1.0.001
5// Begin : 2008-01-01
6// Last Update : 2013-04-01
7// Author : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com
8// License : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html)
9// -------------------------------------------------------------------
10// Copyright (C) 2008-2013 Nicola Asuni - Tecnick.com LTD
11//
12// This file is part of TCPDF software library.
13//
14// TCPDF is free software: you can redistribute it and/or modify it
15// under the terms of the GNU Lesser General Public License as
16// published by the Free Software Foundation, either version 3 of the
17// License, or (at your option) any later version.
18//
19// TCPDF is distributed in the hope that it will be useful, but
20// WITHOUT ANY WARRANTY; without even the implied warranty of
21// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22// See the GNU Lesser General Public License for more details.
23//
24// You should have received a copy of the GNU Lesser General Public License
25// along with TCPDF. If not, see <http://www.gnu.org/licenses/>.
26//
27// See LICENSE.TXT file for more information.
28// -------------------------------------------------------------------
29//
30// Description : Unicode data and encoding maps for TCPDF.
31//
32//============================================================+
33
34/**
35 * @file
36 * Unicode data and encoding maps for TCPDF.
37 * @author Nicola Asuni
38 * @package com.tecnick.tcpdf
39 */
40
41/**
42 * @class TCPDF_FONT_DATA
43 * Unicode data and encoding maps for TCPDF.
44 * @package com.tecnick.tcpdf
45 * @version 1.0.001
46 * @author Nicola Asuni - info@tecnick.com
47 */
48class TCPDF_FONT_DATA {
49
50/**
51 * Unicode code for Left-to-Right Mark.
52 * @public
53 */
54public static $uni_LRM = 8206;
55
56/**
57 * Unicode code for Right-to-Left Mark.
58 * @public
59 */
60public static $uni_RLM = 8207;
61
62/**
63 * Unicode code for Left-to-Right Embedding.
64 * @public
65 */
66public static $uni_LRE = 8234;
67
68/**
69 * Unicode code for Right-to-Left Embedding.
70 * @public
71 */
72public static $uni_RLE = 8235;
73
74/**
75 * Unicode code for Pop Directional Format.
76 * @public
77 */
78public static $uni_PDF = 8236;
79
80/**
81 * Unicode code for Left-to-Right Override.
82 * @public
83 */
84public static $uni_LRO = 8237;
85
86/**
87 * Unicode code for Right-to-Left Override.
88 * @public
89 */
90public static $uni_RLO = 8238;
91
92/**
93 * Pattern to test RTL (Righ-To-Left) strings using regular expressions.
94 * @public
95 */
96public static $uni_RE_PATTERN_RTL = "/(
97 \xD6\xBE # R
98 | \xD7[\x80\x83\x86\x90-\xAA\xB0-\xB4] # R
99 | \xDF[\x80-\xAA\xB4\xB5\xBA] # R
100 | \xE2\x80\x8F # R
101 | \xEF\xAC[\x9D\x9F\xA0-\xA8\xAA-\xB6\xB8-\xBC\xBE] # R
102 | \xEF\xAD[\x80\x81\x83\x84\x86-\x8F] # R
103 | \xF0\x90\xA0[\x80-\x85\x88\x8A-\xB5\xB7\xB8\xBC\xBF] # R
104 | \xF0\x90\xA4[\x80-\x99] # R
105 | \xF0\x90\xA8[\x80\x90-\x93\x95-\x97\x99-\xB3] # R
106 | \xF0\x90\xA9[\x80-\x87\x90-\x98] # R
107 | \xE2\x80[\xAB\xAE] # RLE & RLO
108 )/x";
109
110/**
111 * Pattern to test Arabic strings using regular expressions. Source: http://www.w3.org/International/questions/qa-forms-utf-8
112 * @public
113 */
114public static $uni_RE_PATTERN_ARABIC = "/(
115 \xD8[\x80-\x83\x8B\x8D\x9B\x9E\x9F\xA1-\xBA] # AL
116 | \xD9[\x80-\x8A\xAD-\xAF\xB1-\xBF] # AL
117 | \xDA[\x80-\xBF] # AL
118 | \xDB[\x80-\x95\x9D\xA5\xA6\xAE\xAF\xBA-\xBF] # AL
119 | \xDC[\x80-\x8D\x90\x92-\xAF] # AL
120 | \xDD[\x8D-\xAD] # AL
121 | \xDE[\x80-\xA5\xB1] # AL
122 | \xEF\xAD[\x90-\xBF] # AL
123 | \xEF\xAE[\x80-\xB1] # AL
124 | \xEF\xAF[\x93-\xBF] # AL
125 | \xEF[\xB0-\xB3][\x80-\xBF] # AL
126 | \xEF\xB4[\x80-\xBD] # AL
127 | \xEF\xB5[\x90-\xBF] # AL
128 | \xEF\xB6[\x80-\x8F\x92-\xBF] # AL
129 | \xEF\xB7[\x80-\x87\xB0-\xBC] # AL
130 | \xEF\xB9[\xB0-\xB4\xB6-\xBF] # AL
131 | \xEF\xBA[\x80-\xBF] # AL
132 | \xEF\xBB[\x80-\xBC] # AL
133 | \xD9[\xA0-\xA9\xAB\xAC] # AN
134 )/x";
135
136/**
137 * Array of Unicode types.
138 * @public
139 */
140public static $uni_type = array(
1410=>'BN',
1421=>'BN',
1432=>'BN',
1443=>'BN',
1454=>'BN',
1465=>'BN',
1476=>'BN',
1487=>'BN',
1498=>'BN',
1509=>'S',
15110=>'B',
15211=>'S',
15312=>'WS',
15413=>'B',
15514=>'BN',
15615=>'BN',
15716=>'BN',
15817=>'BN',
15918=>'BN',
16019=>'BN',
16120=>'BN',
16221=>'BN',
16322=>'BN',
16423=>'BN',
16524=>'BN',
16625=>'BN',
16726=>'BN',
16827=>'BN',
16928=>'B',
17029=>'B',
17130=>'B',
17231=>'S',
17332=>'WS',
17433=>'ON',
17534=>'ON',
17635=>'ET',
17736=>'ET',
17837=>'ET',
17938=>'ON',
18039=>'ON',
18140=>'ON',
18241=>'ON',
18342=>'ON',
18443=>'ES',
18544=>'CS',
18645=>'ES',
18746=>'CS',
18847=>'CS',
18948=>'EN',
19049=>'EN',
19150=>'EN',
19251=>'EN',
19352=>'EN',
19453=>'EN',
19554=>'EN',
19655=>'EN',
19756=>'EN',
19857=>'EN',
19958=>'CS',
20059=>'ON',
20160=>'ON',
20261=>'ON',
20362=>'ON',
20463=>'ON',
20564=>'ON',
20665=>'L',
20766=>'L',
20867=>'L',
20968=>'L',
21069=>'L',
21170=>'L',
21271=>'L',
21372=>'L',
21473=>'L',
21574=>'L',
21675=>'L',
21776=>'L',
21877=>'L',
21978=>'L',
22079=>'L',
22180=>'L',
22281=>'L',
22382=>'L',
22483=>'L',
22584=>'L',
22685=>'L',
22786=>'L',
22887=>'L',
22988=>'L',
23089=>'L',
23190=>'L',
23291=>'ON',
23392=>'ON',
23493=>'ON',
23594=>'ON',
23695=>'ON',
23796=>'ON',
23897=>'L',
23998=>'L',
24099=>'L',
241100=>'L',
242101=>'L',
243102=>'L',
244103=>'L',
245104=>'L',
246105=>'L',
247106=>'L',
248107=>'L',
249108=>'L',
250109=>'L',
251110=>'L',
252111=>'L',
253112=>'L',
254113=>'L',
255114=>'L',
256115=>'L',
257116=>'L',
258117=>'L',
259118=>'L',
260119=>'L',
261120=>'L',
262121=>'L',
263122=>'L',
264123=>'ON',
265124=>'ON',
266125=>'ON',
267126=>'ON',
268127=>'BN',
269128=>'BN',
270129=>'BN',
271130=>'BN',
272131=>'BN',
273132=>'BN',
274133=>'B',
275134=>'BN',
276135=>'BN',
277136=>'BN',
278137=>'BN',
279138=>'BN',
280139=>'BN',
281140=>'BN',
282141=>'BN',
283142=>'BN',
284143=>'BN',
285144=>'BN',
286145=>'BN',
287146=>'BN',
288147=>'BN',
289148=>'BN',
290149=>'BN',
291150=>'BN',
292151=>'BN',
293152=>'BN',
294153=>'BN',
295154=>'BN',
296155=>'BN',
297156=>'BN',
298157=>'BN',
299158=>'BN',
300159=>'BN',
301160=>'CS',
302161=>'ON',
303162=>'ET',
304163=>'ET',
305164=>'ET',
306165=>'ET',
307166=>'ON',
308167=>'ON',
309168=>'ON',
310169=>'ON',
311170=>'L',
312171=>'ON',
313172=>'ON',
314173=>'BN',
315174=>'ON',
316175=>'ON',
317176=>'ET',
318177=>'ET',
319178=>'EN',
320179=>'EN',
321180=>'ON',
322181=>'L',
323182=>'ON',
324183=>'ON',
325184=>'ON',
326185=>'EN',
327186=>'L',
328187=>'ON',
329188=>'ON',
330189=>'ON',
331190=>'ON',
332191=>'ON',
333192=>'L',
334193=>'L',
335194=>'L',
336195=>'L',
337196=>'L',
338197=>'L',
339198=>'L',
340199=>'L',
341200=>'L',
342201=>'L',
343202=>'L',
344203=>'L',
345204=>'L',
346205=>'L',
347206=>'L',
348207=>'L',
349208=>'L',
350209=>'L',
351210=>'L',
352211=>'L',
353212=>'L',
354213=>'L',
355214=>'L',
356215=>'ON',
357216=>'L',
358217=>'L',
359218=>'L',
360219=>'L',
361220=>'L',
362221=>'L',
363222=>'L',
364223=>'L',
365224=>'L',
366225=>'L',
367226=>'L',
368227=>'L',
369228=>'L',
370229=>'L',
371230=>'L',
372231=>'L',
373232=>'L',
374233=>'L',
375234=>'L',
376235=>'L',
377236=>'L',
378237=>'L',
379238=>'L',
380239=>'L',
381240=>'L',
382241=>'L',
383242=>'L',
384243=>'L',
385244=>'L',
386245=>'L',
387246=>'L',
388247=>'ON',
389248=>'L',
390249=>'L',
391250=>'L',
392251=>'L',
393252=>'L',
394253=>'L',
395254=>'L',
396255=>'L',
397256=>'L',
398257=>'L',
399258=>'L',
400259=>'L',
401260=>'L',
402261=>'L',
403262=>'L',
404263=>'L',
405264=>'L',
406265=>'L',
407266=>'L',
408267=>'L',
409268=>'L',
410269=>'L',
411270=>'L',
412271=>'L',
413272=>'L',
414273=>'L',
415274=>'L',
416275=>'L',
417276=>'L',
418277=>'L',
419278=>'L',
420279=>'L',
421280=>'L',
422281=>'L',
423282=>'L',
424283=>'L',
425284=>'L',
426285=>'L',
427286=>'L',
428287=>'L',
429288=>'L',
430289=>'L',
431290=>'L',
432291=>'L',
433292=>'L',
434293=>'L',
435294=>'L',
436295=>'L',
437296=>'L',
438297=>'L',
439298=>'L',
440299=>'L',
441300=>'L',
442301=>'L',
443302=>'L',
444303=>'L',
445304=>'L',
446305=>'L',
447306=>'L',
448307=>'L',
449308=>'L',
450309=>'L',
451310=>'L',
452311=>'L',
453312=>'L',
454313=>'L',
455314=>'L',
456315=>'L',
457316=>'L',
458317=>'L',
459318=>'L',
460319=>'L',
461320=>'L',
462321=>'L',
463322=>'L',
464323=>'L',
465324=>'L',
466325=>'L',
467326=>'L',
468327=>'L',
469328=>'L',
470329=>'L',
471330=>'L',
472331=>'L',
473332=>'L',
474333=>'L',
475334=>'L',
476335=>'L',
477336=>'L',
478337=>'L',
479338=>'L',
480339=>'L',
481340=>'L',
482341=>'L',
483342=>'L',
484343=>'L',
485344=>'L',
486345=>'L',
487346=>'L',
488347=>'L',
489348=>'L',
490349=>'L',
491350=>'L',
492351=>'L',
493352=>'L',
494353=>'L',
495354=>'L',
496355=>'L',
497356=>'L',
498357=>'L',
499358=>'L',
500359=>'L',
501360=>'L',
502361=>'L',
503362=>'L',
504363=>'L',
505364=>'L',
506365=>'L',
507366=>'L',
508367=>'L',
509368=>'L',
510369=>'L',
511370=>'L',
512371=>'L',
513372=>'L',
514373=>'L',
515374=>'L',
516375=>'L',
517376=>'L',
518377=>'L',
519378=>'L',
520379=>'L',
521380=>'L',
522381=>'L',
523382=>'L',
524383=>'L',
525384=>'L',
526385=>'L',
527386=>'L',
528387=>'L',
529388=>'L',
530389=>'L',
531390=>'L',
532391=>'L',
533392=>'L',
534393=>'L',
535394=>'L',
536395=>'L',
537396=>'L',
538397=>'L',
539398=>'L',
540399=>'L',
541400=>'L',
542401=>'L',
543402=>'L',
544403=>'L',
545404=>'L',
546405=>'L',
547406=>'L',
548407=>'L',
549408=>'L',
550409=>'L',
551410=>'L',
552411=>'L',
553412=>'L',
554413=>'L',
555414=>'L',
556415=>'L',
557416=>'L',
558417=>'L',
559418=>'L',
560419=>'L',
561420=>'L',
562421=>'L',
563422=>'L',
564423=>'L',
565424=>'L',
566425=>'L',
567426=>'L',
568427=>'L',
569428=>'L',
570429=>'L',
571430=>'L',
572431=>'L',
573432=>'L',
574433=>'L',
575434=>'L',
576435=>'L',
577436=>'L',
578437=>'L',
579438=>'L',
580439=>'L',
581440=>'L',
582441=>'L',
583442=>'L',
584443=>'L',
585444=>'L',
586445=>'L',
587446=>'L',
588447=>'L',
589448=>'L',
590449=>'L',
591450=>'L',
592451=>'L',
593452=>'L',
594453=>'L',
595454=>'L',
596455=>'L',
597456=>'L',
598457=>'L',
599458=>'L',
600459=>'L',
601460=>'L',
602461=>'L',
603462=>'L',
604463=>'L',
605464=>'L',
606465=>'L',
607466=>'L',
608467=>'L',
609468=>'L',
610469=>'L',
611470=>'L',
612471=>'L',
613472=>'L',
614473=>'L',
615474=>'L',
616475=>'L',
617476=>'L',
618477=>'L',
619478=>'L',
620479=>'L',
621480=>'L',
622481=>'L',
623482=>'L',
624483=>'L',
625484=>'L',
626485=>'L',
627486=>'L',
628487=>'L',
629488=>'L',
630489=>'L',
631490=>'L',
632491=>'L',
633492=>'L',
634493=>'L',
635494=>'L',
636495=>'L',
637496=>'L',
638497=>'L',
639498=>'L',
640499=>'L',
641500=>'L',
642501=>'L',
643502=>'L',
644503=>'L',
645504=>'L',
646505=>'L',
647506=>'L',
648507=>'L',
649508=>'L',
650509=>'L',
651510=>'L',
652511=>'L',
653512=>'L',
654513=>'L',
655514=>'L',
656515=>'L',
657516=>'L',
658517=>'L',
659518=>'L',
660519=>'L',
661520=>'L',
662521=>'L',
663522=>'L',
664523=>'L',
665524=>'L',
666525=>'L',
667526=>'L',
668527=>'L',
669528=>'L',
670529=>'L',
671530=>'L',
672531=>'L',
673532=>'L',
674533=>'L',
675534=>'L',
676535=>'L',
677536=>'L',
678537=>'L',
679538=>'L',
680539=>'L',
681540=>'L',
682541=>'L',
683542=>'L',
684543=>'L',
685544=>'L',
686545=>'L',
687546=>'L',
688547=>'L',
689548=>'L',
690549=>'L',
691550=>'L',
692551=>'L',
693552=>'L',
694553=>'L',
695554=>'L',
696555=>'L',
697556=>'L',
698557=>'L',
699558=>'L',
700559=>'L',
701560=>'L',
702561=>'L',
703562=>'L',
704563=>'L',
705564=>'L',
706565=>'L',
707566=>'L',
708567=>'L',
709568=>'L',
710569=>'L',
711570=>'L',
712571=>'L',
713572=>'L',
714573=>'L',
715574=>'L',
716575=>'L',
717576=>'L',
718577=>'L',
719578=>'L',
720579=>'L',
721580=>'L',
722581=>'L',
723582=>'L',
724583=>'L',
725584=>'L',
726585=>'L',
727586=>'L',
728587=>'L',
729588=>'L',
730589=>'L',
731590=>'L',
732591=>'L',
733592=>'L',
734593=>'L',
735594=>'L',
736595=>'L',
737596=>'L',
738597=>'L',
739598=>'L',
740599=>'L',
741600=>'L',
742601=>'L',
743602=>'L',
744603=>'L',
745604=>'L',
746605=>'L',
747606=>'L',
748607=>'L',
749608=>'L',
750609=>'L',
751610=>'L',
752611=>'L',
753612=>'L',
754613=>'L',
755614=>'L',
756615=>'L',
757616=>'L',
758617=>'L',
759618=>'L',
760619=>'L',
761620=>'L',
762621=>'L',
763622=>'L',
764623=>'L',
765624=>'L',
766625=>'L',
767626=>'L',
768627=>'L',
769628=>'L',
770629=>'L',
771630=>'L',
772631=>'L',
773632=>'L',
774633=>'L',
775634=>'L',
776635=>'L',
777636=>'L',
778637=>'L',
779638=>'L',
780639=>'L',
781640=>'L',
782641=>'L',
783642=>'L',
784643=>'L',
785644=>'L',
786645=>'L',
787646=>'L',
788647=>'L',
789648=>'L',
790649=>'L',
791650=>'L',
792651=>'L',
793652=>'L',
794653=>'L',
795654=>'L',
796655=>'L',
797656=>'L',
798657=>'L',
799658=>'L',
800659=>'L',
801660=>'L',
802661=>'L',
803662=>'L',
804663=>'L',
805664=>'L',
806665=>'L',
807666=>'L',
808667=>'L',
809668=>'L',
810669=>'L',
811670=>'L',
812671=>'L',
813672=>'L',
814673=>'L',
815674=>'L',
816675=>'L',
817676=>'L',
818677=>'L',
819678=>'L',
820679=>'L',
821680=>'L',
822681=>'L',
823682=>'L',
824683=>'L',
825684=>'L',
826685=>'L',
827686=>'L',
828687=>'L',
829688=>'L',
830689=>'L',
831690=>'L',
832691=>'L',
833692=>'L',
834693=>'L',
835694=>'L',
836695=>'L',
837696=>'L',
838697=>'ON',
839698=>'ON',
840699=>'L',
841700=>'L',
842701=>'L',
843702=>'L',
844703=>'L',
845704=>'L',
846705=>'L',
847706=>'ON',
848707=>'ON',
849708=>'ON',
850709=>'ON',
851710=>'ON',
852711=>'ON',
853712=>'ON',
854713=>'ON',
855714=>'ON',
856715=>'ON',
857716=>'ON',
858717=>'ON',
859718=>'ON',
860719=>'ON',
861720=>'L',
862721=>'L',
863722=>'ON',
864723=>'ON',
865724=>'ON',
866725=>'ON',
867726=>'ON',
868727=>'ON',
869728=>'ON',
870729=>'ON',
871730=>'ON',
872731=>'ON',
873732=>'ON',
874733=>'ON',
875734=>'ON',
876735=>'ON',
877736=>'L',
878737=>'L',
879738=>'L',
880739=>'L',
881740=>'L',
882741=>'ON',
883742=>'ON',
884743=>'ON',
885744=>'ON',
886745=>'ON',
887746=>'ON',
888747=>'ON',
889748=>'ON',
890749=>'ON',
891750=>'L',
892751=>'ON',
893752=>'ON',
894753=>'ON',
895754=>'ON',
896755=>'ON',
897756=>'ON',
898757=>'ON',
899758=>'ON',
900759=>'ON',
901760=>'ON',
902761=>'ON',
903762=>'ON',
904763=>'ON',
905764=>'ON',
906765=>'ON',
907766=>'ON',
908767=>'ON',
909768=>'NSM',
910769=>'NSM',
911770=>'NSM',
912771=>'NSM',
913772=>'NSM',
914773=>'NSM',
915774=>'NSM',
916775=>'NSM',
917776=>'NSM',
918777=>'NSM',
919778=>'NSM',
920779=>'NSM',
921780=>'NSM',
922781=>'NSM',
923782=>'NSM',
924783=>'NSM',
925784=>'NSM',
926785=>'NSM',
927786=>'NSM',
928787=>'NSM',
929788=>'NSM',
930789=>'NSM',
931790=>'NSM',
932791=>'NSM',
933792=>'NSM',
934793=>'NSM',
935794=>'NSM',
936795=>'NSM',
937796=>'NSM',
938797=>'NSM',
939798=>'NSM',
940799=>'NSM',
941800=>'NSM',
942801=>'NSM',
943802=>'NSM',
944803=>'NSM',
945804=>'NSM',
946805=>'NSM',
947806=>'NSM',
948807=>'NSM',
949808=>'NSM',
950809=>'NSM',
951810=>'NSM',
952811=>'NSM',
953812=>'NSM',
954813=>'NSM',
955814=>'NSM',
956815=>'NSM',
957816=>'NSM',
958817=>'NSM',
959818=>'NSM',
960819=>'NSM',
961820=>'NSM',
962821=>'NSM',
963822=>'NSM',
964823=>'NSM',
965824=>'NSM',
966825=>'NSM',
967826=>'NSM',
968827=>'NSM',
969828=>'NSM',
970829=>'NSM',
971830=>'NSM',
972831=>'NSM',
973832=>'NSM',
974833=>'NSM',
975834=>'NSM',
976835=>'NSM',
977836=>'NSM',
978837=>'NSM',
979838=>'NSM',
980839=>'NSM',
981840=>'NSM',
982841=>'NSM',
983842=>'NSM',
984843=>'NSM',
985844=>'NSM',
986845=>'NSM',
987846=>'NSM',
988847=>'NSM',
989848=>'NSM',
990849=>'NSM',
991850=>'NSM',
992851=>'NSM',
993852=>'NSM',
994853=>'NSM',
995854=>'NSM',
996855=>'NSM',
997856=>'NSM',
998857=>'NSM',
999858=>'NSM',
1000859=>'NSM',
1001860=>'NSM',
1002861=>'NSM',
1003862=>'NSM',
1004863=>'NSM',
1005864=>'NSM',
1006865=>'NSM',
1007866=>'NSM',
1008867=>'NSM',
1009868=>'NSM',
1010869=>'NSM',
1011870=>'NSM',
1012871=>'NSM',
1013872=>'NSM',
1014873=>'NSM',
1015874=>'NSM',
1016875=>'NSM',
1017876=>'NSM',
1018877=>'NSM',
1019878=>'NSM',
1020879=>'NSM',
1021884=>'ON',
1022885=>'ON',
1023890=>'L',
1024891=>'L',
1025892=>'L',
1026893=>'L',
1027894=>'ON',
1028900=>'ON',
1029901=>'ON',
1030902=>'L',
1031903=>'ON',
1032904=>'L',
1033905=>'L',
1034906=>'L',
1035908=>'L',
1036910=>'L',
1037911=>'L',
1038912=>'L',
1039913=>'L',
1040914=>'L',
1041915=>'L',
1042916=>'L',
1043917=>'L',
1044918=>'L',
1045919=>'L',
1046920=>'L',
1047921=>'L',
1048922=>'L',
1049923=>'L',
1050924=>'L',
1051925=>'L',
1052926=>'L',
1053927=>'L',
1054928=>'L',
1055929=>'L',
1056931=>'L',
1057932=>'L',
1058933=>'L',
1059934=>'L',
1060935=>'L',
1061936=>'L',
1062937=>'L',
1063938=>'L',
1064939=>'L',
1065940=>'L',
1066941=>'L',
1067942=>'L',
1068943=>'L',
1069944=>'L',
1070945=>'L',
1071946=>'L',
1072947=>'L',
1073948=>'L',
1074949=>'L',
1075950=>'L',
1076951=>'L',
1077952=>'L',
1078953=>'L',
1079954=>'L',
1080955=>'L',
1081956=>'L',
1082957=>'L',
1083958=>'L',
1084959=>'L',
1085960=>'L',
1086961=>'L',
1087962=>'L',
1088963=>'L',
1089964=>'L',
1090965=>'L',
1091966=>'L',
1092967=>'L',
1093968=>'L',
1094969=>'L',
1095970=>'L',
1096971=>'L',
1097972=>'L',
1098973=>'L',
1099974=>'L',
1100976=>'L',
1101977=>'L',
1102978=>'L',
1103979=>'L',
1104980=>'L',
1105981=>'L',
1106982=>'L',
1107983=>'L',
1108984=>'L',
1109985=>'L',
1110986=>'L',
1111987=>'L',
1112988=>'L',
1113989=>'L',
1114990=>'L',
1115991=>'L',
1116992=>'L',
1117993=>'L',
1118994=>'L',
1119995=>'L',
1120996=>'L',
1121997=>'L',
1122998=>'L',
1123999=>'L',
11241000=>'L',
11251001=>'L',
11261002=>'L',
11271003=>'L',
11281004=>'L',
11291005=>'L',
11301006=>'L',
11311007=>'L',
11321008=>'L',
11331009=>'L',
11341010=>'L',
11351011=>'L',
11361012=>'L',
11371013=>'L',
11381014=>'ON',
11391015=>'L',
11401016=>'L',
11411017=>'L',
11421018=>'L',
11431019=>'L',
11441020=>'L',
11451021=>'L',
11461022=>'L',
11471023=>'L',
11481024=>'L',
11491025=>'L',
11501026=>'L',
11511027=>'L',
11521028=>'L',
11531029=>'L',
11541030=>'L',
11551031=>'L',
11561032=>'L',
11571033=>'L',
11581034=>'L',
11591035=>'L',
11601036=>'L',
11611037=>'L',
11621038=>'L',
11631039=>'L',
11641040=>'L',
11651041=>'L',
11661042=>'L',
11671043=>'L',
11681044=>'L',
11691045=>'L',
11701046=>'L',
11711047=>'L',
11721048=>'L',
11731049=>'L',
11741050=>'L',
11751051=>'L',
11761052=>'L',
11771053=>'L',
11781054=>'L',
11791055=>'L',
11801056=>'L',
11811057=>'L',
11821058=>'L',
11831059=>'L',
11841060=>'L',
11851061=>'L',
11861062=>'L',
11871063=>'L',
11881064=>'L',
11891065=>'L',
11901066=>'L',
11911067=>'L',
11921068=>'L',
11931069=>'L',
11941070=>'L',
11951071=>'L',
11961072=>'L',
11971073=>'L',
11981074=>'L',
11991075=>'L',
12001076=>'L',
12011077=>'L',
12021078=>'L',
12031079=>'L',
12041080=>'L',
12051081=>'L',
12061082=>'L',
12071083=>'L',
12081084=>'L',
12091085=>'L',
12101086=>'L',
12111087=>'L',
12121088=>'L',
12131089=>'L',
12141090=>'L',
12151091=>'L',
12161092=>'L',
12171093=>'L',
12181094=>'L',
12191095=>'L',
12201096=>'L',
12211097=>'L',
12221098=>'L',
12231099=>'L',
12241100=>'L',
12251101=>'L',
12261102=>'L',
12271103=>'L',
12281104=>'L',
12291105=>'L',
12301106=>'L',
12311107=>'L',
12321108=>'L',
12331109=>'L',
12341110=>'L',
12351111=>'L',
12361112=>'L',
12371113=>'L',
12381114=>'L',
12391115=>'L',
12401116=>'L',
12411117=>'L',
12421118=>'L',
12431119=>'L',
12441120=>'L',
12451121=>'L',
12461122=>'L',
12471123=>'L',
12481124=>'L',
12491125=>'L',
12501126=>'L',
12511127=>'L',
12521128=>'L',
12531129=>'L',
12541130=>'L',
12551131=>'L',
12561132=>'L',
12571133=>'L',
12581134=>'L',
12591135=>'L',
12601136=>'L',
12611137=>'L',
12621138=>'L',
12631139=>'L',
12641140=>'L',
12651141=>'L',
12661142=>'L',
12671143=>'L',
12681144=>'L',
12691145=>'L',
12701146=>'L',
12711147=>'L',
12721148=>'L',
12731149=>'L',
12741150=>'L',
12751151=>'L',
12761152=>'L',
12771153=>'L',
12781154=>'L',
12791155=>'NSM',
12801156=>'NSM',
12811157=>'NSM',
12821158=>'NSM',
12831160=>'NSM',
12841161=>'NSM',
12851162=>'L',
12861163=>'L',
12871164=>'L',
12881165=>'L',
12891166=>'L',
12901167=>'L',
12911168=>'L',
12921169=>'L',
12931170=>'L',
12941171=>'L',
12951172=>'L',
12961173=>'L',
12971174=>'L',
12981175=>'L',
12991176=>'L',
13001177=>'L',
13011178=>'L',
13021179=>'L',
13031180=>'L',
13041181=>'L',
13051182=>'L',
13061183=>'L',
13071184=>'L',
13081185=>'L',
13091186=>'L',
13101187=>'L',
13111188=>'L',
13121189=>'L',
13131190=>'L',
13141191=>'L',
13151192=>'L',
13161193=>'L',
13171194=>'L',
13181195=>'L',
13191196=>'L',
13201197=>'L',
13211198=>'L',
13221199=>'L',
13231200=>'L',
13241201=>'L',
13251202=>'L',
13261203=>'L',
13271204=>'L',
13281205=>'L',
13291206=>'L',
13301207=>'L',
13311208=>'L',
13321209=>'L',
13331210=>'L',
13341211=>'L',
13351212=>'L',
13361213=>'L',
13371214=>'L',
13381215=>'L',
13391216=>'L',
13401217=>'L',
13411218=>'L',
13421219=>'L',
13431220=>'L',
13441221=>'L',
13451222=>'L',
13461223=>'L',
13471224=>'L',
13481225=>'L',
13491226=>'L',
13501227=>'L',
13511228=>'L',
13521229=>'L',
13531230=>'L',
13541231=>'L',
13551232=>'L',
13561233=>'L',
13571234=>'L',
13581235=>'L',
13591236=>'L',
13601237=>'L',
13611238=>'L',
13621239=>'L',
13631240=>'L',
13641241=>'L',
13651242=>'L',
13661243=>'L',
13671244=>'L',
13681245=>'L',
13691246=>'L',
13701247=>'L',
13711248=>'L',
13721249=>'L',
13731250=>'L',
13741251=>'L',
13751252=>'L',
13761253=>'L',
13771254=>'L',
13781255=>'L',
13791256=>'L',
13801257=>'L',
13811258=>'L',
13821259=>'L',
13831260=>'L',
13841261=>'L',
13851262=>'L',
13861263=>'L',
13871264=>'L',
13881265=>'L',
13891266=>'L',
13901267=>'L',
13911268=>'L',
13921269=>'L',
13931270=>'L',
13941271=>'L',
13951272=>'L',
13961273=>'L',
13971274=>'L',
13981275=>'L',
13991276=>'L',
14001277=>'L',
14011278=>'L',
14021279=>'L',
14031280=>'L',
14041281=>'L',
14051282=>'L',
14061283=>'L',
14071284=>'L',
14081285=>'L',
14091286=>'L',
14101287=>'L',
14111288=>'L',
14121289=>'L',
14131290=>'L',
14141291=>'L',
14151292=>'L',
14161293=>'L',
14171294=>'L',
14181295=>'L',
14191296=>'L',
14201297=>'L',
14211298=>'L',
14221299=>'L',
14231329=>'L',
14241330=>'L',
14251331=>'L',
14261332=>'L',
14271333=>'L',
14281334=>'L',
14291335=>'L',
14301336=>'L',
14311337=>'L',
14321338=>'L',
14331339=>'L',
14341340=>'L',
14351341=>'L',
14361342=>'L',
14371343=>'L',
14381344=>'L',
14391345=>'L',
14401346=>'L',
14411347=>'L',
14421348=>'L',
14431349=>'L',
14441350=>'L',
14451351=>'L',
14461352=>'L',
14471353=>'L',
14481354=>'L',
14491355=>'L',
14501356=>'L',
14511357=>'L',
14521358=>'L',
14531359=>'L',
14541360=>'L',
14551361=>'L',
14561362=>'L',
14571363=>'L',
14581364=>'L',
14591365=>'L',
14601366=>'L',
14611369=>'L',
14621370=>'L',
14631371=>'L',
14641372=>'L',
14651373=>'L',
14661374=>'L',
14671375=>'L',
14681377=>'L',
14691378=>'L',
14701379=>'L',
14711380=>'L',
14721381=>'L',
14731382=>'L',
14741383=>'L',
14751384=>'L',
14761385=>'L',
14771386=>'L',
14781387=>'L',
14791388=>'L',
14801389=>'L',
14811390=>'L',
14821391=>'L',
14831392=>'L',
14841393=>'L',
14851394=>'L',
14861395=>'L',
14871396=>'L',
14881397=>'L',
14891398=>'L',
14901399=>'L',
14911400=>'L',
14921401=>'L',
14931402=>'L',
14941403=>'L',
14951404=>'L',
14961405=>'L',
14971406=>'L',
14981407=>'L',
14991408=>'L',
15001409=>'L',
15011410=>'L',
15021411=>'L',
15031412=>'L',
15041413=>'L',
15051414=>'L',
15061415=>'L',
15071417=>'L',
15081418=>'ON',
15091425=>'NSM',
15101426=>'NSM',
15111427=>'NSM',
15121428=>'NSM',
15131429=>'NSM',
15141430=>'NSM',
15151431=>'NSM',
15161432=>'NSM',
15171433=>'NSM',
15181434=>'NSM',
15191435=>'NSM',
15201436=>'NSM',
15211437=>'NSM',
15221438=>'NSM',
15231439=>'NSM',
15241440=>'NSM',
15251441=>'NSM',
15261442=>'NSM',
15271443=>'NSM',
15281444=>'NSM',
15291445=>'NSM',
15301446=>'NSM',
15311447=>'NSM',
15321448=>'NSM',
15331449=>'NSM',
15341450=>'NSM',
15351451=>'NSM',
15361452=>'NSM',
15371453=>'NSM',
15381454=>'NSM',
15391455=>'NSM',
15401456=>'NSM',
15411457=>'NSM',
15421458=>'NSM',
15431459=>'NSM',
15441460=>'NSM',
15451461=>'NSM',
15461462=>'NSM',
15471463=>'NSM',
15481464=>'NSM',
15491465=>'NSM',
15501466=>'NSM',
15511467=>'NSM',
15521468=>'NSM',
15531469=>'NSM',
15541470=>'R',
15551471=>'NSM',
15561472=>'R',
15571473=>'NSM',
15581474=>'NSM',
15591475=>'R',
15601476=>'NSM',
15611477=>'NSM',
15621478=>'R',
15631479=>'NSM',
15641488=>'R',
15651489=>'R',
15661490=>'R',
15671491=>'R',
15681492=>'R',
15691493=>'R',
15701494=>'R',
15711495=>'R',
15721496=>'R',
15731497=>'R',
15741498=>'R',
15751499=>'R',
15761500=>'R',
15771501=>'R',
15781502=>'R',
15791503=>'R',
15801504=>'R',
15811505=>'R',
15821506=>'R',
15831507=>'R',
15841508=>'R',
15851509=>'R',
15861510=>'R',
15871511=>'R',
15881512=>'R',
15891513=>'R',
15901514=>'R',
15911520=>'R',
15921521=>'R',
15931522=>'R',
15941523=>'R',
15951524=>'R',
15961536=>'AL',
15971537=>'AL',
15981538=>'AL',
15991539=>'AL',
16001547=>'AL',
16011548=>'CS',
16021549=>'AL',
16031550=>'ON',
16041551=>'ON',
16051552=>'NSM',
16061553=>'NSM',
16071554=>'NSM',
16081555=>'NSM',
16091556=>'NSM',
16101557=>'NSM',
16111563=>'AL',
16121566=>'AL',
16131567=>'AL',
16141569=>'AL',
16151570=>'AL',
16161571=>'AL',
16171572=>'AL',
16181573=>'AL',
16191574=>'AL',
16201575=>'AL',
16211576=>'AL',
16221577=>'AL',
16231578=>'AL',
16241579=>'AL',
16251580=>'AL',
16261581=>'AL',
16271582=>'AL',
16281583=>'AL',
16291584=>'AL',
16301585=>'AL',
16311586=>'AL',
16321587=>'AL',
16331588=>'AL',
16341589=>'AL',
16351590=>'AL',
16361591=>'AL',
16371592=>'AL',
16381593=>'AL',
16391594=>'AL',
16401600=>'AL',
16411601=>'AL',
16421602=>'AL',
16431603=>'AL',
16441604=>'AL',
16451605=>'AL',
16461606=>'AL',
16471607=>'AL',
16481608=>'AL',
16491609=>'AL',
16501610=>'AL',
16511611=>'NSM',
16521612=>'NSM',
16531613=>'NSM',
16541614=>'NSM',
16551615=>'NSM',
16561616=>'NSM',
16571617=>'NSM',
16581618=>'NSM',
16591619=>'NSM',
16601620=>'NSM',
16611621=>'NSM',
16621622=>'NSM',
16631623=>'NSM',
16641624=>'NSM',
16651625=>'NSM',
16661626=>'NSM',
16671627=>'NSM',
16681628=>'NSM',
16691629=>'NSM',
16701630=>'NSM',
16711632=>'AN',
16721633=>'AN',
16731634=>'AN',
16741635=>'AN',
16751636=>'AN',
16761637=>'AN',
16771638=>'AN',
16781639=>'AN',
16791640=>'AN',
16801641=>'AN',
16811642=>'ET',
16821643=>'AN',
16831644=>'AN',
16841645=>'AL',
16851646=>'AL',
16861647=>'AL',
16871648=>'NSM',
16881649=>'AL',
16891650=>'AL',
16901651=>'AL',
16911652=>'AL',
16921653=>'AL',
16931654=>'AL',
16941655=>'AL',
16951656=>'AL',
16961657=>'AL',
16971658=>'AL',
16981659=>'AL',
16991660=>'AL',
17001661=>'AL',
17011662=>'AL',
17021663=>'AL',
17031664=>'AL',
17041665=>'AL',
17051666=>'AL',
17061667=>'AL',
17071668=>'AL',
17081669=>'AL',
17091670=>'AL',
17101671=>'AL',
17111672=>'AL',
17121673=>'AL',
17131674=>'AL',
17141675=>'AL',
17151676=>'AL',
17161677=>'AL',
17171678=>'AL',
17181679=>'AL',
17191680=>'AL',
17201681=>'AL',
17211682=>'AL',
17221683=>'AL',
17231684=>'AL',
17241685=>'AL',
17251686=>'AL',
17261687=>'AL',
17271688=>'AL',
17281689=>'AL',
17291690=>'AL',
17301691=>'AL',
17311692=>'AL',
17321693=>'AL',
17331694=>'AL',
17341695=>'AL',
17351696=>'AL',
17361697=>'AL',
17371698=>'AL',
17381699=>'AL',
17391700=>'AL',
17401701=>'AL',
17411702=>'AL',
17421703=>'AL',
17431704=>'AL',
17441705=>'AL',
17451706=>'AL',
17461707=>'AL',
17471708=>'AL',
17481709=>'AL',
17491710=>'AL',
17501711=>'AL',
17511712=>'AL',
17521713=>'AL',
17531714=>'AL',
17541715=>'AL',
17551716=>'AL',
17561717=>'AL',
17571718=>'AL',
17581719=>'AL',
17591720=>'AL',
17601721=>'AL',
17611722=>'AL',
17621723=>'AL',
17631724=>'AL',
17641725=>'AL',
17651726=>'AL',
17661727=>'AL',
17671728=>'AL',
17681729=>'AL',
17691730=>'AL',
17701731=>'AL',
17711732=>'AL',
17721733=>'AL',
17731734=>'AL',
17741735=>'AL',
17751736=>'AL',
17761737=>'AL',
17771738=>'AL',
17781739=>'AL',
17791740=>'AL',
17801741=>'AL',
17811742=>'AL',
17821743=>'AL',
17831744=>'AL',
17841745=>'AL',
17851746=>'AL',
17861747=>'AL',
17871748=>'AL',
17881749=>'AL',
17891750=>'NSM',
17901751=>'NSM',
17911752=>'NSM',
17921753=>'NSM',
17931754=>'NSM',
17941755=>'NSM',
17951756=>'NSM',
17961757=>'AL',
17971758=>'NSM',
17981759=>'NSM',
17991760=>'NSM',
18001761=>'NSM',
18011762=>'NSM',
18021763=>'NSM',
18031764=>'NSM',
18041765=>'AL',
18051766=>'AL',
18061767=>'NSM',
18071768=>'NSM',
18081769=>'ON',
18091770=>'NSM',
18101771=>'NSM',
18111772=>'NSM',
18121773=>'NSM',
18131774=>'AL',
18141775=>'AL',
18151776=>'EN',
18161777=>'EN',
18171778=>'EN',
18181779=>'EN',
18191780=>'EN',
18201781=>'EN',
18211782=>'EN',
18221783=>'EN',
18231784=>'EN',
18241785=>'EN',
18251786=>'AL',
18261787=>'AL',
18271788=>'AL',
18281789=>'AL',
18291790=>'AL',
18301791=>'AL',
18311792=>'AL',
18321793=>'AL',
18331794=>'AL',
18341795=>'AL',
18351796=>'AL',
18361797=>'AL',
18371798=>'AL',
18381799=>'AL',
18391800=>'AL',
18401801=>'AL',
18411802=>'AL',
18421803=>'AL',
18431804=>'AL',
18441805=>'AL',
18451807=>'BN',
18461808=>'AL',
18471809=>'NSM',
18481810=>'AL',
18491811=>'AL',
18501812=>'AL',
18511813=>'AL',
18521814=>'AL',
18531815=>'AL',
18541816=>'AL',
18551817=>'AL',
18561818=>'AL',
18571819=>'AL',
18581820=>'AL',
18591821=>'AL',
18601822=>'AL',
18611823=>'AL',
18621824=>'AL',
18631825=>'AL',
18641826=>'AL',
18651827=>'AL',
18661828=>'AL',
18671829=>'AL',
18681830=>'AL',
18691831=>'AL',
18701832=>'AL',
18711833=>'AL',
18721834=>'AL',
18731835=>'AL',
18741836=>'AL',
18751837=>'AL',
18761838=>'AL',
18771839=>'AL',
18781840=>'NSM',
18791841=>'NSM',
18801842=>'NSM',
18811843=>'NSM',
18821844=>'NSM',
18831845=>'NSM',
18841846=>'NSM',
18851847=>'NSM',
18861848=>'NSM',
18871849=>'NSM',
18881850=>'NSM',
18891851=>'NSM',
18901852=>'NSM',
18911853=>'NSM',
18921854=>'NSM',
18931855=>'NSM',
18941856=>'NSM',
18951857=>'NSM',
18961858=>'NSM',
18971859=>'NSM',
18981860=>'NSM',
18991861=>'NSM',
19001862=>'NSM',
19011863=>'NSM',
19021864=>'NSM',
19031865=>'NSM',
19041866=>'NSM',
19051869=>'AL',
19061870=>'AL',
19071871=>'AL',
19081872=>'AL',
19091873=>'AL',
19101874=>'AL',
19111875=>'AL',
19121876=>'AL',
19131877=>'AL',
19141878=>'AL',
19151879=>'AL',
19161880=>'AL',
19171881=>'AL',
19181882=>'AL',
19191883=>'AL',
19201884=>'AL',
19211885=>'AL',
19221886=>'AL',
19231887=>'AL',
19241888=>'AL',
19251889=>'AL',
19261890=>'AL',
19271891=>'AL',
19281892=>'AL',
19291893=>'AL',
19301894=>'AL',
19311895=>'AL',
19321896=>'AL',
19331897=>'AL',
19341898=>'AL',
19351899=>'AL',
19361900=>'AL',
19371901=>'AL',
19381920=>'AL',
19391921=>'AL',
19401922=>'AL',
19411923=>'AL',
19421924=>'AL',
19431925=>'AL',
19441926=>'AL',
19451927=>'AL',
19461928=>'AL',
19471929=>'AL',
19481930=>'AL',
19491931=>'AL',
19501932=>'AL',
19511933=>'AL',
19521934=>'AL',
19531935=>'AL',
19541936=>'AL',
19551937=>'AL',
19561938=>'AL',
19571939=>'AL',
19581940=>'AL',
19591941=>'AL',
19601942=>'AL',
19611943=>'AL',
19621944=>'AL',
19631945=>'AL',
19641946=>'AL',
19651947=>'AL',
19661948=>'AL',
19671949=>'AL',
19681950=>'AL',
19691951=>'AL',
19701952=>'AL',
19711953=>'AL',
19721954=>'AL',
19731955=>'AL',
19741956=>'AL',
19751957=>'AL',
19761958=>'NSM',
19771959=>'NSM',
19781960=>'NSM',
19791961=>'NSM',
19801962=>'NSM',
19811963=>'NSM',
19821964=>'NSM',
19831965=>'NSM',
19841966=>'NSM',
19851967=>'NSM',
19861968=>'NSM',
19871969=>'AL',
19881984=>'R',
19891985=>'R',
19901986=>'R',
19911987=>'R',
19921988=>'R',
19931989=>'R',
19941990=>'R',
19951991=>'R',
19961992=>'R',
19971993=>'R',
19981994=>'R',
19991995=>'R',
20001996=>'R',
20011997=>'R',
20021998=>'R',
20031999=>'R',
20042000=>'R',
20052001=>'R',
20062002=>'R',
20072003=>'R',
20082004=>'R',
20092005=>'R',
20102006=>'R',
20112007=>'R',
20122008=>'R',
20132009=>'R',
20142010=>'R',
20152011=>'R',
20162012=>'R',
20172013=>'R',
20182014=>'R',
20192015=>'R',
20202016=>'R',
20212017=>'R',
20222018=>'R',
20232019=>'R',
20242020=>'R',
20252021=>'R',
20262022=>'R',
20272023=>'R',
20282024=>'R',
20292025=>'R',
20302026=>'R',
20312027=>'NSM',
20322028=>'NSM',
20332029=>'NSM',
20342030=>'NSM',
20352031=>'NSM',
20362032=>'NSM',
20372033=>'NSM',
20382034=>'NSM',
20392035=>'NSM',
20402036=>'R',
20412037=>'R',
20422038=>'ON',
20432039=>'ON',
20442040=>'ON',
20452041=>'ON',
20462042=>'R',
20472305=>'NSM',
20482306=>'NSM',
20492307=>'L',
20502308=>'L',
20512309=>'L',
20522310=>'L',
20532311=>'L',
20542312=>'L',
20552313=>'L',
20562314=>'L',
20572315=>'L',
20582316=>'L',
20592317=>'L',
20602318=>'L',
20612319=>'L',
20622320=>'L',
20632321=>'L',
20642322=>'L',
20652323=>'L',
20662324=>'L',
20672325=>'L',
20682326=>'L',
20692327=>'L',
20702328=>'L',
20712329=>'L',
20722330=>'L',
20732331=>'L',
20742332=>'L',
20752333=>'L',
20762334=>'L',
20772335=>'L',
20782336=>'L',
20792337=>'L',
20802338=>'L',
20812339=>'L',
20822340=>'L',
20832341=>'L',
20842342=>'L',
20852343=>'L',
20862344=>'L',
20872345=>'L',
20882346=>'L',
20892347=>'L',
20902348=>'L',
20912349=>'L',
20922350=>'L',
20932351=>'L',
20942352=>'L',
20952353=>'L',
20962354=>'L',
20972355=>'L',
20982356=>'L',
20992357=>'L',
21002358=>'L',
21012359=>'L',
21022360=>'L',
21032361=>'L',
21042364=>'NSM',
21052365=>'L',
21062366=>'L',
21072367=>'L',
21082368=>'L',
21092369=>'NSM',
21102370=>'NSM',
21112371=>'NSM',
21122372=>'NSM',
21132373=>'NSM',
21142374=>'NSM',
21152375=>'NSM',
21162376=>'NSM',
21172377=>'L',
21182378=>'L',
21192379=>'L',
21202380=>'L',
21212381=>'NSM',
21222384=>'L',
21232385=>'NSM',
21242386=>'NSM',
21252387=>'NSM',
21262388=>'NSM',
21272392=>'L',
21282393=>'L',
21292394=>'L',
21302395=>'L',
21312396=>'L',
21322397=>'L',
21332398=>'L',
21342399=>'L',
21352400=>'L',
21362401=>'L',
21372402=>'NSM',
21382403=>'NSM',
21392404=>'L',
21402405=>'L',
21412406=>'L',
21422407=>'L',
21432408=>'L',
21442409=>'L',
21452410=>'L',
21462411=>'L',
21472412=>'L',
21482413=>'L',
21492414=>'L',
21502415=>'L',
21512416=>'L',
21522427=>'L',
21532428=>'L',
21542429=>'L',
21552430=>'L',
21562431=>'L',
21572433=>'NSM',
21582434=>'L',
21592435=>'L',
21602437=>'L',
21612438=>'L',
21622439=>'L',
21632440=>'L',
21642441=>'L',
21652442=>'L',
21662443=>'L',
21672444=>'L',
21682447=>'L',
21692448=>'L',
21702451=>'L',
21712452=>'L',
21722453=>'L',
21732454=>'L',
21742455=>'L',
21752456=>'L',
21762457=>'L',
21772458=>'L',
21782459=>'L',
21792460=>'L',
21802461=>'L',
21812462=>'L',
21822463=>'L',
21832464=>'L',
21842465=>'L',
21852466=>'L',
21862467=>'L',
21872468=>'L',
21882469=>'L',
21892470=>'L',
21902471=>'L',
21912472=>'L',
21922474=>'L',
21932475=>'L',
21942476=>'L',
21952477=>'L',
21962478=>'L',
21972479=>'L',
21982480=>'L',
21992482=>'L',
22002486=>'L',
22012487=>'L',
22022488=>'L',
22032489=>'L',
22042492=>'NSM',
22052493=>'L',
22062494=>'L',
22072495=>'L',
22082496=>'L',
22092497=>'NSM',
22102498=>'NSM',
22112499=>'NSM',
22122500=>'NSM',
22132503=>'L',
22142504=>'L',
22152507=>'L',
22162508=>'L',
22172509=>'NSM',
22182510=>'L',
22192519=>'L',
22202524=>'L',
22212525=>'L',
22222527=>'L',
22232528=>'L',
22242529=>'L',
22252530=>'NSM',
22262531=>'NSM',
22272534=>'L',
22282535=>'L',
22292536=>'L',
22302537=>'L',
22312538=>'L',
22322539=>'L',
22332540=>'L',
22342541=>'L',
22352542=>'L',
22362543=>'L',
22372544=>'L',
22382545=>'L',
22392546=>'ET',
22402547=>'ET',
22412548=>'L',
22422549=>'L',
22432550=>'L',
22442551=>'L',
22452552=>'L',
22462553=>'L',
22472554=>'L',
22482561=>'NSM',
22492562=>'NSM',
22502563=>'L',
22512565=>'L',
22522566=>'L',
22532567=>'L',
22542568=>'L',
22552569=>'L',
22562570=>'L',
22572575=>'L',
22582576=>'L',
22592579=>'L',
22602580=>'L',
22612581=>'L',
22622582=>'L',
22632583=>'L',
22642584=>'L',
22652585=>'L',
22662586=>'L',
22672587=>'L',
22682588=>'L',
22692589=>'L',
22702590=>'L',
22712591=>'L',
22722592=>'L',
22732593=>'L',
22742594=>'L',
22752595=>'L',
22762596=>'L',
22772597=>'L',
22782598=>'L',
22792599=>'L',
22802600=>'L',
22812602=>'L',
22822603=>'L',
22832604=>'L',
22842605=>'L',
22852606=>'L',
22862607=>'L',
22872608=>'L',
22882610=>'L',
22892611=>'L',
22902613=>'L',
22912614=>'L',
22922616=>'L',
22932617=>'L',
22942620=>'NSM',
22952622=>'L',
22962623=>'L',
22972624=>'L',
22982625=>'NSM',
22992626=>'NSM',
23002631=>'NSM',
23012632=>'NSM',
23022635=>'NSM',
23032636=>'NSM',
23042637=>'NSM',
23052649=>'L',
23062650=>'L',
23072651=>'L',
23082652=>'L',
23092654=>'L',
23102662=>'L',
23112663=>'L',
23122664=>'L',
23132665=>'L',
23142666=>'L',
23152667=>'L',
23162668=>'L',
23172669=>'L',
23182670=>'L',
23192671=>'L',
23202672=>'NSM',
23212673=>'NSM',
23222674=>'L',
23232675=>'L',
23242676=>'L',
23252689=>'NSM',
23262690=>'NSM',
23272691=>'L',
23282693=>'L',
23292694=>'L',
23302695=>'L',
23312696=>'L',
23322697=>'L',
23332698=>'L',
23342699=>'L',
23352700=>'L',
23362701=>'L',
23372703=>'L',
23382704=>'L',
23392705=>'L',
23402707=>'L',
23412708=>'L',
23422709=>'L',
23432710=>'L',
23442711=>'L',
23452712=>'L',
23462713=>'L',
23472714=>'L',
23482715=>'L',
23492716=>'L',
23502717=>'L',
23512718=>'L',
23522719=>'L',
23532720=>'L',
23542721=>'L',
23552722=>'L',
23562723=>'L',
23572724=>'L',
23582725=>'L',
23592726=>'L',
23602727=>'L',
23612728=>'L',
23622730=>'L',
23632731=>'L',
23642732=>'L',
23652733=>'L',
23662734=>'L',
23672735=>'L',
23682736=>'L',
23692738=>'L',
23702739=>'L',
23712741=>'L',
23722742=>'L',
23732743=>'L',
23742744=>'L',
23752745=>'L',
23762748=>'NSM',
23772749=>'L',
23782750=>'L',
23792751=>'L',
23802752=>'L',
23812753=>'NSM',
23822754=>'NSM',
23832755=>'NSM',
23842756=>'NSM',
23852757=>'NSM',
23862759=>'NSM',
23872760=>'NSM',
23882761=>'L',
23892763=>'L',
23902764=>'L',
23912765=>'NSM',
23922768=>'L',
23932784=>'L',
23942785=>'L',
23952786=>'NSM',
23962787=>'NSM',
23972790=>'L',
23982791=>'L',
23992792=>'L',
24002793=>'L',
24012794=>'L',
24022795=>'L',
24032796=>'L',
24042797=>'L',
24052798=>'L',
24062799=>'L',
24072801=>'ET',
24082817=>'NSM',
24092818=>'L',
24102819=>'L',
24112821=>'L',
24122822=>'L',
24132823=>'L',
24142824=>'L',
24152825=>'L',
24162826=>'L',
24172827=>'L',
24182828=>'L',
24192831=>'L',
24202832=>'L',
24212835=>'L',
24222836=>'L',
24232837=>'L',
24242838=>'L',
24252839=>'L',
24262840=>'L',
24272841=>'L',
24282842=>'L',
24292843=>'L',
24302844=>'L',
24312845=>'L',
24322846=>'L',
24332847=>'L',
24342848=>'L',
24352849=>'L',
24362850=>'L',
24372851=>'L',
24382852=>'L',
24392853=>'L',
24402854=>'L',
24412855=>'L',
24422856=>'L',
24432858=>'L',
24442859=>'L',
24452860=>'L',
24462861=>'L',
24472862=>'L',
24482863=>'L',
24492864=>'L',
24502866=>'L',
24512867=>'L',
24522869=>'L',
24532870=>'L',
24542871=>'L',
24552872=>'L',
24562873=>'L',
24572876=>'NSM',
24582877=>'L',
24592878=>'L',
24602879=>'NSM',
24612880=>'L',
24622881=>'NSM',
24632882=>'NSM',
24642883=>'NSM',
24652887=>'L',
24662888=>'L',
24672891=>'L',
24682892=>'L',
24692893=>'NSM',
24702902=>'NSM',
24712903=>'L',
24722908=>'L',
24732909=>'L',
24742911=>'L',
24752912=>'L',
24762913=>'L',
24772918=>'L',
24782919=>'L',
24792920=>'L',
24802921=>'L',
24812922=>'L',
24822923=>'L',
24832924=>'L',
24842925=>'L',
24852926=>'L',
24862927=>'L',
24872928=>'L',
24882929=>'L',
24892946=>'NSM',
24902947=>'L',
24912949=>'L',
24922950=>'L',
24932951=>'L',
24942952=>'L',
24952953=>'L',
24962954=>'L',
24972958=>'L',
24982959=>'L',
24992960=>'L',
25002962=>'L',
25012963=>'L',
25022964=>'L',
25032965=>'L',
25042969=>'L',
25052970=>'L',
25062972=>'L',
25072974=>'L',
25082975=>'L',
25092979=>'L',
25102980=>'L',
25112984=>'L',
25122985=>'L',
25132986=>'L',
25142990=>'L',
25152991=>'L',
25162992=>'L',
25172993=>'L',
25182994=>'L',
25192995=>'L',
25202996=>'L',
25212997=>'L',
25222998=>'L',
25232999=>'L',
25243000=>'L',
25253001=>'L',
25263006=>'L',
25273007=>'L',
25283008=>'NSM',
25293009=>'L',
25303010=>'L',
25313014=>'L',
25323015=>'L',
25333016=>'L',
25343018=>'L',
25353019=>'L',
25363020=>'L',
25373021=>'NSM',
25383031=>'L',
25393046=>'L',
25403047=>'L',
25413048=>'L',
25423049=>'L',
25433050=>'L',
25443051=>'L',
25453052=>'L',
25463053=>'L',
25473054=>'L',
25483055=>'L',
25493056=>'L',
25503057=>'L',
25513058=>'L',
25523059=>'ON',
25533060=>'ON',
25543061=>'ON',
25553062=>'ON',
25563063=>'ON',
25573064=>'ON',
25583065=>'ET',
25593066=>'ON',
25603073=>'L',
25613074=>'L',
25623075=>'L',
25633077=>'L',
25643078=>'L',
25653079=>'L',
25663080=>'L',
25673081=>'L',
25683082=>'L',
25693083=>'L',
25703084=>'L',
25713086=>'L',
25723087=>'L',
25733088=>'L',
25743090=>'L',
25753091=>'L',
25763092=>'L',
25773093=>'L',
25783094=>'L',
25793095=>'L',
25803096=>'L',
25813097=>'L',
25823098=>'L',
25833099=>'L',
25843100=>'L',
25853101=>'L',
25863102=>'L',
25873103=>'L',
25883104=>'L',
25893105=>'L',
25903106=>'L',
25913107=>'L',
25923108=>'L',
25933109=>'L',
25943110=>'L',
25953111=>'L',
25963112=>'L',
25973114=>'L',
25983115=>'L',
25993116=>'L',
26003117=>'L',
26013118=>'L',
26023119=>'L',
26033120=>'L',
26043121=>'L',
26053122=>'L',
26063123=>'L',
26073125=>'L',
26083126=>'L',
26093127=>'L',
26103128=>'L',
26113129=>'L',
26123134=>'NSM',
26133135=>'NSM',
26143136=>'NSM',
26153137=>'L',
26163138=>'L',
26173139=>'L',
26183140=>'L',
26193142=>'NSM',
26203143=>'NSM',
26213144=>'NSM',
26223146=>'NSM',
26233147=>'NSM',
26243148=>'NSM',
26253149=>'NSM',
26263157=>'NSM',
26273158=>'NSM',
26283168=>'L',
26293169=>'L',
26303174=>'L',
26313175=>'L',
26323176=>'L',
26333177=>'L',
26343178=>'L',
26353179=>'L',
26363180=>'L',
26373181=>'L',
26383182=>'L',
26393183=>'L',
26403202=>'L',
26413203=>'L',
26423205=>'L',
26433206=>'L',
26443207=>'L',
26453208=>'L',
26463209=>'L',
26473210=>'L',
26483211=>'L',
26493212=>'L',
26503214=>'L',
26513215=>'L',
26523216=>'L',
26533218=>'L',
26543219=>'L',
26553220=>'L',
26563221=>'L',
26573222=>'L',
26583223=>'L',
26593224=>'L',
26603225=>'L',
26613226=>'L',
26623227=>'L',
26633228=>'L',
26643229=>'L',
26653230=>'L',
26663231=>'L',
26673232=>'L',
26683233=>'L',
26693234=>'L',
26703235=>'L',
26713236=>'L',
26723237=>'L',
26733238=>'L',
26743239=>'L',
26753240=>'L',
26763242=>'L',
26773243=>'L',
26783244=>'L',
26793245=>'L',
26803246=>'L',
26813247=>'L',
26823248=>'L',
26833249=>'L',
26843250=>'L',
26853251=>'L',
26863253=>'L',
26873254=>'L',
26883255=>'L',
26893256=>'L',
26903257=>'L',
26913260=>'NSM',
26923261=>'L',
26933262=>'L',
26943263=>'L',
26953264=>'L',
26963265=>'L',
26973266=>'L',
26983267=>'L',
26993268=>'L',
27003270=>'L',
27013271=>'L',
27023272=>'L',
27033274=>'L',
27043275=>'L',
27053276=>'NSM',
27063277=>'NSM',
27073285=>'L',
27083286=>'L',
27093294=>'L',
27103296=>'L',
27113297=>'L',
27123298=>'NSM',
27133299=>'NSM',
27143302=>'L',
27153303=>'L',
27163304=>'L',
27173305=>'L',
27183306=>'L',
27193307=>'L',
27203308=>'L',
27213309=>'L',
27223310=>'L',
27233311=>'L',
27243313=>'ON',
27253314=>'ON',
27263330=>'L',
27273331=>'L',
27283333=>'L',
27293334=>'L',
27303335=>'L',
27313336=>'L',
27323337=>'L',
27333338=>'L',
27343339=>'L',
27353340=>'L',
27363342=>'L',
27373343=>'L',
27383344=>'L',
27393346=>'L',
27403347=>'L',
27413348=>'L',
27423349=>'L',
27433350=>'L',
27443351=>'L',
27453352=>'L',
27463353=>'L',
27473354=>'L',
27483355=>'L',
27493356=>'L',
27503357=>'L',
27513358=>'L',
27523359=>'L',
27533360=>'L',
27543361=>'L',
27553362=>'L',
27563363=>'L',
27573364=>'L',
27583365=>'L',
27593366=>'L',
27603367=>'L',
27613368=>'L',
27623370=>'L',
27633371=>'L',
27643372=>'L',
27653373=>'L',
27663374=>'L',
27673375=>'L',
27683376=>'L',
27693377=>'L',
27703378=>'L',
27713379=>'L',
27723380=>'L',
27733381=>'L',
27743382=>'L',
27753383=>'L',
27763384=>'L',
27773385=>'L',
27783390=>'L',
27793391=>'L',
27803392=>'L',
27813393=>'NSM',
27823394=>'NSM',
27833395=>'NSM',
27843398=>'L',
27853399=>'L',
27863400=>'L',
27873402=>'L',
27883403=>'L',
27893404=>'L',
27903405=>'NSM',
27913415=>'L',
27923424=>'L',
27933425=>'L',
27943430=>'L',
27953431=>'L',
27963432=>'L',
27973433=>'L',
27983434=>'L',
27993435=>'L',
28003436=>'L',
28013437=>'L',
28023438=>'L',
28033439=>'L',
28043458=>'L',
28053459=>'L',
28063461=>'L',
28073462=>'L',
28083463=>'L',
28093464=>'L',
28103465=>'L',
28113466=>'L',
28123467=>'L',
28133468=>'L',
28143469=>'L',
28153470=>'L',
28163471=>'L',
28173472=>'L',
28183473=>'L',
28193474=>'L',
28203475=>'L',
28213476=>'L',
28223477=>'L',
28233478=>'L',
28243482=>'L',
28253483=>'L',
28263484=>'L',
28273485=>'L',
28283486=>'L',
28293487=>'L',
28303488=>'L',
28313489=>'L',
28323490=>'L',
28333491=>'L',
28343492=>'L',
28353493=>'L',
28363494=>'L',
28373495=>'L',
28383496=>'L',
28393497=>'L',
28403498=>'L',
28413499=>'L',
28423500=>'L',
28433501=>'L',
28443502=>'L',
28453503=>'L',
28463504=>'L',
28473505=>'L',
28483507=>'L',
28493508=>'L',
28503509=>'L',
28513510=>'L',
28523511=>'L',
28533512=>'L',
28543513=>'L',
28553514=>'L',
28563515=>'L',
28573517=>'L',
28583520=>'L',
28593521=>'L',
28603522=>'L',
28613523=>'L',
28623524=>'L',
28633525=>'L',
28643526=>'L',
28653530=>'NSM',
28663535=>'L',
28673536=>'L',
28683537=>'L',
28693538=>'NSM',
28703539=>'NSM',
28713540=>'NSM',
28723542=>'NSM',
28733544=>'L',
28743545=>'L',
28753546=>'L',
28763547=>'L',
28773548=>'L',
28783549=>'L',
28793550=>'L',
28803551=>'L',
28813570=>'L',
28823571=>'L',
28833572=>'L',
28843585=>'L',
28853586=>'L',
28863587=>'L',
28873588=>'L',
28883589=>'L',
28893590=>'L',
28903591=>'L',
28913592=>'L',
28923593=>'L',
28933594=>'L',
28943595=>'L',
28953596=>'L',
28963597=>'L',
28973598=>'L',
28983599=>'L',
28993600=>'L',
29003601=>'L',
29013602=>'L',
29023603=>'L',
29033604=>'L',
29043605=>'L',
29053606=>'L',
29063607=>'L',
29073608=>'L',
29083609=>'L',
29093610=>'L',
29103611=>'L',
29113612=>'L',
29123613=>'L',
29133614=>'L',
29143615=>'L',
29153616=>'L',
29163617=>'L',
29173618=>'L',
29183619=>'L',
29193620=>'L',
29203621=>'L',
29213622=>'L',
29223623=>'L',
29233624=>'L',
29243625=>'L',
29253626=>'L',
29263627=>'L',
29273628=>'L',
29283629=>'L',
29293630=>'L',
29303631=>'L',
29313632=>'L',
29323633=>'NSM',
29333634=>'L',
29343635=>'L',
29353636=>'NSM',
29363637=>'NSM',
29373638=>'NSM',
29383639=>'NSM',
29393640=>'NSM',
29403641=>'NSM',
29413642=>'NSM',
29423647=>'ET',
29433648=>'L',
29443649=>'L',
29453650=>'L',
29463651=>'L',
29473652=>'L',
29483653=>'L',
29493654=>'L',
29503655=>'NSM',
29513656=>'NSM',
29523657=>'NSM',
29533658=>'NSM',
29543659=>'NSM',
29553660=>'NSM',
29563661=>'NSM',
29573662=>'NSM',
29583663=>'L',
29593664=>'L',
29603665=>'L',
29613666=>'L',
29623667=>'L',
29633668=>'L',
29643669=>'L',
29653670=>'L',
29663671=>'L',
29673672=>'L',
29683673=>'L',
29693674=>'L',
29703675=>'L',
29713713=>'L',
29723714=>'L',
29733716=>'L',
29743719=>'L',
29753720=>'L',
29763722=>'L',
29773725=>'L',
29783732=>'L',
29793733=>'L',
29803734=>'L',
29813735=>'L',
29823737=>'L',
29833738=>'L',
29843739=>'L',
29853740=>'L',
29863741=>'L',
29873742=>'L',
29883743=>'L',
29893745=>'L',
29903746=>'L',
29913747=>'L',
29923749=>'L',
29933751=>'L',
29943754=>'L',
29953755=>'L',
29963757=>'L',
29973758=>'L',
29983759=>'L',
29993760=>'L',
30003761=>'NSM',
30013762=>'L',
30023763=>'L',
30033764=>'NSM',
30043765=>'NSM',
30053766=>'NSM',
30063767=>'NSM',
30073768=>'NSM',
30083769=>'NSM',
30093771=>'NSM',
30103772=>'NSM',
30113773=>'L',
30123776=>'L',
30133777=>'L',
30143778=>'L',
30153779=>'L',
30163780=>'L',
30173782=>'L',
30183784=>'NSM',
30193785=>'NSM',
30203786=>'NSM',
30213787=>'NSM',
30223788=>'NSM',
30233789=>'NSM',
30243792=>'L',
30253793=>'L',
30263794=>'L',
30273795=>'L',
30283796=>'L',
30293797=>'L',
30303798=>'L',
30313799=>'L',
30323800=>'L',
30333801=>'L',
30343804=>'L',
30353805=>'L',
30363840=>'L',
30373841=>'L',
30383842=>'L',
30393843=>'L',
30403844=>'L',
30413845=>'L',
30423846=>'L',
30433847=>'L',
30443848=>'L',
30453849=>'L',
30463850=>'L',
30473851=>'L',
30483852=>'L',
30493853=>'L',
30503854=>'L',
30513855=>'L',
30523856=>'L',
30533857=>'L',
30543858=>'L',
30553859=>'L',
30563860=>'L',
30573861=>'L',
30583862=>'L',
30593863=>'L',
30603864=>'NSM',
30613865=>'NSM',
30623866=>'L',
30633867=>'L',
30643868=>'L',
30653869=>'L',
30663870=>'L',
30673871=>'L',
30683872=>'L',
30693873=>'L',
30703874=>'L',
30713875=>'L',
30723876=>'L',
30733877=>'L',
30743878=>'L',
30753879=>'L',
30763880=>'L',
30773881=>'L',
30783882=>'L',
30793883=>'L',
30803884=>'L',
30813885=>'L',
30823886=>'L',
30833887=>'L',
30843888=>'L',
30853889=>'L',
30863890=>'L',
30873891=>'L',
30883892=>'L',
30893893=>'NSM',
30903894=>'L',
30913895=>'NSM',
30923896=>'L',
30933897=>'NSM',
30943898=>'ON',
30953899=>'ON',
30963900=>'ON',
30973901=>'ON',
30983902=>'L',
30993903=>'L',
31003904=>'L',
31013905=>'L',
31023906=>'L',
31033907=>'L',
31043908=>'L',
31053909=>'L',
31063910=>'L',
31073911=>'L',
31083913=>'L',
31093914=>'L',
31103915=>'L',
31113916=>'L',
31123917=>'L',
31133918=>'L',
31143919=>'L',
31153920=>'L',
31163921=>'L',
31173922=>'L',
31183923=>'L',
31193924=>'L',
31203925=>'L',
31213926=>'L',
31223927=>'L',
31233928=>'L',
31243929=>'L',
31253930=>'L',
31263931=>'L',
31273932=>'L',
31283933=>'L',
31293934=>'L',
31303935=>'L',
31313936=>'L',
31323937=>'L',
31333938=>'L',
31343939=>'L',
31353940=>'L',
31363941=>'L',
31373942=>'L',
31383943=>'L',
31393944=>'L',
31403945=>'L',
31413946=>'L',
31423953=>'NSM',
31433954=>'NSM',
31443955=>'NSM',
31453956=>'NSM',
31463957=>'NSM',
31473958=>'NSM',
31483959=>'NSM',
31493960=>'NSM',
31503961=>'NSM',
31513962=>'NSM',
31523963=>'NSM',
31533964=>'NSM',
31543965=>'NSM',
31553966=>'NSM',
31563967=>'L',
31573968=>'NSM',
31583969=>'NSM',
31593970=>'NSM',
31603971=>'NSM',
31613972=>'NSM',
31623973=>'L',
31633974=>'NSM',
31643975=>'NSM',
31653976=>'L',
31663977=>'L',
31673978=>'L',
31683979=>'L',
31693984=>'NSM',
31703985=>'NSM',
31713986=>'NSM',
31723987=>'NSM',
31733988=>'NSM',
31743989=>'NSM',
31753990=>'NSM',
31763991=>'NSM',
31773993=>'NSM',
31783994=>'NSM',
31793995=>'NSM',
31803996=>'NSM',
31813997=>'NSM',
31823998=>'NSM',
31833999=>'NSM',
31844000=>'NSM',
31854001=>'NSM',
31864002=>'NSM',
31874003=>'NSM',
31884004=>'NSM',
31894005=>'NSM',
31904006=>'NSM',
31914007=>'NSM',
31924008=>'NSM',
31934009=>'NSM',
31944010=>'NSM',
31954011=>'NSM',
31964012=>'NSM',
31974013=>'NSM',
31984014=>'NSM',
31994015=>'NSM',
32004016=>'NSM',
32014017=>'NSM',
32024018=>'NSM',
32034019=>'NSM',
32044020=>'NSM',
32054021=>'NSM',
32064022=>'NSM',
32074023=>'NSM',
32084024=>'NSM',
32094025=>'NSM',
32104026=>'NSM',
32114027=>'NSM',
32124028=>'NSM',
32134030=>'L',
32144031=>'L',
32154032=>'L',
32164033=>'L',
32174034=>'L',
32184035=>'L',
32194036=>'L',
32204037=>'L',
32214038=>'NSM',
32224039=>'L',
32234040=>'L',
32244041=>'L',
32254042=>'L',
32264043=>'L',
32274044=>'L',
32284047=>'L',
32294048=>'L',
32304049=>'L',
32314096=>'L',
32324097=>'L',
32334098=>'L',
32344099=>'L',
32354100=>'L',
32364101=>'L',
32374102=>'L',
32384103=>'L',
32394104=>'L',
32404105=>'L',
32414106=>'L',
32424107=>'L',
32434108=>'L',
32444109=>'L',
32454110=>'L',
32464111=>'L',
32474112=>'L',
32484113=>'L',
32494114=>'L',
32504115=>'L',
32514116=>'L',
32524117=>'L',
32534118=>'L',
32544119=>'L',
32554120=>'L',
32564121=>'L',
32574122=>'L',
32584123=>'L',
32594124=>'L',
32604125=>'L',
32614126=>'L',
32624127=>'L',
32634128=>'L',
32644129=>'L',
32654131=>'L',
32664132=>'L',
32674133=>'L',
32684134=>'L',
32694135=>'L',
32704137=>'L',
32714138=>'L',
32724140=>'L',
32734141=>'NSM',
32744142=>'NSM',
32754143=>'NSM',
32764144=>'NSM',
32774145=>'L',
32784146=>'NSM',
32794150=>'NSM',
32804151=>'NSM',
32814152=>'L',
32824153=>'NSM',
32834160=>'L',
32844161=>'L',
32854162=>'L',
32864163=>'L',
32874164=>'L',
32884165=>'L',
32894166=>'L',
32904167=>'L',
32914168=>'L',
32924169=>'L',
32934170=>'L',
32944171=>'L',
32954172=>'L',
32964173=>'L',
32974174=>'L',
32984175=>'L',
32994176=>'L',
33004177=>'L',
33014178=>'L',
33024179=>'L',
33034180=>'L',
33044181=>'L',
33054182=>'L',
33064183=>'L',
33074184=>'NSM',
33084185=>'NSM',
33094256=>'L',
33104257=>'L',
33114258=>'L',
33124259=>'L',
33134260=>'L',
33144261=>'L',
33154262=>'L',
33164263=>'L',
33174264=>'L',
33184265=>'L',
33194266=>'L',
33204267=>'L',
33214268=>'L',
33224269=>'L',
33234270=>'L',
33244271=>'L',
33254272=>'L',
33264273=>'L',
33274274=>'L',
33284275=>'L',
33294276=>'L',
33304277=>'L',
33314278=>'L',
33324279=>'L',
33334280=>'L',
33344281=>'L',
33354282=>'L',
33364283=>'L',
33374284=>'L',
33384285=>'L',
33394286=>'L',
33404287=>'L',
33414288=>'L',
33424289=>'L',
33434290=>'L',
33444291=>'L',
33454292=>'L',
33464293=>'L',
33474304=>'L',
33484305=>'L',
33494306=>'L',
33504307=>'L',
33514308=>'L',
33524309=>'L',
33534310=>'L',
33544311=>'L',
33554312=>'L',
33564313=>'L',
33574314=>'L',
33584315=>'L',
33594316=>'L',
33604317=>'L',
33614318=>'L',
33624319=>'L',
33634320=>'L',
33644321=>'L',
33654322=>'L',
33664323=>'L',
33674324=>'L',
33684325=>'L',
33694326=>'L',
33704327=>'L',
33714328=>'L',
33724329=>'L',
33734330=>'L',
33744331=>'L',
33754332=>'L',
33764333=>'L',
33774334=>'L',
33784335=>'L',
33794336=>'L',
33804337=>'L',
33814338=>'L',
33824339=>'L',
33834340=>'L',
33844341=>'L',
33854342=>'L',
33864343=>'L',
33874344=>'L',
33884345=>'L',
33894346=>'L',
33904347=>'L',
33914348=>'L',
33924352=>'L',
33934353=>'L',
33944354=>'L',
33954355=>'L',
33964356=>'L',
33974357=>'L',
33984358=>'L',
33994359=>'L',
34004360=>'L',
34014361=>'L',
34024362=>'L',
34034363=>'L',
34044364=>'L',
34054365=>'L',
34064366=>'L',
34074367=>'L',
34084368=>'L',
34094369=>'L',
34104370=>'L',
34114371=>'L',
34124372=>'L',
34134373=>'L',
34144374=>'L',
34154375=>'L',
34164376=>'L',
34174377=>'L',
34184378=>'L',
34194379=>'L',
34204380=>'L',
34214381=>'L',
34224382=>'L',
34234383=>'L',
34244384=>'L',
34254385=>'L',
34264386=>'L',
34274387=>'L',
34284388=>'L',
34294389=>'L',
34304390=>'L',
34314391=>'L',
34324392=>'L',
34334393=>'L',
34344394=>'L',
34354395=>'L',
34364396=>'L',
34374397=>'L',
34384398=>'L',
34394399=>'L',
34404400=>'L',
34414401=>'L',
34424402=>'L',
34434403=>'L',
34444404=>'L',
34454405=>'L',
34464406=>'L',
34474407=>'L',
34484408=>'L',
34494409=>'L',
34504410=>'L',
34514411=>'L',
34524412=>'L',
34534413=>'L',
34544414=>'L',
34554415=>'L',
34564416=>'L',
34574417=>'L',
34584418=>'L',
34594419=>'L',
34604420=>'L',
34614421=>'L',
34624422=>'L',
34634423=>'L',
34644424=>'L',
34654425=>'L',
34664426=>'L',
34674427=>'L',
34684428=>'L',
34694429=>'L',
34704430=>'L',
34714431=>'L',
34724432=>'L',
34734433=>'L',
34744434=>'L',
34754435=>'L',
34764436=>'L',
34774437=>'L',
34784438=>'L',
34794439=>'L',
34804440=>'L',
34814441=>'L',
34824447=>'L',
34834448=>'L',
34844449=>'L',
34854450=>'L',
34864451=>'L',
34874452=>'L',
34884453=>'L',
34894454=>'L',
34904455=>'L',
34914456=>'L',
34924457=>'L',
34934458=>'L',
34944459=>'L',
34954460=>'L',
34964461=>'L',
34974462=>'L',
34984463=>'L',
34994464=>'L',
35004465=>'L',
35014466=>'L',
35024467=>'L',
35034468=>'L',
35044469=>'L',
35054470=>'L',
35064471=>'L',
35074472=>'L',
35084473=>'L',
35094474=>'L',
35104475=>'L',
35114476=>'L',
35124477=>'L',
35134478=>'L',
35144479=>'L',
35154480=>'L',
35164481=>'L',
35174482=>'L',
35184483=>'L',
35194484=>'L',
35204485=>'L',
35214486=>'L',
35224487=>'L',
35234488=>'L',
35244489=>'L',
35254490=>'L',
35264491=>'L',
35274492=>'L',
35284493=>'L',
35294494=>'L',
35304495=>'L',
35314496=>'L',
35324497=>'L',
35334498=>'L',
35344499=>'L',
35354500=>'L',
35364501=>'L',
35374502=>'L',
35384503=>'L',
35394504=>'L',
35404505=>'L',
35414506=>'L',
35424507=>'L',
35434508=>'L',
35444509=>'L',
35454510=>'L',
35464511=>'L',
35474512=>'L',
35484513=>'L',
35494514=>'L',
35504520=>'L',
35514521=>'L',
35524522=>'L',
35534523=>'L',
35544524=>'L',
35554525=>'L',
35564526=>'L',
35574527=>'L',
35584528=>'L',
35594529=>'L',
35604530=>'L',
35614531=>'L',
35624532=>'L',
35634533=>'L',
35644534=>'L',
35654535=>'L',
35664536=>'L',
35674537=>'L',
35684538=>'L',
35694539=>'L',
35704540=>'L',
35714541=>'L',
35724542=>'L',
35734543=>'L',
35744544=>'L',
35754545=>'L',
35764546=>'L',
35774547=>'L',
35784548=>'L',
35794549=>'L',
35804550=>'L',
35814551=>'L',
35824552=>'L',
35834553=>'L',
35844554=>'L',
35854555=>'L',
35864556=>'L',
35874557=>'L',
35884558=>'L',
35894559=>'L',
35904560=>'L',
35914561=>'L',
35924562=>'L',
35934563=>'L',
35944564=>'L',
35954565=>'L',
35964566=>'L',
35974567=>'L',
35984568=>'L',
35994569=>'L',
36004570=>'L',
36014571=>'L',
36024572=>'L',
36034573=>'L',
36044574=>'L',
36054575=>'L',
36064576=>'L',
36074577=>'L',
36084578=>'L',
36094579=>'L',
36104580=>'L',
36114581=>'L',
36124582=>'L',
36134583=>'L',
36144584=>'L',
36154585=>'L',
36164586=>'L',
36174587=>'L',
36184588=>'L',
36194589=>'L',
36204590=>'L',
36214591=>'L',
36224592=>'L',
36234593=>'L',
36244594=>'L',
36254595=>'L',
36264596=>'L',
36274597=>'L',
36284598=>'L',
36294599=>'L',
36304600=>'L',
36314601=>'L',
36324608=>'L',
36334609=>'L',
36344610=>'L',
36354611=>'L',
36364612=>'L',
36374613=>'L',
36384614=>'L',
36394615=>'L',
36404616=>'L',
36414617=>'L',
36424618=>'L',
36434619=>'L',
36444620=>'L',
36454621=>'L',
36464622=>'L',
36474623=>'L',
36484624=>'L',
36494625=>'L',
36504626=>'L',
36514627=>'L',
36524628=>'L',
36534629=>'L',
36544630=>'L',
36554631=>'L',
36564632=>'L',
36574633=>'L',
36584634=>'L',
36594635=>'L',
36604636=>'L',
36614637=>'L',
36624638=>'L',
36634639=>'L',
36644640=>'L',
36654641=>'L',
36664642=>'L',
36674643=>'L',
36684644=>'L',
36694645=>'L',
36704646=>'L',
36714647=>'L',
36724648=>'L',
36734649=>'L',
36744650=>'L',
36754651=>'L',
36764652=>'L',
36774653=>'L',
36784654=>'L',
36794655=>'L',
36804656=>'L',
36814657=>'L',
36824658=>'L',
36834659=>'L',
36844660=>'L',
36854661=>'L',
36864662=>'L',
36874663=>'L',
36884664=>'L',
36894665=>'L',
36904666=>'L',
36914667=>'L',
36924668=>'L',
36934669=>'L',
36944670=>'L',
36954671=>'L',
36964672=>'L',
36974673=>'L',
36984674=>'L',
36994675=>'L',
37004676=>'L',
37014677=>'L',
37024678=>'L',
37034679=>'L',
37044680=>'L',
37054682=>'L',
37064683=>'L',
37074684=>'L',
37084685=>'L',
37094688=>'L',
37104689=>'L',
37114690=>'L',
37124691=>'L',
37134692=>'L',
37144693=>'L',
37154694=>'L',
37164696=>'L',
37174698=>'L',
37184699=>'L',
37194700=>'L',
37204701=>'L',
37214704=>'L',
37224705=>'L',
37234706=>'L',
37244707=>'L',
37254708=>'L',
37264709=>'L',
37274710=>'L',
37284711=>'L',
37294712=>'L',
37304713=>'L',
37314714=>'L',
37324715=>'L',
37334716=>'L',
37344717=>'L',
37354718=>'L',
37364719=>'L',
37374720=>'L',
37384721=>'L',
37394722=>'L',
37404723=>'L',
37414724=>'L',
37424725=>'L',
37434726=>'L',
37444727=>'L',
37454728=>'L',
37464729=>'L',
37474730=>'L',
37484731=>'L',
37494732=>'L',
37504733=>'L',
37514734=>'L',
37524735=>'L',
37534736=>'L',
37544737=>'L',
37554738=>'L',
37564739=>'L',
37574740=>'L',
37584741=>'L',
37594742=>'L',
37604743=>'L',
37614744=>'L',
37624746=>'L',
37634747=>'L',
37644748=>'L',
37654749=>'L',
37664752=>'L',
37674753=>'L',
37684754=>'L',
37694755=>'L',
37704756=>'L',
37714757=>'L',
37724758=>'L',
37734759=>'L',
37744760=>'L',
37754761=>'L',
37764762=>'L',
37774763=>'L',
37784764=>'L',
37794765=>'L',
37804766=>'L',
37814767=>'L',
37824768=>'L',
37834769=>'L',
37844770=>'L',
37854771=>'L',
37864772=>'L',
37874773=>'L',
37884774=>'L',
37894775=>'L',
37904776=>'L',
37914777=>'L',
37924778=>'L',
37934779=>'L',
37944780=>'L',
37954781=>'L',
37964782=>'L',
37974783=>'L',
37984784=>'L',
37994786=>'L',
38004787=>'L',
38014788=>'L',
38024789=>'L',
38034792=>'L',
38044793=>'L',
38054794=>'L',
38064795=>'L',
38074796=>'L',
38084797=>'L',
38094798=>'L',
38104800=>'L',
38114802=>'L',
38124803=>'L',
38134804=>'L',
38144805=>'L',
38154808=>'L',
38164809=>'L',
38174810=>'L',
38184811=>'L',
38194812=>'L',
38204813=>'L',
38214814=>'L',
38224815=>'L',
38234816=>'L',
38244817=>'L',
38254818=>'L',
38264819=>'L',
38274820=>'L',
38284821=>'L',
38294822=>'L',
38304824=>'L',
38314825=>'L',
38324826=>'L',
38334827=>'L',
38344828=>'L',
38354829=>'L',
38364830=>'L',
38374831=>'L',
38384832=>'L',
38394833=>'L',
38404834=>'L',
38414835=>'L',
38424836=>'L',
38434837=>'L',
38444838=>'L',
38454839=>'L',
38464840=>'L',
38474841=>'L',
38484842=>'L',
38494843=>'L',
38504844=>'L',
38514845=>'L',
38524846=>'L',
38534847=>'L',
38544848=>'L',
38554849=>'L',
38564850=>'L',
38574851=>'L',
38584852=>'L',
38594853=>'L',
38604854=>'L',
38614855=>'L',
38624856=>'L',
38634857=>'L',
38644858=>'L',
38654859=>'L',
38664860=>'L',
38674861=>'L',
38684862=>'L',
38694863=>'L',
38704864=>'L',
38714865=>'L',
38724866=>'L',
38734867=>'L',
38744868=>'L',
38754869=>'L',
38764870=>'L',
38774871=>'L',
38784872=>'L',
38794873=>'L',
38804874=>'L',
38814875=>'L',
38824876=>'L',
38834877=>'L',
38844878=>'L',
38854879=>'L',
38864880=>'L',
38874882=>'L',
38884883=>'L',
38894884=>'L',
38904885=>'L',
38914888=>'L',
38924889=>'L',
38934890=>'L',
38944891=>'L',
38954892=>'L',
38964893=>'L',
38974894=>'L',
38984895=>'L',
38994896=>'L',
39004897=>'L',
39014898=>'L',
39024899=>'L',
39034900=>'L',
39044901=>'L',
39054902=>'L',
39064903=>'L',
39074904=>'L',
39084905=>'L',
39094906=>'L',
39104907=>'L',
39114908=>'L',
39124909=>'L',
39134910=>'L',
39144911=>'L',
39154912=>'L',
39164913=>'L',
39174914=>'L',
39184915=>'L',
39194916=>'L',
39204917=>'L',
39214918=>'L',
39224919=>'L',
39234920=>'L',
39244921=>'L',
39254922=>'L',
39264923=>'L',
39274924=>'L',
39284925=>'L',
39294926=>'L',
39304927=>'L',
39314928=>'L',
39324929=>'L',
39334930=>'L',
39344931=>'L',
39354932=>'L',
39364933=>'L',
39374934=>'L',
39384935=>'L',
39394936=>'L',
39404937=>'L',
39414938=>'L',
39424939=>'L',
39434940=>'L',
39444941=>'L',
39454942=>'L',
39464943=>'L',
39474944=>'L',
39484945=>'L',
39494946=>'L',
39504947=>'L',
39514948=>'L',
39524949=>'L',
39534950=>'L',
39544951=>'L',
39554952=>'L',
39564953=>'L',
39574954=>'L',
39584959=>'NSM',
39594960=>'L',
39604961=>'L',
39614962=>'L',
39624963=>'L',
39634964=>'L',
39644965=>'L',
39654966=>'L',
39664967=>'L',
39674968=>'L',
39684969=>'L',
39694970=>'L',
39704971=>'L',
39714972=>'L',
39724973=>'L',
39734974=>'L',
39744975=>'L',
39754976=>'L',
39764977=>'L',
39774978=>'L',
39784979=>'L',
39794980=>'L',
39804981=>'L',
39814982=>'L',
39824983=>'L',
39834984=>'L',
39844985=>'L',
39854986=>'L',
39864987=>'L',
39874988=>'L',
39884992=>'L',
39894993=>'L',
39904994=>'L',
39914995=>'L',
39924996=>'L',
39934997=>'L',
39944998=>'L',
39954999=>'L',
39965000=>'L',
39975001=>'L',
39985002=>'L',
39995003=>'L',
40005004=>'L',
40015005=>'L',
40025006=>'L',
40035007=>'L',
40045008=>'ON',
40055009=>'ON',
40065010=>'ON',
40075011=>'ON',
40085012=>'ON',
40095013=>'ON',
40105014=>'ON',
40115015=>'ON',
40125016=>'ON',
40135017=>'ON',
40145024=>'L',
40155025=>'L',
40165026=>'L',
40175027=>'L',
40185028=>'L',
40195029=>'L',
40205030=>'L',
40215031=>'L',
40225032=>'L',
40235033=>'L',
40245034=>'L',
40255035=>'L',
40265036=>'L',
40275037=>'L',
40285038=>'L',
40295039=>'L',
40305040=>'L',
40315041=>'L',
40325042=>'L',
40335043=>'L',
40345044=>'L',
40355045=>'L',
40365046=>'L',
40375047=>'L',
40385048=>'L',
40395049=>'L',
40405050=>'L',
40415051=>'L',
40425052=>'L',
40435053=>'L',
40445054=>'L',
40455055=>'L',
40465056=>'L',
40475057=>'L',
40485058=>'L',
40495059=>'L',
40505060=>'L',
40515061=>'L',
40525062=>'L',
40535063=>'L',
40545064=>'L',
40555065=>'L',
40565066=>'L',
40575067=>'L',
40585068=>'L',
40595069=>'L',
40605070=>'L',
40615071=>'L',
40625072=>'L',
40635073=>'L',
40645074=>'L',
40655075=>'L',
40665076=>'L',
40675077=>'L',
40685078=>'L',
40695079=>'L',
40705080=>'L',
40715081=>'L',
40725082=>'L',
40735083=>'L',
40745084=>'L',
40755085=>'L',
40765086=>'L',
40775087=>'L',
40785088=>'L',
40795089=>'L',
40805090=>'L',
40815091=>'L',
40825092=>'L',
40835093=>'L',
40845094=>'L',
40855095=>'L',
40865096=>'L',
40875097=>'L',
40885098=>'L',
40895099=>'L',
40905100=>'L',
40915101=>'L',
40925102=>'L',
40935103=>'L',
40945104=>'L',
40955105=>'L',
40965106=>'L',
40975107=>'L',
40985108=>'L',
40995121=>'L',
41005122=>'L',
41015123=>'L',
41025124=>'L',
41035125=>'L',
41045126=>'L',
41055127=>'L',
41065128=>'L',
41075129=>'L',
41085130=>'L',
41095131=>'L',
41105132=>'L',
41115133=>'L',
41125134=>'L',
41135135=>'L',
41145136=>'L',
41155137=>'L',
41165138=>'L',
41175139=>'L',
41185140=>'L',
41195141=>'L',
41205142=>'L',
41215143=>'L',
41225144=>'L',
41235145=>'L',
41245146=>'L',
41255147=>'L',
41265148=>'L',
41275149=>'L',
41285150=>'L',
41295151=>'L',
41305152=>'L',
41315153=>'L',
41325154=>'L',
41335155=>'L',
41345156=>'L',
41355157=>'L',
41365158=>'L',
41375159=>'L',
41385160=>'L',
41395161=>'L',
41405162=>'L',
41415163=>'L',
41425164=>'L',
41435165=>'L',
41445166=>'L',
41455167=>'L',
41465168=>'L',
41475169=>'L',
41485170=>'L',
41495171=>'L',
41505172=>'L',
41515173=>'L',
41525174=>'L',
41535175=>'L',
41545176=>'L',
41555177=>'L',
41565178=>'L',
41575179=>'L',
41585180=>'L',
41595181=>'L',
41605182=>'L',
41615183=>'L',
41625184=>'L',
41635185=>'L',
41645186=>'L',
41655187=>'L',
41665188=>'L',
41675189=>'L',
41685190=>'L',
41695191=>'L',
41705192=>'L',
41715193=>'L',
41725194=>'L',
41735195=>'L',
41745196=>'L',
41755197=>'L',
41765198=>'L',
41775199=>'L',
41785200=>'L',
41795201=>'L',
41805202=>'L',
41815203=>'L',
41825204=>'L',
41835205=>'L',
41845206=>'L',
41855207=>'L',
41865208=>'L',
41875209=>'L',
41885210=>'L',
41895211=>'L',
41905212=>'L',
41915213=>'L',
41925214=>'L',
41935215=>'L',
41945216=>'L',
41955217=>'L',
41965218=>'L',
41975219=>'L',
41985220=>'L',
41995221=>'L',
42005222=>'L',
42015223=>'L',
42025224=>'L',
42035225=>'L',
42045226=>'L',
42055227=>'L',
42065228=>'L',
42075229=>'L',
42085230=>'L',
42095231=>'L',
42105232=>'L',
42115233=>'L',
42125234=>'L',
42135235=>'L',
42145236=>'L',
42155237=>'L',
42165238=>'L',
42175239=>'L',
42185240=>'L',
42195241=>'L',
42205242=>'L',
42215243=>'L',
42225244=>'L',
42235245=>'L',
42245246=>'L',
42255247=>'L',
42265248=>'L',
42275249=>'L',
42285250=>'L',
42295251=>'L',
42305252=>'L',
42315253=>'L',
42325254=>'L',
42335255=>'L',
42345256=>'L',
42355257=>'L',
42365258=>'L',
42375259=>'L',
42385260=>'L',
42395261=>'L',
42405262=>'L',
42415263=>'L',
42425264=>'L',
42435265=>'L',
42445266=>'L',
42455267=>'L',
42465268=>'L',
42475269=>'L',
42485270=>'L',
42495271=>'L',
42505272=>'L',
42515273=>'L',
42525274=>'L',
42535275=>'L',
42545276=>'L',
42555277=>'L',
42565278=>'L',
42575279=>'L',
42585280=>'L',
42595281=>'L',
42605282=>'L',
42615283=>'L',
42625284=>'L',
42635285=>'L',
42645286=>'L',
42655287=>'L',
42665288=>'L',
42675289=>'L',
42685290=>'L',
42695291=>'L',
42705292=>'L',
42715293=>'L',
42725294=>'L',
42735295=>'L',
42745296=>'L',
42755297=>'L',
42765298=>'L',
42775299=>'L',
42785300=>'L',
42795301=>'L',
42805302=>'L',
42815303=>'L',
42825304=>'L',
42835305=>'L',
42845306=>'L',
42855307=>'L',
42865308=>'L',
42875309=>'L',
42885310=>'L',
42895311=>'L',
42905312=>'L',
42915313=>'L',
42925314=>'L',
42935315=>'L',
42945316=>'L',
42955317=>'L',
42965318=>'L',
42975319=>'L',
42985320=>'L',
42995321=>'L',
43005322=>'L',
43015323=>'L',
43025324=>'L',
43035325=>'L',
43045326=>'L',
43055327=>'L',
43065328=>'L',
43075329=>'L',
43085330=>'L',
43095331=>'L',
43105332=>'L',
43115333=>'L',
43125334=>'L',
43135335=>'L',
43145336=>'L',
43155337=>'L',
43165338=>'L',
43175339=>'L',
43185340=>'L',
43195341=>'L',
43205342=>'L',
43215343=>'L',
43225344=>'L',
43235345=>'L',
43245346=>'L',
43255347=>'L',
43265348=>'L',
43275349=>'L',
43285350=>'L',
43295351=>'L',
43305352=>'L',
43315353=>'L',
43325354=>'L',
43335355=>'L',
43345356=>'L',
43355357=>'L',
43365358=>'L',
43375359=>'L',
43385360=>'L',
43395361=>'L',
43405362=>'L',
43415363=>'L',
43425364=>'L',
43435365=>'L',
43445366=>'L',
43455367=>'L',
43465368=>'L',
43475369=>'L',
43485370=>'L',
43495371=>'L',
43505372=>'L',
43515373=>'L',
43525374=>'L',
43535375=>'L',
43545376=>'L',
43555377=>'L',
43565378=>'L',
43575379=>'L',
43585380=>'L',
43595381=>'L',
43605382=>'L',
43615383=>'L',
43625384=>'L',
43635385=>'L',
43645386=>'L',
43655387=>'L',
43665388=>'L',
43675389=>'L',
43685390=>'L',
43695391=>'L',
43705392=>'L',
43715393=>'L',
43725394=>'L',
43735395=>'L',
43745396=>'L',
43755397=>'L',
43765398=>'L',
43775399=>'L',
43785400=>'L',
43795401=>'L',
43805402=>'L',
43815403=>'L',
43825404=>'L',
43835405=>'L',
43845406=>'L',
43855407=>'L',
43865408=>'L',
43875409=>'L',
43885410=>'L',
43895411=>'L',
43905412=>'L',
43915413=>'L',
43925414=>'L',
43935415=>'L',
43945416=>'L',
43955417=>'L',
43965418=>'L',
43975419=>'L',
43985420=>'L',
43995421=>'L',
44005422=>'L',
44015423=>'L',
44025424=>'L',
44035425=>'L',
44045426=>'L',
44055427=>'L',
44065428=>'L',
44075429=>'L',
44085430=>'L',
44095431=>'L',
44105432=>'L',
44115433=>'L',
44125434=>'L',
44135435=>'L',
44145436=>'L',
44155437=>'L',
44165438=>'L',
44175439=>'L',
44185440=>'L',
44195441=>'L',
44205442=>'L',
44215443=>'L',
44225444=>'L',
44235445=>'L',
44245446=>'L',
44255447=>'L',
44265448=>'L',
44275449=>'L',
44285450=>'L',
44295451=>'L',
44305452=>'L',
44315453=>'L',
44325454=>'L',
44335455=>'L',
44345456=>'L',
44355457=>'L',
44365458=>'L',
44375459=>'L',
44385460=>'L',
44395461=>'L',
44405462=>'L',
44415463=>'L',
44425464=>'L',
44435465=>'L',
44445466=>'L',
44455467=>'L',
44465468=>'L',
44475469=>'L',
44485470=>'L',
44495471=>'L',
44505472=>'L',
44515473=>'L',
44525474=>'L',
44535475=>'L',
44545476=>'L',
44555477=>'L',
44565478=>'L',
44575479=>'L',
44585480=>'L',
44595481=>'L',
44605482=>'L',
44615483=>'L',
44625484=>'L',
44635485=>'L',
44645486=>'L',
44655487=>'L',
44665488=>'L',
44675489=>'L',
44685490=>'L',
44695491=>'L',
44705492=>'L',
44715493=>'L',
44725494=>'L',
44735495=>'L',
44745496=>'L',
44755497=>'L',
44765498=>'L',
44775499=>'L',
44785500=>'L',
44795501=>'L',
44805502=>'L',
44815503=>'L',
44825504=>'L',
44835505=>'L',
44845506=>'L',
44855507=>'L',
44865508=>'L',
44875509=>'L',
44885510=>'L',
44895511=>'L',
44905512=>'L',
44915513=>'L',
44925514=>'L',
44935515=>'L',
44945516=>'L',
44955517=>'L',
44965518=>'L',
44975519=>'L',
44985520=>'L',
44995521=>'L',
45005522=>'L',
45015523=>'L',
45025524=>'L',
45035525=>'L',
45045526=>'L',
45055527=>'L',
45065528=>'L',
45075529=>'L',
45085530=>'L',
45095531=>'L',
45105532=>'L',
45115533=>'L',
45125534=>'L',
45135535=>'L',
45145536=>'L',
45155537=>'L',
45165538=>'L',
45175539=>'L',
45185540=>'L',
45195541=>'L',
45205542=>'L',
45215543=>'L',
45225544=>'L',
45235545=>'L',
45245546=>'L',
45255547=>'L',
45265548=>'L',
45275549=>'L',
45285550=>'L',
45295551=>'L',
45305552=>'L',
45315553=>'L',
45325554=>'L',
45335555=>'L',
45345556=>'L',
45355557=>'L',
45365558=>'L',
45375559=>'L',
45385560=>'L',
45395561=>'L',
45405562=>'L',
45415563=>'L',
45425564=>'L',
45435565=>'L',
45445566=>'L',
45455567=>'L',
45465568=>'L',
45475569=>'L',
45485570=>'L',
45495571=>'L',
45505572=>'L',
45515573=>'L',
45525574=>'L',
45535575=>'L',
45545576=>'L',
45555577=>'L',
45565578=>'L',
45575579=>'L',
45585580=>'L',
45595581=>'L',
45605582=>'L',
45615583=>'L',
45625584=>'L',
45635585=>'L',
45645586=>'L',
45655587=>'L',
45665588=>'L',
45675589=>'L',
45685590=>'L',
45695591=>'L',
45705592=>'L',
45715593=>'L',
45725594=>'L',
45735595=>'L',
45745596=>'L',
45755597=>'L',
45765598=>'L',
45775599=>'L',
45785600=>'L',
45795601=>'L',
45805602=>'L',
45815603=>'L',
45825604=>'L',
45835605=>'L',
45845606=>'L',
45855607=>'L',
45865608=>'L',
45875609=>'L',
45885610=>'L',
45895611=>'L',
45905612=>'L',
45915613=>'L',
45925614=>'L',
45935615=>'L',
45945616=>'L',
45955617=>'L',
45965618=>'L',
45975619=>'L',
45985620=>'L',
45995621=>'L',
46005622=>'L',
46015623=>'L',
46025624=>'L',
46035625=>'L',
46045626=>'L',
46055627=>'L',
46065628=>'L',
46075629=>'L',
46085630=>'L',
46095631=>'L',
46105632=>'L',
46115633=>'L',
46125634=>'L',
46135635=>'L',
46145636=>'L',
46155637=>'L',
46165638=>'L',
46175639=>'L',
46185640=>'L',
46195641=>'L',
46205642=>'L',
46215643=>'L',
46225644=>'L',
46235645=>'L',
46245646=>'L',
46255647=>'L',
46265648=>'L',
46275649=>'L',
46285650=>'L',
46295651=>'L',
46305652=>'L',
46315653=>'L',
46325654=>'L',
46335655=>'L',
46345656=>'L',
46355657=>'L',
46365658=>'L',
46375659=>'L',
46385660=>'L',
46395661=>'L',
46405662=>'L',
46415663=>'L',
46425664=>'L',
46435665=>'L',
46445666=>'L',
46455667=>'L',
46465668=>'L',
46475669=>'L',
46485670=>'L',
46495671=>'L',
46505672=>'L',
46515673=>'L',
46525674=>'L',
46535675=>'L',
46545676=>'L',
46555677=>'L',
46565678=>'L',
46575679=>'L',
46585680=>'L',
46595681=>'L',
46605682=>'L',
46615683=>'L',
46625684=>'L',
46635685=>'L',
46645686=>'L',
46655687=>'L',
46665688=>'L',
46675689=>'L',
46685690=>'L',
46695691=>'L',
46705692=>'L',
46715693=>'L',
46725694=>'L',
46735695=>'L',
46745696=>'L',
46755697=>'L',
46765698=>'L',
46775699=>'L',
46785700=>'L',
46795701=>'L',
46805702=>'L',
46815703=>'L',
46825704=>'L',
46835705=>'L',
46845706=>'L',
46855707=>'L',
46865708=>'L',
46875709=>'L',
46885710=>'L',
46895711=>'L',
46905712=>'L',
46915713=>'L',
46925714=>'L',
46935715=>'L',
46945716=>'L',
46955717=>'L',
46965718=>'L',
46975719=>'L',
46985720=>'L',
46995721=>'L',
47005722=>'L',
47015723=>'L',
47025724=>'L',
47035725=>'L',
47045726=>'L',
47055727=>'L',
47065728=>'L',
47075729=>'L',
47085730=>'L',
47095731=>'L',
47105732=>'L',
47115733=>'L',
47125734=>'L',
47135735=>'L',
47145736=>'L',
47155737=>'L',
47165738=>'L',
47175739=>'L',
47185740=>'L',
47195741=>'L',
47205742=>'L',
47215743=>'L',
47225744=>'L',
47235745=>'L',
47245746=>'L',
47255747=>'L',
47265748=>'L',
47275749=>'L',
47285750=>'L',
47295760=>'WS',
47305761=>'L',
47315762=>'L',
47325763=>'L',
47335764=>'L',
47345765=>'L',
47355766=>'L',
47365767=>'L',
47375768=>'L',
47385769=>'L',
47395770=>'L',
47405771=>'L',
47415772=>'L',
47425773=>'L',
47435774=>'L',
47445775=>'L',
47455776=>'L',
47465777=>'L',
47475778=>'L',
47485779=>'L',
47495780=>'L',
47505781=>'L',
47515782=>'L',
47525783=>'L',
47535784=>'L',
47545785=>'L',
47555786=>'L',
47565787=>'ON',
47575788=>'ON',
47585792=>'L',
47595793=>'L',
47605794=>'L',
47615795=>'L',
47625796=>'L',
47635797=>'L',
47645798=>'L',
47655799=>'L',
47665800=>'L',
47675801=>'L',
47685802=>'L',
47695803=>'L',
47705804=>'L',
47715805=>'L',
47725806=>'L',
47735807=>'L',
47745808=>'L',
47755809=>'L',
47765810=>'L',
47775811=>'L',
47785812=>'L',
47795813=>'L',
47805814=>'L',
47815815=>'L',
47825816=>'L',
47835817=>'L',
47845818=>'L',
47855819=>'L',
47865820=>'L',
47875821=>'L',
47885822=>'L',
47895823=>'L',
47905824=>'L',
47915825=>'L',
47925826=>'L',
47935827=>'L',
47945828=>'L',
47955829=>'L',
47965830=>'L',
47975831=>'L',
47985832=>'L',
47995833=>'L',
48005834=>'L',
48015835=>'L',
48025836=>'L',
48035837=>'L',
48045838=>'L',
48055839=>'L',
48065840=>'L',
48075841=>'L',
48085842=>'L',
48095843=>'L',
48105844=>'L',
48115845=>'L',
48125846=>'L',
48135847=>'L',
48145848=>'L',
48155849=>'L',
48165850=>'L',
48175851=>'L',
48185852=>'L',
48195853=>'L',
48205854=>'L',
48215855=>'L',
48225856=>'L',
48235857=>'L',
48245858=>'L',
48255859=>'L',
48265860=>'L',
48275861=>'L',
48285862=>'L',
48295863=>'L',
48305864=>'L',
48315865=>'L',
48325866=>'L',
48335867=>'L',
48345868=>'L',
48355869=>'L',
48365870=>'L',
48375871=>'L',
48385872=>'L',
48395888=>'L',
48405889=>'L',
48415890=>'L',
48425891=>'L',
48435892=>'L',
48445893=>'L',
48455894=>'L',
48465895=>'L',
48475896=>'L',
48485897=>'L',
48495898=>'L',
48505899=>'L',
48515900=>'L',
48525902=>'L',
48535903=>'L',
48545904=>'L',
48555905=>'L',
48565906=>'NSM',
48575907=>'NSM',
48585908=>'NSM',
48595920=>'L',
48605921=>'L',
48615922=>'L',
48625923=>'L',
48635924=>'L',
48645925=>'L',
48655926=>'L',
48665927=>'L',
48675928=>'L',
48685929=>'L',
48695930=>'L',
48705931=>'L',
48715932=>'L',
48725933=>'L',
48735934=>'L',
48745935=>'L',
48755936=>'L',
48765937=>'L',
48775938=>'NSM',
48785939=>'NSM',
48795940=>'NSM',
48805941=>'L',
48815942=>'L',
48825952=>'L',
48835953=>'L',
48845954=>'L',
48855955=>'L',
48865956=>'L',
48875957=>'L',
48885958=>'L',
48895959=>'L',
48905960=>'L',
48915961=>'L',
48925962=>'L',
48935963=>'L',
48945964=>'L',
48955965=>'L',
48965966=>'L',
48975967=>'L',
48985968=>'L',
48995969=>'L',
49005970=>'NSM',
49015971=>'NSM',
49025984=>'L',
49035985=>'L',
49045986=>'L',
49055987=>'L',
49065988=>'L',
49075989=>'L',
49085990=>'L',
49095991=>'L',
49105992=>'L',
49115993=>'L',
49125994=>'L',
49135995=>'L',
49145996=>'L',
49155998=>'L',
49165999=>'L',
49176000=>'L',
49186002=>'NSM',
49196003=>'NSM',
49206016=>'L',
49216017=>'L',
49226018=>'L',
49236019=>'L',
49246020=>'L',
49256021=>'L',
49266022=>'L',
49276023=>'L',
49286024=>'L',
49296025=>'L',
49306026=>'L',
49316027=>'L',
49326028=>'L',
49336029=>'L',
49346030=>'L',
49356031=>'L',
49366032=>'L',
49376033=>'L',
49386034=>'L',
49396035=>'L',
49406036=>'L',
49416037=>'L',
49426038=>'L',
49436039=>'L',
49446040=>'L',
49456041=>'L',
49466042=>'L',
49476043=>'L',
49486044=>'L',
49496045=>'L',
49506046=>'L',
49516047=>'L',
49526048=>'L',
49536049=>'L',
49546050=>'L',
49556051=>'L',
49566052=>'L',
49576053=>'L',
49586054=>'L',
49596055=>'L',
49606056=>'L',
49616057=>'L',
49626058=>'L',
49636059=>'L',
49646060=>'L',
49656061=>'L',
49666062=>'L',
49676063=>'L',
49686064=>'L',
49696065=>'L',
49706066=>'L',
49716067=>'L',
49726068=>'L',
49736069=>'L',
49746070=>'L',
49756071=>'NSM',
49766072=>'NSM',
49776073=>'NSM',
49786074=>'NSM',
49796075=>'NSM',
49806076=>'NSM',
49816077=>'NSM',
49826078=>'L',
49836079=>'L',
49846080=>'L',
49856081=>'L',
49866082=>'L',
49876083=>'L',
49886084=>'L',
49896085=>'L',
49906086=>'NSM',
49916087=>'L',
49926088=>'L',
49936089=>'NSM',
49946090=>'NSM',
49956091=>'NSM',
49966092=>'NSM',
49976093=>'NSM',
49986094=>'NSM',
49996095=>'NSM',
50006096=>'NSM',
50016097=>'NSM',
50026098=>'NSM',
50036099=>'NSM',
50046100=>'L',
50056101=>'L',
50066102=>'L',
50076103=>'L',
50086104=>'L',
50096105=>'L',
50106106=>'L',
50116107=>'ET',
50126108=>'L',
50136109=>'NSM',
50146112=>'L',
50156113=>'L',
50166114=>'L',
50176115=>'L',
50186116=>'L',
50196117=>'L',
50206118=>'L',
50216119=>'L',
50226120=>'L',
50236121=>'L',
50246128=>'ON',
50256129=>'ON',
50266130=>'ON',
50276131=>'ON',
50286132=>'ON',
50296133=>'ON',
50306134=>'ON',
50316135=>'ON',
50326136=>'ON',
50336137=>'ON',
50346144=>'ON',
50356145=>'ON',
50366146=>'ON',
50376147=>'ON',
50386148=>'ON',
50396149=>'ON',
50406150=>'ON',
50416151=>'ON',
50426152=>'ON',
50436153=>'ON',
50446154=>'ON',
50456155=>'NSM',
50466156=>'NSM',
50476157=>'NSM',
50486158=>'WS',
50496160=>'L',
50506161=>'L',
50516162=>'L',
50526163=>'L',
50536164=>'L',
50546165=>'L',
50556166=>'L',
50566167=>'L',
50576168=>'L',
50586169=>'L',
50596176=>'L',
50606177=>'L',
50616178=>'L',
50626179=>'L',
50636180=>'L',
50646181=>'L',
50656182=>'L',
50666183=>'L',
50676184=>'L',
50686185=>'L',
50696186=>'L',
50706187=>'L',
50716188=>'L',
50726189=>'L',
50736190=>'L',
50746191=>'L',
50756192=>'L',
50766193=>'L',
50776194=>'L',
50786195=>'L',
50796196=>'L',
50806197=>'L',
50816198=>'L',
50826199=>'L',
50836200=>'L',
50846201=>'L',
50856202=>'L',
50866203=>'L',
50876204=>'L',
50886205=>'L',
50896206=>'L',
50906207=>'L',
50916208=>'L',
50926209=>'L',
50936210=>'L',
50946211=>'L',
50956212=>'L',
50966213=>'L',
50976214=>'L',
50986215=>'L',
50996216=>'L',
51006217=>'L',
51016218=>'L',
51026219=>'L',
51036220=>'L',
51046221=>'L',
51056222=>'L',
51066223=>'L',
51076224=>'L',
51086225=>'L',
51096226=>'L',
51106227=>'L',
51116228=>'L',
51126229=>'L',
51136230=>'L',
51146231=>'L',
51156232=>'L',
51166233=>'L',
51176234=>'L',
51186235=>'L',
51196236=>'L',
51206237=>'L',
51216238=>'L',
51226239=>'L',
51236240=>'L',
51246241=>'L',
51256242=>'L',
51266243=>'L',
51276244=>'L',
51286245=>'L',
51296246=>'L',
51306247=>'L',
51316248=>'L',
51326249=>'L',
51336250=>'L',
51346251=>'L',
51356252=>'L',
51366253=>'L',
51376254=>'L',
51386255=>'L',
51396256=>'L',
51406257=>'L',
51416258=>'L',
51426259=>'L',
51436260=>'L',
51446261=>'L',
51456262=>'L',
51466263=>'L',
51476272=>'L',
51486273=>'L',
51496274=>'L',
51506275=>'L',
51516276=>'L',
51526277=>'L',
51536278=>'L',
51546279=>'L',
51556280=>'L',
51566281=>'L',
51576282=>'L',
51586283=>'L',
51596284=>'L',
51606285=>'L',
51616286=>'L',
51626287=>'L',
51636288=>'L',
51646289=>'L',
51656290=>'L',
51666291=>'L',
51676292=>'L',
51686293=>'L',
51696294=>'L',
51706295=>'L',
51716296=>'L',
51726297=>'L',
51736298=>'L',
51746299=>'L',
51756300=>'L',
51766301=>'L',
51776302=>'L',
51786303=>'L',
51796304=>'L',
51806305=>'L',
51816306=>'L',
51826307=>'L',
51836308=>'L',
51846309=>'L',
51856310=>'L',
51866311=>'L',
51876312=>'L',
51886313=>'NSM',
51896400=>'L',
51906401=>'L',
51916402=>'L',
51926403=>'L',
51936404=>'L',
51946405=>'L',
51956406=>'L',
51966407=>'L',
51976408=>'L',
51986409=>'L',
51996410=>'L',
52006411=>'L',
52016412=>'L',
52026413=>'L',
52036414=>'L',
52046415=>'L',
52056416=>'L',
52066417=>'L',
52076418=>'L',
52086419=>'L',
52096420=>'L',
52106421=>'L',
52116422=>'L',
52126423=>'L',
52136424=>'L',
52146425=>'L',
52156426=>'L',
52166427=>'L',
52176428=>'L',
52186432=>'NSM',
52196433=>'NSM',
52206434=>'NSM',
52216435=>'L',
52226436=>'L',
52236437=>'L',
52246438=>'L',
52256439=>'NSM',
52266440=>'NSM',
52276441=>'NSM',
52286442=>'NSM',
52296443=>'NSM',
52306448=>'L',
52316449=>'L',
52326450=>'NSM',
52336451=>'L',
52346452=>'L',
52356453=>'L',
52366454=>'L',
52376455=>'L',
52386456=>'L',
52396457=>'NSM',
52406458=>'NSM',
52416459=>'NSM',
52426464=>'ON',
52436468=>'ON',
52446469=>'ON',
52456470=>'L',
52466471=>'L',
52476472=>'L',
52486473=>'L',
52496474=>'L',
52506475=>'L',
52516476=>'L',
52526477=>'L',
52536478=>'L',
52546479=>'L',
52556480=>'L',
52566481=>'L',
52576482=>'L',
52586483=>'L',
52596484=>'L',
52606485=>'L',
52616486=>'L',
52626487=>'L',
52636488=>'L',
52646489=>'L',
52656490=>'L',
52666491=>'L',
52676492=>'L',
52686493=>'L',
52696494=>'L',
52706495=>'L',
52716496=>'L',
52726497=>'L',
52736498=>'L',
52746499=>'L',
52756500=>'L',
52766501=>'L',
52776502=>'L',
52786503=>'L',
52796504=>'L',
52806505=>'L',
52816506=>'L',
52826507=>'L',
52836508=>'L',
52846509=>'L',
52856512=>'L',
52866513=>'L',
52876514=>'L',
52886515=>'L',
52896516=>'L',
52906528=>'L',
52916529=>'L',
52926530=>'L',
52936531=>'L',
52946532=>'L',
52956533=>'L',
52966534=>'L',
52976535=>'L',
52986536=>'L',
52996537=>'L',
53006538=>'L',
53016539=>'L',
53026540=>'L',
53036541=>'L',
53046542=>'L',
53056543=>'L',
53066544=>'L',
53076545=>'L',
53086546=>'L',
53096547=>'L',
53106548=>'L',
53116549=>'L',
53126550=>'L',
53136551=>'L',
53146552=>'L',
53156553=>'L',
53166554=>'L',
53176555=>'L',
53186556=>'L',
53196557=>'L',
53206558=>'L',
53216559=>'L',
53226560=>'L',
53236561=>'L',
53246562=>'L',
53256563=>'L',
53266564=>'L',
53276565=>'L',
53286566=>'L',
53296567=>'L',
53306568=>'L',
53316569=>'L',
53326576=>'L',
53336577=>'L',
53346578=>'L',
53356579=>'L',
53366580=>'L',
53376581=>'L',
53386582=>'L',
53396583=>'L',
53406584=>'L',
53416585=>'L',
53426586=>'L',
53436587=>'L',
53446588=>'L',
53456589=>'L',
53466590=>'L',
53476591=>'L',
53486592=>'L',
53496593=>'L',
53506594=>'L',
53516595=>'L',
53526596=>'L',
53536597=>'L',
53546598=>'L',
53556599=>'L',
53566600=>'L',
53576601=>'L',
53586608=>'L',
53596609=>'L',
53606610=>'L',
53616611=>'L',
53626612=>'L',
53636613=>'L',
53646614=>'L',
53656615=>'L',
53666616=>'L',
53676617=>'L',
53686622=>'ON',
53696623=>'ON',
53706624=>'ON',
53716625=>'ON',
53726626=>'ON',
53736627=>'ON',
53746628=>'ON',
53756629=>'ON',
53766630=>'ON',
53776631=>'ON',
53786632=>'ON',
53796633=>'ON',
53806634=>'ON',
53816635=>'ON',
53826636=>'ON',
53836637=>'ON',
53846638=>'ON',
53856639=>'ON',
53866640=>'ON',
53876641=>'ON',
53886642=>'ON',
53896643=>'ON',
53906644=>'ON',
53916645=>'ON',
53926646=>'ON',
53936647=>'ON',
53946648=>'ON',
53956649=>'ON',
53966650=>'ON',
53976651=>'ON',
53986652=>'ON',
53996653=>'ON',
54006654=>'ON',
54016655=>'ON',
54026656=>'L',
54036657=>'L',
54046658=>'L',
54056659=>'L',
54066660=>'L',
54076661=>'L',
54086662=>'L',
54096663=>'L',
54106664=>'L',
54116665=>'L',
54126666=>'L',
54136667=>'L',
54146668=>'L',
54156669=>'L',
54166670=>'L',
54176671=>'L',
54186672=>'L',
54196673=>'L',
54206674=>'L',
54216675=>'L',
54226676=>'L',
54236677=>'L',
54246678=>'L',
54256679=>'NSM',
54266680=>'NSM',
54276681=>'L',
54286682=>'L',
54296683=>'L',
54306686=>'L',
54316687=>'L',
54326912=>'NSM',
54336913=>'NSM',
54346914=>'NSM',
54356915=>'NSM',
54366916=>'L',
54376917=>'L',
54386918=>'L',
54396919=>'L',
54406920=>'L',
54416921=>'L',
54426922=>'L',
54436923=>'L',
54446924=>'L',
54456925=>'L',
54466926=>'L',
54476927=>'L',
54486928=>'L',
54496929=>'L',
54506930=>'L',
54516931=>'L',
54526932=>'L',
54536933=>'L',
54546934=>'L',
54556935=>'L',
54566936=>'L',
54576937=>'L',
54586938=>'L',
54596939=>'L',
54606940=>'L',
54616941=>'L',
54626942=>'L',
54636943=>'L',
54646944=>'L',
54656945=>'L',
54666946=>'L',
54676947=>'L',
54686948=>'L',
54696949=>'L',
54706950=>'L',
54716951=>'L',
54726952=>'L',
54736953=>'L',
54746954=>'L',
54756955=>'L',
54766956=>'L',
54776957=>'L',
54786958=>'L',
54796959=>'L',
54806960=>'L',
54816961=>'L',
54826962=>'L',
54836963=>'L',
54846964=>'NSM',
54856965=>'L',
54866966=>'NSM',
54876967=>'NSM',
54886968=>'NSM',
54896969=>'NSM',
54906970=>'NSM',
54916971=>'L',
54926972=>'NSM',
54936973=>'L',
54946974=>'L',
54956975=>'L',
54966976=>'L',
54976977=>'L',
54986978=>'NSM',
54996979=>'L',
55006980=>'L',
55016981=>'L',
55026982=>'L',
55036983=>'L',
55046984=>'L',
55056985=>'L',
55066986=>'L',
55076987=>'L',
55086992=>'L',
55096993=>'L',
55106994=>'L',
55116995=>'L',
55126996=>'L',
55136997=>'L',
55146998=>'L',
55156999=>'L',
55167000=>'L',
55177001=>'L',
55187002=>'L',
55197003=>'L',
55207004=>'L',
55217005=>'L',
55227006=>'L',
55237007=>'L',
55247008=>'L',
55257009=>'L',
55267010=>'L',
55277011=>'L',
55287012=>'L',
55297013=>'L',
55307014=>'L',
55317015=>'L',
55327016=>'L',
55337017=>'L',
55347018=>'L',
55357019=>'NSM',
55367020=>'NSM',
55377021=>'NSM',
55387022=>'NSM',
55397023=>'NSM',
55407024=>'NSM',
55417025=>'NSM',
55427026=>'NSM',
55437027=>'NSM',
55447028=>'L',
55457029=>'L',
55467030=>'L',
55477031=>'L',
55487032=>'L',
55497033=>'L',
55507034=>'L',
55517035=>'L',
55527036=>'L',
55537424=>'L',
55547425=>'L',
55557426=>'L',
55567427=>'L',
55577428=>'L',
55587429=>'L',
55597430=>'L',
55607431=>'L',
55617432=>'L',
55627433=>'L',
55637434=>'L',
55647435=>'L',
55657436=>'L',
55667437=>'L',
55677438=>'L',
55687439=>'L',
55697440=>'L',
55707441=>'L',
55717442=>'L',
55727443=>'L',
55737444=>'L',
55747445=>'L',
55757446=>'L',
55767447=>'L',
55777448=>'L',
55787449=>'L',
55797450=>'L',
55807451=>'L',
55817452=>'L',
55827453=>'L',
55837454=>'L',
55847455=>'L',
55857456=>'L',
55867457=>'L',
55877458=>'L',
55887459=>'L',
55897460=>'L',
55907461=>'L',
55917462=>'L',
55927463=>'L',
55937464=>'L',
55947465=>'L',
55957466=>'L',
55967467=>'L',
55977468=>'L',
55987469=>'L',
55997470=>'L',
56007471=>'L',
56017472=>'L',
56027473=>'L',
56037474=>'L',
56047475=>'L',
56057476=>'L',
56067477=>'L',
56077478=>'L',
56087479=>'L',
56097480=>'L',
56107481=>'L',
56117482=>'L',
56127483=>'L',
56137484=>'L',
56147485=>'L',
56157486=>'L',
56167487=>'L',
56177488=>'L',
56187489=>'L',
56197490=>'L',
56207491=>'L',
56217492=>'L',
56227493=>'L',
56237494=>'L',
56247495=>'L',
56257496=>'L',
56267497=>'L',
56277498=>'L',
56287499=>'L',
56297500=>'L',
56307501=>'L',
56317502=>'L',
56327503=>'L',
56337504=>'L',
56347505=>'L',
56357506=>'L',
56367507=>'L',
56377508=>'L',
56387509=>'L',
56397510=>'L',
56407511=>'L',
56417512=>'L',
56427513=>'L',
56437514=>'L',
56447515=>'L',
56457516=>'L',
56467517=>'L',
56477518=>'L',
56487519=>'L',
56497520=>'L',
56507521=>'L',
56517522=>'L',
56527523=>'L',
56537524=>'L',
56547525=>'L',
56557526=>'L',
56567527=>'L',
56577528=>'L',
56587529=>'L',
56597530=>'L',
56607531=>'L',
56617532=>'L',
56627533=>'L',
56637534=>'L',
56647535=>'L',
56657536=>'L',
56667537=>'L',
56677538=>'L',
56687539=>'L',
56697540=>'L',
56707541=>'L',
56717542=>'L',
56727543=>'L',
56737544=>'L',
56747545=>'L',
56757546=>'L',
56767547=>'L',
56777548=>'L',
56787549=>'L',
56797550=>'L',
56807551=>'L',
56817552=>'L',
56827553=>'L',
56837554=>'L',
56847555=>'L',
56857556=>'L',
56867557=>'L',
56877558=>'L',
56887559=>'L',
56897560=>'L',
56907561=>'L',
56917562=>'L',
56927563=>'L',
56937564=>'L',
56947565=>'L',
56957566=>'L',
56967567=>'L',
56977568=>'L',
56987569=>'L',
56997570=>'L',
57007571=>'L',
57017572=>'L',
57027573=>'L',
57037574=>'L',
57047575=>'L',
57057576=>'L',
57067577=>'L',
57077578=>'L',
57087579=>'L',
57097580=>'L',
57107581=>'L',
57117582=>'L',
57127583=>'L',
57137584=>'L',
57147585=>'L',
57157586=>'L',
57167587=>'L',
57177588=>'L',
57187589=>'L',
57197590=>'L',
57207591=>'L',
57217592=>'L',
57227593=>'L',
57237594=>'L',
57247595=>'L',
57257596=>'L',
57267597=>'L',
57277598=>'L',
57287599=>'L',
57297600=>'L',
57307601=>'L',
57317602=>'L',
57327603=>'L',
57337604=>'L',
57347605=>'L',
57357606=>'L',
57367607=>'L',
57377608=>'L',
57387609=>'L',
57397610=>'L',
57407611=>'L',
57417612=>'L',
57427613=>'L',
57437614=>'L',
57447615=>'L',
57457616=>'NSM',
57467617=>'NSM',
57477618=>'NSM',
57487619=>'NSM',
57497620=>'NSM',
57507621=>'NSM',
57517622=>'NSM',
57527623=>'NSM',
57537624=>'NSM',
57547625=>'NSM',
57557626=>'NSM',
57567678=>'NSM',
57577679=>'NSM',
57587680=>'L',
57597681=>'L',
57607682=>'L',
57617683=>'L',
57627684=>'L',
57637685=>'L',
57647686=>'L',
57657687=>'L',
57667688=>'L',
57677689=>'L',
57687690=>'L',
57697691=>'L',
57707692=>'L',
57717693=>'L',
57727694=>'L',
57737695=>'L',
57747696=>'L',
57757697=>'L',
57767698=>'L',
57777699=>'L',
57787700=>'L',
57797701=>'L',
57807702=>'L',
57817703=>'L',
57827704=>'L',
57837705=>'L',
57847706=>'L',
57857707=>'L',
57867708=>'L',
57877709=>'L',
57887710=>'L',
57897711=>'L',
57907712=>'L',
57917713=>'L',
57927714=>'L',
57937715=>'L',
57947716=>'L',
57957717=>'L',
57967718=>'L',
57977719=>'L',
57987720=>'L',
57997721=>'L',
58007722=>'L',
58017723=>'L',
58027724=>'L',
58037725=>'L',
58047726=>'L',
58057727=>'L',
58067728=>'L',
58077729=>'L',
58087730=>'L',
58097731=>'L',
58107732=>'L',
58117733=>'L',
58127734=>'L',
58137735=>'L',
58147736=>'L',
58157737=>'L',
58167738=>'L',
58177739=>'L',
58187740=>'L',
58197741=>'L',
58207742=>'L',
58217743=>'L',
58227744=>'L',
58237745=>'L',
58247746=>'L',
58257747=>'L',
58267748=>'L',
58277749=>'L',
58287750=>'L',
58297751=>'L',
58307752=>'L',
58317753=>'L',
58327754=>'L',
58337755=>'L',
58347756=>'L',
58357757=>'L',
58367758=>'L',
58377759=>'L',
58387760=>'L',
58397761=>'L',
58407762=>'L',
58417763=>'L',
58427764=>'L',
58437765=>'L',
58447766=>'L',
58457767=>'L',
58467768=>'L',
58477769=>'L',
58487770=>'L',
58497771=>'L',
58507772=>'L',
58517773=>'L',
58527774=>'L',
58537775=>'L',
58547776=>'L',
58557777=>'L',
58567778=>'L',
58577779=>'L',
58587780=>'L',
58597781=>'L',
58607782=>'L',
58617783=>'L',
58627784=>'L',
58637785=>'L',
58647786=>'L',
58657787=>'L',
58667788=>'L',
58677789=>'L',
58687790=>'L',
58697791=>'L',
58707792=>'L',
58717793=>'L',
58727794=>'L',
58737795=>'L',
58747796=>'L',
58757797=>'L',
58767798=>'L',
58777799=>'L',
58787800=>'L',
58797801=>'L',
58807802=>'L',
58817803=>'L',
58827804=>'L',
58837805=>'L',
58847806=>'L',
58857807=>'L',
58867808=>'L',
58877809=>'L',
58887810=>'L',
58897811=>'L',
58907812=>'L',
58917813=>'L',
58927814=>'L',
58937815=>'L',
58947816=>'L',
58957817=>'L',
58967818=>'L',
58977819=>'L',
58987820=>'L',
58997821=>'L',
59007822=>'L',
59017823=>'L',
59027824=>'L',
59037825=>'L',
59047826=>'L',
59057827=>'L',
59067828=>'L',
59077829=>'L',
59087830=>'L',
59097831=>'L',
59107832=>'L',
59117833=>'L',
59127834=>'L',
59137835=>'L',
59147840=>'L',
59157841=>'L',
59167842=>'L',
59177843=>'L',
59187844=>'L',
59197845=>'L',
59207846=>'L',
59217847=>'L',
59227848=>'L',
59237849=>'L',
59247850=>'L',
59257851=>'L',
59267852=>'L',
59277853=>'L',
59287854=>'L',
59297855=>'L',
59307856=>'L',
59317857=>'L',
59327858=>'L',
59337859=>'L',
59347860=>'L',
59357861=>'L',
59367862=>'L',
59377863=>'L',
59387864=>'L',
59397865=>'L',
59407866=>'L',
59417867=>'L',
59427868=>'L',
59437869=>'L',
59447870=>'L',
59457871=>'L',
59467872=>'L',
59477873=>'L',
59487874=>'L',
59497875=>'L',
59507876=>'L',
59517877=>'L',
59527878=>'L',
59537879=>'L',
59547880=>'L',
59557881=>'L',
59567882=>'L',
59577883=>'L',
59587884=>'L',
59597885=>'L',
59607886=>'L',
59617887=>'L',
59627888=>'L',
59637889=>'L',
59647890=>'L',
59657891=>'L',
59667892=>'L',
59677893=>'L',
59687894=>'L',
59697895=>'L',
59707896=>'L',
59717897=>'L',
59727898=>'L',
59737899=>'L',
59747900=>'L',
59757901=>'L',
59767902=>'L',
59777903=>'L',
59787904=>'L',
59797905=>'L',
59807906=>'L',
59817907=>'L',
59827908=>'L',
59837909=>'L',
59847910=>'L',
59857911=>'L',
59867912=>'L',
59877913=>'L',
59887914=>'L',
59897915=>'L',
59907916=>'L',
59917917=>'L',
59927918=>'L',
59937919=>'L',
59947920=>'L',
59957921=>'L',
59967922=>'L',
59977923=>'L',
59987924=>'L',
59997925=>'L',
60007926=>'L',
60017927=>'L',
60027928=>'L',
60037929=>'L',
60047936=>'L',
60057937=>'L',
60067938=>'L',
60077939=>'L',
60087940=>'L',
60097941=>'L',
60107942=>'L',
60117943=>'L',
60127944=>'L',
60137945=>'L',
60147946=>'L',
60157947=>'L',
60167948=>'L',
60177949=>'L',
60187950=>'L',
60197951=>'L',
60207952=>'L',
60217953=>'L',
60227954=>'L',
60237955=>'L',
60247956=>'L',
60257957=>'L',
60267960=>'L',
60277961=>'L',
60287962=>'L',
60297963=>'L',
60307964=>'L',
60317965=>'L',
60327968=>'L',
60337969=>'L',
60347970=>'L',
60357971=>'L',
60367972=>'L',
60377973=>'L',
60387974=>'L',
60397975=>'L',
60407976=>'L',
60417977=>'L',
60427978=>'L',
60437979=>'L',
60447980=>'L',
60457981=>'L',
60467982=>'L',
60477983=>'L',
60487984=>'L',
60497985=>'L',
60507986=>'L',
60517987=>'L',
60527988=>'L',
60537989=>'L',
60547990=>'L',
60557991=>'L',
60567992=>'L',
60577993=>'L',
60587994=>'L',
60597995=>'L',
60607996=>'L',
60617997=>'L',
60627998=>'L',
60637999=>'L',
60648000=>'L',
60658001=>'L',
60668002=>'L',
60678003=>'L',
60688004=>'L',
60698005=>'L',
60708008=>'L',
60718009=>'L',
60728010=>'L',
60738011=>'L',
60748012=>'L',
60758013=>'L',
60768016=>'L',
60778017=>'L',
60788018=>'L',
60798019=>'L',
60808020=>'L',
60818021=>'L',
60828022=>'L',
60838023=>'L',
60848025=>'L',
60858027=>'L',
60868029=>'L',
60878031=>'L',
60888032=>'L',
60898033=>'L',
60908034=>'L',
60918035=>'L',
60928036=>'L',
60938037=>'L',
60948038=>'L',
60958039=>'L',
60968040=>'L',
60978041=>'L',
60988042=>'L',
60998043=>'L',
61008044=>'L',
61018045=>'L',
61028046=>'L',
61038047=>'L',
61048048=>'L',
61058049=>'L',
61068050=>'L',
61078051=>'L',
61088052=>'L',
61098053=>'L',
61108054=>'L',
61118055=>'L',
61128056=>'L',
61138057=>'L',
61148058=>'L',
61158059=>'L',
61168060=>'L',
61178061=>'L',
61188064=>'L',
61198065=>'L',
61208066=>'L',
61218067=>'L',
61228068=>'L',
61238069=>'L',
61248070=>'L',
61258071=>'L',
61268072=>'L',
61278073=>'L',
61288074=>'L',
61298075=>'L',
61308076=>'L',
61318077=>'L',
61328078=>'L',
61338079=>'L',
61348080=>'L',
61358081=>'L',
61368082=>'L',
61378083=>'L',
61388084=>'L',
61398085=>'L',
61408086=>'L',
61418087=>'L',
61428088=>'L',
61438089=>'L',
61448090=>'L',
61458091=>'L',
61468092=>'L',
61478093=>'L',
61488094=>'L',
61498095=>'L',
61508096=>'L',
61518097=>'L',
61528098=>'L',
61538099=>'L',
61548100=>'L',
61558101=>'L',
61568102=>'L',
61578103=>'L',
61588104=>'L',
61598105=>'L',
61608106=>'L',
61618107=>'L',
61628108=>'L',
61638109=>'L',
61648110=>'L',
61658111=>'L',
61668112=>'L',
61678113=>'L',
61688114=>'L',
61698115=>'L',
61708116=>'L',
61718118=>'L',
61728119=>'L',
61738120=>'L',
61748121=>'L',
61758122=>'L',
61768123=>'L',
61778124=>'L',
61788125=>'ON',
61798126=>'L',
61808127=>'ON',
61818128=>'ON',
61828129=>'ON',
61838130=>'L',
61848131=>'L',
61858132=>'L',
61868134=>'L',
61878135=>'L',
61888136=>'L',
61898137=>'L',
61908138=>'L',
61918139=>'L',
61928140=>'L',
61938141=>'ON',
61948142=>'ON',
61958143=>'ON',
61968144=>'L',
61978145=>'L',
61988146=>'L',
61998147=>'L',
62008150=>'L',
62018151=>'L',
62028152=>'L',
62038153=>'L',
62048154=>'L',
62058155=>'L',
62068157=>'ON',
62078158=>'ON',
62088159=>'ON',
62098160=>'L',
62108161=>'L',
62118162=>'L',
62128163=>'L',
62138164=>'L',
62148165=>'L',
62158166=>'L',
62168167=>'L',
62178168=>'L',
62188169=>'L',
62198170=>'L',
62208171=>'L',
62218172=>'L',
62228173=>'ON',
62238174=>'ON',
62248175=>'ON',
62258178=>'L',
62268179=>'L',
62278180=>'L',
62288182=>'L',
62298183=>'L',
62308184=>'L',
62318185=>'L',
62328186=>'L',
62338187=>'L',
62348188=>'L',
62358189=>'ON',
62368190=>'ON',
62378192=>'WS',
62388193=>'WS',
62398194=>'WS',
62408195=>'WS',
62418196=>'WS',
62428197=>'WS',
62438198=>'WS',
62448199=>'WS',
62458200=>'WS',
62468201=>'WS',
62478202=>'WS',
62488203=>'BN',
62498204=>'BN',
62508205=>'BN',
62518206=>'L',
62528207=>'R',
62538208=>'ON',
62548209=>'ON',
62558210=>'ON',
62568211=>'ON',
62578212=>'ON',
62588213=>'ON',
62598214=>'ON',
62608215=>'ON',
62618216=>'ON',
62628217=>'ON',
62638218=>'ON',
62648219=>'ON',
62658220=>'ON',
62668221=>'ON',
62678222=>'ON',
62688223=>'ON',
62698224=>'ON',
62708225=>'ON',
62718226=>'ON',
62728227=>'ON',
62738228=>'ON',
62748229=>'ON',
62758230=>'ON',
62768231=>'ON',
62778232=>'WS',
62788233=>'B',
62798234=>'LRE',
62808235=>'RLE',
62818236=>'PDF',
62828237=>'LRO',
62838238=>'RLO',
62848239=>'CS',
62858240=>'ET',
62868241=>'ET',
62878242=>'ET',
62888243=>'ET',
62898244=>'ET',
62908245=>'ON',
62918246=>'ON',
62928247=>'ON',
62938248=>'ON',
62948249=>'ON',
62958250=>'ON',
62968251=>'ON',
62978252=>'ON',
62988253=>'ON',
62998254=>'ON',
63008255=>'ON',
63018256=>'ON',
63028257=>'ON',
63038258=>'ON',
63048259=>'ON',
63058260=>'CS',
63068261=>'ON',
63078262=>'ON',
63088263=>'ON',
63098264=>'ON',
63108265=>'ON',
63118266=>'ON',
63128267=>'ON',
63138268=>'ON',
63148269=>'ON',
63158270=>'ON',
63168271=>'ON',
63178272=>'ON',
63188273=>'ON',
63198274=>'ON',
63208275=>'ON',
63218276=>'ON',
63228277=>'ON',
63238278=>'ON',
63248279=>'ON',
63258280=>'ON',
63268281=>'ON',
63278282=>'ON',
63288283=>'ON',
63298284=>'ON',
63308285=>'ON',
63318286=>'ON',
63328287=>'WS',
63338288=>'BN',
63348289=>'BN',
63358290=>'BN',
63368291=>'BN',
63378298=>'BN',
63388299=>'BN',
63398300=>'BN',
63408301=>'BN',
63418302=>'BN',
63428303=>'BN',
63438304=>'EN',
63448305=>'L',
63458308=>'EN',
63468309=>'EN',
63478310=>'EN',
63488311=>'EN',
63498312=>'EN',
63508313=>'EN',
63518314=>'ES',
63528315=>'ES',
63538316=>'ON',
63548317=>'ON',
63558318=>'ON',
63568319=>'L',
63578320=>'EN',
63588321=>'EN',
63598322=>'EN',
63608323=>'EN',
63618324=>'EN',
63628325=>'EN',
63638326=>'EN',
63648327=>'EN',
63658328=>'EN',
63668329=>'EN',
63678330=>'ES',
63688331=>'ES',
63698332=>'ON',
63708333=>'ON',
63718334=>'ON',
63728336=>'L',
63738337=>'L',
63748338=>'L',
63758339=>'L',
63768340=>'L',
63778352=>'ET',
63788353=>'ET',
63798354=>'ET',
63808355=>'ET',
63818356=>'ET',
63828357=>'ET',
63838358=>'ET',
63848359=>'ET',
63858360=>'ET',
63868361=>'ET',
63878362=>'ET',
63888363=>'ET',
63898364=>'ET',
63908365=>'ET',
63918366=>'ET',
63928367=>'ET',
63938368=>'ET',
63948369=>'ET',
63958370=>'ET',
63968371=>'ET',
63978372=>'ET',
63988373=>'ET',
63998400=>'NSM',
64008401=>'NSM',
64018402=>'NSM',
64028403=>'NSM',
64038404=>'NSM',
64048405=>'NSM',
64058406=>'NSM',
64068407=>'NSM',
64078408=>'NSM',
64088409=>'NSM',
64098410=>'NSM',
64108411=>'NSM',
64118412=>'NSM',
64128413=>'NSM',
64138414=>'NSM',
64148415=>'NSM',
64158416=>'NSM',
64168417=>'NSM',
64178418=>'NSM',
64188419=>'NSM',
64198420=>'NSM',
64208421=>'NSM',
64218422=>'NSM',
64228423=>'NSM',
64238424=>'NSM',
64248425=>'NSM',
64258426=>'NSM',
64268427=>'NSM',
64278428=>'NSM',
64288429=>'NSM',
64298430=>'NSM',
64308431=>'NSM',
64318448=>'ON',
64328449=>'ON',
64338450=>'L',
64348451=>'ON',
64358452=>'ON',
64368453=>'ON',
64378454=>'ON',
64388455=>'L',
64398456=>'ON',
64408457=>'ON',
64418458=>'L',
64428459=>'L',
64438460=>'L',
64448461=>'L',
64458462=>'L',
64468463=>'L',
64478464=>'L',
64488465=>'L',
64498466=>'L',
64508467=>'L',
64518468=>'ON',
64528469=>'L',
64538470=>'ON',
64548471=>'ON',
64558472=>'ON',
64568473=>'L',
64578474=>'L',
64588475=>'L',
64598476=>'L',
64608477=>'L',
64618478=>'ON',
64628479=>'ON',
64638480=>'ON',
64648481=>'ON',
64658482=>'ON',
64668483=>'ON',
64678484=>'L',
64688485=>'ON',
64698486=>'L',
64708487=>'ON',
64718488=>'L',
64728489=>'ON',
64738490=>'L',
64748491=>'L',
64758492=>'L',
64768493=>'L',
64778494=>'ET',
64788495=>'L',
64798496=>'L',
64808497=>'L',
64818498=>'L',
64828499=>'L',
64838500=>'L',
64848501=>'L',
64858502=>'L',
64868503=>'L',
64878504=>'L',
64888505=>'L',
64898506=>'ON',
64908507=>'ON',
64918508=>'L',
64928509=>'L',
64938510=>'L',
64948511=>'L',
64958512=>'ON',
64968513=>'ON',
64978514=>'ON',
64988515=>'ON',
64998516=>'ON',
65008517=>'L',
65018518=>'L',
65028519=>'L',
65038520=>'L',
65048521=>'L',
65058522=>'ON',
65068523=>'ON',
65078524=>'ON',
65088525=>'ON',
65098526=>'L',
65108531=>'ON',
65118532=>'ON',
65128533=>'ON',
65138534=>'ON',
65148535=>'ON',
65158536=>'ON',
65168537=>'ON',
65178538=>'ON',
65188539=>'ON',
65198540=>'ON',
65208541=>'ON',
65218542=>'ON',
65228543=>'ON',
65238544=>'L',
65248545=>'L',
65258546=>'L',
65268547=>'L',
65278548=>'L',
65288549=>'L',
65298550=>'L',
65308551=>'L',
65318552=>'L',
65328553=>'L',
65338554=>'L',
65348555=>'L',
65358556=>'L',
65368557=>'L',
65378558=>'L',
65388559=>'L',
65398560=>'L',
65408561=>'L',
65418562=>'L',
65428563=>'L',
65438564=>'L',
65448565=>'L',
65458566=>'L',
65468567=>'L',
65478568=>'L',
65488569=>'L',
65498570=>'L',
65508571=>'L',
65518572=>'L',
65528573=>'L',
65538574=>'L',
65548575=>'L',
65558576=>'L',
65568577=>'L',
65578578=>'L',
65588579=>'L',
65598580=>'L',
65608592=>'ON',
65618593=>'ON',
65628594=>'ON',
65638595=>'ON',
65648596=>'ON',
65658597=>'ON',
65668598=>'ON',
65678599=>'ON',
65688600=>'ON',
65698601=>'ON',
65708602=>'ON',
65718603=>'ON',
65728604=>'ON',
65738605=>'ON',
65748606=>'ON',
65758607=>'ON',
65768608=>'ON',
65778609=>'ON',
65788610=>'ON',
65798611=>'ON',
65808612=>'ON',
65818613=>'ON',
65828614=>'ON',
65838615=>'ON',
65848616=>'ON',
65858617=>'ON',
65868618=>'ON',
65878619=>'ON',
65888620=>'ON',
65898621=>'ON',
65908622=>'ON',
65918623=>'ON',
65928624=>'ON',
65938625=>'ON',
65948626=>'ON',
65958627=>'ON',
65968628=>'ON',
65978629=>'ON',
65988630=>'ON',
65998631=>'ON',
66008632=>'ON',
66018633=>'ON',
66028634=>'ON',
66038635=>'ON',
66048636=>'ON',
66058637=>'ON',
66068638=>'ON',
66078639=>'ON',
66088640=>'ON',
66098641=>'ON',
66108642=>'ON',
66118643=>'ON',
66128644=>'ON',
66138645=>'ON',
66148646=>'ON',
66158647=>'ON',
66168648=>'ON',
66178649=>'ON',
66188650=>'ON',
66198651=>'ON',
66208652=>'ON',
66218653=>'ON',
66228654=>'ON',
66238655=>'ON',
66248656=>'ON',
66258657=>'ON',
66268658=>'ON',
66278659=>'ON',
66288660=>'ON',
66298661=>'ON',
66308662=>'ON',
66318663=>'ON',
66328664=>'ON',
66338665=>'ON',
66348666=>'ON',
66358667=>'ON',
66368668=>'ON',
66378669=>'ON',
66388670=>'ON',
66398671=>'ON',
66408672=>'ON',
66418673=>'ON',
66428674=>'ON',
66438675=>'ON',
66448676=>'ON',
66458677=>'ON',
66468678=>'ON',
66478679=>'ON',
66488680=>'ON',
66498681=>'ON',
66508682=>'ON',
66518683=>'ON',
66528684=>'ON',
66538685=>'ON',
66548686=>'ON',
66558687=>'ON',
66568688=>'ON',
66578689=>'ON',
66588690=>'ON',
66598691=>'ON',
66608692=>'ON',
66618693=>'ON',
66628694=>'ON',
66638695=>'ON',
66648696=>'ON',
66658697=>'ON',
66668698=>'ON',
66678699=>'ON',
66688700=>'ON',
66698701=>'ON',
66708702=>'ON',
66718703=>'ON',
66728704=>'ON',
66738705=>'ON',
66748706=>'ON',
66758707=>'ON',
66768708=>'ON',
66778709=>'ON',
66788710=>'ON',
66798711=>'ON',
66808712=>'ON',
66818713=>'ON',
66828714=>'ON',
66838715=>'ON',
66848716=>'ON',
66858717=>'ON',
66868718=>'ON',
66878719=>'ON',
66888720=>'ON',
66898721=>'ON',
66908722=>'ES',
66918723=>'ET',
66928724=>'ON',
66938725=>'ON',
66948726=>'ON',
66958727=>'ON',
66968728=>'ON',
66978729=>'ON',
66988730=>'ON',
66998731=>'ON',
67008732=>'ON',
67018733=>'ON',
67028734=>'ON',
67038735=>'ON',
67048736=>'ON',
67058737=>'ON',
67068738=>'ON',
67078739=>'ON',
67088740=>'ON',
67098741=>'ON',
67108742=>'ON',
67118743=>'ON',
67128744=>'ON',
67138745=>'ON',
67148746=>'ON',
67158747=>'ON',
67168748=>'ON',
67178749=>'ON',
67188750=>'ON',
67198751=>'ON',
67208752=>'ON',
67218753=>'ON',
67228754=>'ON',
67238755=>'ON',
67248756=>'ON',
67258757=>'ON',
67268758=>'ON',
67278759=>'ON',
67288760=>'ON',
67298761=>'ON',
67308762=>'ON',
67318763=>'ON',
67328764=>'ON',
67338765=>'ON',
67348766=>'ON',
67358767=>'ON',
67368768=>'ON',
67378769=>'ON',
67388770=>'ON',
67398771=>'ON',
67408772=>'ON',
67418773=>'ON',
67428774=>'ON',
67438775=>'ON',
67448776=>'ON',
67458777=>'ON',
67468778=>'ON',
67478779=>'ON',
67488780=>'ON',
67498781=>'ON',
67508782=>'ON',
67518783=>'ON',
67528784=>'ON',
67538785=>'ON',
67548786=>'ON',
67558787=>'ON',
67568788=>'ON',
67578789=>'ON',
67588790=>'ON',
67598791=>'ON',
67608792=>'ON',
67618793=>'ON',
67628794=>'ON',
67638795=>'ON',
67648796=>'ON',
67658797=>'ON',
67668798=>'ON',
67678799=>'ON',
67688800=>'ON',
67698801=>'ON',
67708802=>'ON',
67718803=>'ON',
67728804=>'ON',
67738805=>'ON',
67748806=>'ON',
67758807=>'ON',
67768808=>'ON',
67778809=>'ON',
67788810=>'ON',
67798811=>'ON',
67808812=>'ON',
67818813=>'ON',
67828814=>'ON',
67838815=>'ON',
67848816=>'ON',
67858817=>'ON',
67868818=>'ON',
67878819=>'ON',
67888820=>'ON',
67898821=>'ON',
67908822=>'ON',
67918823=>'ON',
67928824=>'ON',
67938825=>'ON',
67948826=>'ON',
67958827=>'ON',
67968828=>'ON',
67978829=>'ON',
67988830=>'ON',
67998831=>'ON',
68008832=>'ON',
68018833=>'ON',
68028834=>'ON',
68038835=>'ON',
68048836=>'ON',
68058837=>'ON',
68068838=>'ON',
68078839=>'ON',
68088840=>'ON',
68098841=>'ON',
68108842=>'ON',
68118843=>'ON',
68128844=>'ON',
68138845=>'ON',
68148846=>'ON',
68158847=>'ON',
68168848=>'ON',
68178849=>'ON',
68188850=>'ON',
68198851=>'ON',
68208852=>'ON',
68218853=>'ON',
68228854=>'ON',
68238855=>'ON',
68248856=>'ON',
68258857=>'ON',
68268858=>'ON',
68278859=>'ON',
68288860=>'ON',
68298861=>'ON',
68308862=>'ON',
68318863=>'ON',
68328864=>'ON',
68338865=>'ON',
68348866=>'ON',
68358867=>'ON',
68368868=>'ON',
68378869=>'ON',
68388870=>'ON',
68398871=>'ON',
68408872=>'ON',
68418873=>'ON',
68428874=>'ON',
68438875=>'ON',
68448876=>'ON',
68458877=>'ON',
68468878=>'ON',
68478879=>'ON',
68488880=>'ON',
68498881=>'ON',
68508882=>'ON',
68518883=>'ON',
68528884=>'ON',
68538885=>'ON',
68548886=>'ON',
68558887=>'ON',
68568888=>'ON',
68578889=>'ON',
68588890=>'ON',
68598891=>'ON',
68608892=>'ON',
68618893=>'ON',
68628894=>'ON',
68638895=>'ON',
68648896=>'ON',
68658897=>'ON',
68668898=>'ON',
68678899=>'ON',
68688900=>'ON',
68698901=>'ON',
68708902=>'ON',
68718903=>'ON',
68728904=>'ON',
68738905=>'ON',
68748906=>'ON',
68758907=>'ON',
68768908=>'ON',
68778909=>'ON',
68788910=>'ON',
68798911=>'ON',
68808912=>'ON',
68818913=>'ON',
68828914=>'ON',
68838915=>'ON',
68848916=>'ON',
68858917=>'ON',
68868918=>'ON',
68878919=>'ON',
68888920=>'ON',
68898921=>'ON',
68908922=>'ON',
68918923=>'ON',
68928924=>'ON',
68938925=>'ON',
68948926=>'ON',
68958927=>'ON',
68968928=>'ON',
68978929=>'ON',
68988930=>'ON',
68998931=>'ON',
69008932=>'ON',
69018933=>'ON',
69028934=>'ON',
69038935=>'ON',
69048936=>'ON',
69058937=>'ON',
69068938=>'ON',
69078939=>'ON',
69088940=>'ON',
69098941=>'ON',
69108942=>'ON',
69118943=>'ON',
69128944=>'ON',
69138945=>'ON',
69148946=>'ON',
69158947=>'ON',
69168948=>'ON',
69178949=>'ON',
69188950=>'ON',
69198951=>'ON',
69208952=>'ON',
69218953=>'ON',
69228954=>'ON',
69238955=>'ON',
69248956=>'ON',
69258957=>'ON',
69268958=>'ON',
69278959=>'ON',
69288960=>'ON',
69298961=>'ON',
69308962=>'ON',
69318963=>'ON',
69328964=>'ON',
69338965=>'ON',
69348966=>'ON',
69358967=>'ON',
69368968=>'ON',
69378969=>'ON',
69388970=>'ON',
69398971=>'ON',
69408972=>'ON',
69418973=>'ON',
69428974=>'ON',
69438975=>'ON',
69448976=>'ON',
69458977=>'ON',
69468978=>'ON',
69478979=>'ON',
69488980=>'ON',
69498981=>'ON',
69508982=>'ON',
69518983=>'ON',
69528984=>'ON',
69538985=>'ON',
69548986=>'ON',
69558987=>'ON',
69568988=>'ON',
69578989=>'ON',
69588990=>'ON',
69598991=>'ON',
69608992=>'ON',
69618993=>'ON',
69628994=>'ON',
69638995=>'ON',
69648996=>'ON',
69658997=>'ON',
69668998=>'ON',
69678999=>'ON',
69689000=>'ON',
69699001=>'ON',
69709002=>'ON',
69719003=>'ON',
69729004=>'ON',
69739005=>'ON',
69749006=>'ON',
69759007=>'ON',
69769008=>'ON',
69779009=>'ON',
69789010=>'ON',
69799011=>'ON',
69809012=>'ON',
69819013=>'ON',
69829014=>'L',
69839015=>'L',
69849016=>'L',
69859017=>'L',
69869018=>'L',
69879019=>'L',
69889020=>'L',
69899021=>'L',
69909022=>'L',
69919023=>'L',
69929024=>'L',
69939025=>'L',
69949026=>'L',
69959027=>'L',
69969028=>'L',
69979029=>'L',
69989030=>'L',
69999031=>'L',
70009032=>'L',
70019033=>'L',
70029034=>'L',
70039035=>'L',
70049036=>'L',
70059037=>'L',
70069038=>'L',
70079039=>'L',
70089040=>'L',
70099041=>'L',
70109042=>'L',
70119043=>'L',
70129044=>'L',
70139045=>'L',
70149046=>'L',
70159047=>'L',
70169048=>'L',
70179049=>'L',
70189050=>'L',
70199051=>'L',
70209052=>'L',
70219053=>'L',
70229054=>'L',
70239055=>'L',
70249056=>'L',
70259057=>'L',
70269058=>'L',
70279059=>'L',
70289060=>'L',
70299061=>'L',
70309062=>'L',
70319063=>'L',
70329064=>'L',
70339065=>'L',
70349066=>'L',
70359067=>'L',
70369068=>'L',
70379069=>'L',
70389070=>'L',
70399071=>'L',
70409072=>'L',
70419073=>'L',
70429074=>'L',
70439075=>'L',
70449076=>'L',
70459077=>'L',
70469078=>'L',
70479079=>'L',
70489080=>'L',
70499081=>'L',
70509082=>'L',
70519083=>'ON',
70529084=>'ON',
70539085=>'ON',
70549086=>'ON',
70559087=>'ON',
70569088=>'ON',
70579089=>'ON',
70589090=>'ON',
70599091=>'ON',
70609092=>'ON',
70619093=>'ON',
70629094=>'ON',
70639095=>'ON',
70649096=>'ON',
70659097=>'ON',
70669098=>'ON',
70679099=>'ON',
70689100=>'ON',
70699101=>'ON',
70709102=>'ON',
70719103=>'ON',
70729104=>'ON',
70739105=>'ON',
70749106=>'ON',
70759107=>'ON',
70769108=>'ON',
70779109=>'L',
70789110=>'ON',
70799111=>'ON',
70809112=>'ON',
70819113=>'ON',
70829114=>'ON',
70839115=>'ON',
70849116=>'ON',
70859117=>'ON',
70869118=>'ON',
70879119=>'ON',
70889120=>'ON',
70899121=>'ON',
70909122=>'ON',
70919123=>'ON',
70929124=>'ON',
70939125=>'ON',
70949126=>'ON',
70959127=>'ON',
70969128=>'ON',
70979129=>'ON',
70989130=>'ON',
70999131=>'ON',
71009132=>'ON',
71019133=>'ON',
71029134=>'ON',
71039135=>'ON',
71049136=>'ON',
71059137=>'ON',
71069138=>'ON',
71079139=>'ON',
71089140=>'ON',
71099141=>'ON',
71109142=>'ON',
71119143=>'ON',
71129144=>'ON',
71139145=>'ON',
71149146=>'ON',
71159147=>'ON',
71169148=>'ON',
71179149=>'ON',
71189150=>'ON',
71199151=>'ON',
71209152=>'ON',
71219153=>'ON',
71229154=>'ON',
71239155=>'ON',
71249156=>'ON',
71259157=>'ON',
71269158=>'ON',
71279159=>'ON',
71289160=>'ON',
71299161=>'ON',
71309162=>'ON',
71319163=>'ON',
71329164=>'ON',
71339165=>'ON',
71349166=>'ON',
71359167=>'ON',
71369168=>'ON',
71379169=>'ON',
71389170=>'ON',
71399171=>'ON',
71409172=>'ON',
71419173=>'ON',
71429174=>'ON',
71439175=>'ON',
71449176=>'ON',
71459177=>'ON',
71469178=>'ON',
71479179=>'ON',
71489180=>'ON',
71499181=>'ON',
71509182=>'ON',
71519183=>'ON',
71529184=>'ON',
71539185=>'ON',
71549186=>'ON',
71559187=>'ON',
71569188=>'ON',
71579189=>'ON',
71589190=>'ON',
71599191=>'ON',
71609216=>'ON',
71619217=>'ON',
71629218=>'ON',
71639219=>'ON',
71649220=>'ON',
71659221=>'ON',
71669222=>'ON',
71679223=>'ON',
71689224=>'ON',
71699225=>'ON',
71709226=>'ON',
71719227=>'ON',
71729228=>'ON',
71739229=>'ON',
71749230=>'ON',
71759231=>'ON',
71769232=>'ON',
71779233=>'ON',
71789234=>'ON',
71799235=>'ON',
71809236=>'ON',
71819237=>'ON',
71829238=>'ON',
71839239=>'ON',
71849240=>'ON',
71859241=>'ON',
71869242=>'ON',
71879243=>'ON',
71889244=>'ON',
71899245=>'ON',
71909246=>'ON',
71919247=>'ON',
71929248=>'ON',
71939249=>'ON',
71949250=>'ON',
71959251=>'ON',
71969252=>'ON',
71979253=>'ON',
71989254=>'ON',
71999280=>'ON',
72009281=>'ON',
72019282=>'ON',
72029283=>'ON',
72039284=>'ON',
72049285=>'ON',
72059286=>'ON',
72069287=>'ON',
72079288=>'ON',
72089289=>'ON',
72099290=>'ON',
72109312=>'ON',
72119313=>'ON',
72129314=>'ON',
72139315=>'ON',
72149316=>'ON',
72159317=>'ON',
72169318=>'ON',
72179319=>'ON',
72189320=>'ON',
72199321=>'ON',
72209322=>'ON',
72219323=>'ON',
72229324=>'ON',
72239325=>'ON',
72249326=>'ON',
72259327=>'ON',
72269328=>'ON',
72279329=>'ON',
72289330=>'ON',
72299331=>'ON',
72309332=>'ON',
72319333=>'ON',
72329334=>'ON',
72339335=>'ON',
72349336=>'ON',
72359337=>'ON',
72369338=>'ON',
72379339=>'ON',
72389340=>'ON',
72399341=>'ON',
72409342=>'ON',
72419343=>'ON',
72429344=>'ON',
72439345=>'ON',
72449346=>'ON',
72459347=>'ON',
72469348=>'ON',
72479349=>'ON',
72489350=>'ON',
72499351=>'ON',
72509352=>'EN',
72519353=>'EN',
72529354=>'EN',
72539355=>'EN',
72549356=>'EN',
72559357=>'EN',
72569358=>'EN',
72579359=>'EN',
72589360=>'EN',
72599361=>'EN',
72609362=>'EN',
72619363=>'EN',
72629364=>'EN',
72639365=>'EN',
72649366=>'EN',
72659367=>'EN',
72669368=>'EN',
72679369=>'EN',
72689370=>'EN',
72699371=>'EN',
72709372=>'L',
72719373=>'L',
72729374=>'L',
72739375=>'L',
72749376=>'L',
72759377=>'L',
72769378=>'L',
72779379=>'L',
72789380=>'L',
72799381=>'L',
72809382=>'L',
72819383=>'L',
72829384=>'L',
72839385=>'L',
72849386=>'L',
72859387=>'L',
72869388=>'L',
72879389=>'L',
72889390=>'L',
72899391=>'L',
72909392=>'L',
72919393=>'L',
72929394=>'L',
72939395=>'L',
72949396=>'L',
72959397=>'L',
72969398=>'L',
72979399=>'L',
72989400=>'L',
72999401=>'L',
73009402=>'L',
73019403=>'L',
73029404=>'L',
73039405=>'L',
73049406=>'L',
73059407=>'L',
73069408=>'L',
73079409=>'L',
73089410=>'L',
73099411=>'L',
73109412=>'L',
73119413=>'L',
73129414=>'L',
73139415=>'L',
73149416=>'L',
73159417=>'L',
73169418=>'L',
73179419=>'L',
73189420=>'L',
73199421=>'L',
73209422=>'L',
73219423=>'L',
73229424=>'L',
73239425=>'L',
73249426=>'L',
73259427=>'L',
73269428=>'L',
73279429=>'L',
73289430=>'L',
73299431=>'L',
73309432=>'L',
73319433=>'L',
73329434=>'L',
73339435=>'L',
73349436=>'L',
73359437=>'L',
73369438=>'L',
73379439=>'L',
73389440=>'L',
73399441=>'L',
73409442=>'L',
73419443=>'L',
73429444=>'L',
73439445=>'L',
73449446=>'L',
73459447=>'L',
73469448=>'L',
73479449=>'L',
73489450=>'ON',
73499451=>'ON',
73509452=>'ON',
73519453=>'ON',
73529454=>'ON',
73539455=>'ON',
73549456=>'ON',
73559457=>'ON',
73569458=>'ON',
73579459=>'ON',
73589460=>'ON',
73599461=>'ON',
73609462=>'ON',
73619463=>'ON',
73629464=>'ON',
73639465=>'ON',
73649466=>'ON',
73659467=>'ON',
73669468=>'ON',
73679469=>'ON',
73689470=>'ON',
73699471=>'ON',
73709472=>'ON',
73719473=>'ON',
73729474=>'ON',
73739475=>'ON',
73749476=>'ON',
73759477=>'ON',
73769478=>'ON',
73779479=>'ON',
73789480=>'ON',
73799481=>'ON',
73809482=>'ON',
73819483=>'ON',
73829484=>'ON',
73839485=>'ON',
73849486=>'ON',
73859487=>'ON',
73869488=>'ON',
73879489=>'ON',
73889490=>'ON',
73899491=>'ON',
73909492=>'ON',
73919493=>'ON',
73929494=>'ON',
73939495=>'ON',
73949496=>'ON',
73959497=>'ON',
73969498=>'ON',
73979499=>'ON',
73989500=>'ON',
73999501=>'ON',
74009502=>'ON',
74019503=>'ON',
74029504=>'ON',
74039505=>'ON',
74049506=>'ON',
74059507=>'ON',
74069508=>'ON',
74079509=>'ON',
74089510=>'ON',
74099511=>'ON',
74109512=>'ON',
74119513=>'ON',
74129514=>'ON',
74139515=>'ON',
74149516=>'ON',
74159517=>'ON',
74169518=>'ON',
74179519=>'ON',
74189520=>'ON',
74199521=>'ON',
74209522=>'ON',
74219523=>'ON',
74229524=>'ON',
74239525=>'ON',
74249526=>'ON',
74259527=>'ON',
74269528=>'ON',
74279529=>'ON',
74289530=>'ON',
74299531=>'ON',
74309532=>'ON',
74319533=>'ON',
74329534=>'ON',
74339535=>'ON',
74349536=>'ON',
74359537=>'ON',
74369538=>'ON',
74379539=>'ON',
74389540=>'ON',
74399541=>'ON',
74409542=>'ON',
74419543=>'ON',
74429544=>'ON',
74439545=>'ON',
74449546=>'ON',
74459547=>'ON',
74469548=>'ON',
74479549=>'ON',
74489550=>'ON',
74499551=>'ON',
74509552=>'ON',
74519553=>'ON',
74529554=>'ON',
74539555=>'ON',
74549556=>'ON',
74559557=>'ON',
74569558=>'ON',
74579559=>'ON',
74589560=>'ON',
74599561=>'ON',
74609562=>'ON',
74619563=>'ON',
74629564=>'ON',
74639565=>'ON',
74649566=>'ON',
74659567=>'ON',
74669568=>'ON',
74679569=>'ON',
74689570=>'ON',
74699571=>'ON',
74709572=>'ON',
74719573=>'ON',
74729574=>'ON',
74739575=>'ON',
74749576=>'ON',
74759577=>'ON',
74769578=>'ON',
74779579=>'ON',
74789580=>'ON',
74799581=>'ON',
74809582=>'ON',
74819583=>'ON',
74829584=>'ON',
74839585=>'ON',
74849586=>'ON',
74859587=>'ON',
74869588=>'ON',
74879589=>'ON',
74889590=>'ON',
74899591=>'ON',
74909592=>'ON',
74919593=>'ON',
74929594=>'ON',
74939595=>'ON',
74949596=>'ON',
74959597=>'ON',
74969598=>'ON',
74979599=>'ON',
74989600=>'ON',
74999601=>'ON',
75009602=>'ON',
75019603=>'ON',
75029604=>'ON',
75039605=>'ON',
75049606=>'ON',
75059607=>'ON',
75069608=>'ON',
75079609=>'ON',
75089610=>'ON',
75099611=>'ON',
75109612=>'ON',
75119613=>'ON',
75129614=>'ON',
75139615=>'ON',
75149616=>'ON',
75159617=>'ON',
75169618=>'ON',
75179619=>'ON',
75189620=>'ON',
75199621=>'ON',
75209622=>'ON',
75219623=>'ON',
75229624=>'ON',
75239625=>'ON',
75249626=>'ON',
75259627=>'ON',
75269628=>'ON',
75279629=>'ON',
75289630=>'ON',
75299631=>'ON',
75309632=>'ON',
75319633=>'ON',
75329634=>'ON',
75339635=>'ON',
75349636=>'ON',
75359637=>'ON',
75369638=>'ON',
75379639=>'ON',
75389640=>'ON',
75399641=>'ON',
75409642=>'ON',
75419643=>'ON',
75429644=>'ON',
75439645=>'ON',
75449646=>'ON',
75459647=>'ON',
75469648=>'ON',
75479649=>'ON',
75489650=>'ON',
75499651=>'ON',
75509652=>'ON',
75519653=>'ON',
75529654=>'ON',
75539655=>'ON',
75549656=>'ON',
75559657=>'ON',
75569658=>'ON',
75579659=>'ON',
75589660=>'ON',
75599661=>'ON',
75609662=>'ON',
75619663=>'ON',
75629664=>'ON',
75639665=>'ON',
75649666=>'ON',
75659667=>'ON',
75669668=>'ON',
75679669=>'ON',
75689670=>'ON',
75699671=>'ON',
75709672=>'ON',
75719673=>'ON',
75729674=>'ON',
75739675=>'ON',
75749676=>'ON',
75759677=>'ON',
75769678=>'ON',
75779679=>'ON',
75789680=>'ON',
75799681=>'ON',
75809682=>'ON',
75819683=>'ON',
75829684=>'ON',
75839685=>'ON',
75849686=>'ON',
75859687=>'ON',
75869688=>'ON',
75879689=>'ON',
75889690=>'ON',
75899691=>'ON',
75909692=>'ON',
75919693=>'ON',
75929694=>'ON',
75939695=>'ON',
75949696=>'ON',
75959697=>'ON',
75969698=>'ON',
75979699=>'ON',
75989700=>'ON',
75999701=>'ON',
76009702=>'ON',
76019703=>'ON',
76029704=>'ON',
76039705=>'ON',
76049706=>'ON',
76059707=>'ON',
76069708=>'ON',
76079709=>'ON',
76089710=>'ON',
76099711=>'ON',
76109712=>'ON',
76119713=>'ON',
76129714=>'ON',
76139715=>'ON',
76149716=>'ON',
76159717=>'ON',
76169718=>'ON',
76179719=>'ON',
76189720=>'ON',
76199721=>'ON',
76209722=>'ON',
76219723=>'ON',
76229724=>'ON',
76239725=>'ON',
76249726=>'ON',
76259727=>'ON',
76269728=>'ON',
76279729=>'ON',
76289730=>'ON',
76299731=>'ON',
76309732=>'ON',
76319733=>'ON',
76329734=>'ON',
76339735=>'ON',
76349736=>'ON',
76359737=>'ON',
76369738=>'ON',
76379739=>'ON',
76389740=>'ON',
76399741=>'ON',
76409742=>'ON',
76419743=>'ON',
76429744=>'ON',
76439745=>'ON',
76449746=>'ON',
76459747=>'ON',
76469748=>'ON',
76479749=>'ON',
76489750=>'ON',
76499751=>'ON',
76509752=>'ON',
76519753=>'ON',
76529754=>'ON',
76539755=>'ON',
76549756=>'ON',
76559757=>'ON',
76569758=>'ON',
76579759=>'ON',
76589760=>'ON',
76599761=>'ON',
76609762=>'ON',
76619763=>'ON',
76629764=>'ON',
76639765=>'ON',
76649766=>'ON',
76659767=>'ON',
76669768=>'ON',
76679769=>'ON',
76689770=>'ON',
76699771=>'ON',
76709772=>'ON',
76719773=>'ON',
76729774=>'ON',
76739775=>'ON',
76749776=>'ON',
76759777=>'ON',
76769778=>'ON',
76779779=>'ON',
76789780=>'ON',
76799781=>'ON',
76809782=>'ON',
76819783=>'ON',
76829784=>'ON',
76839785=>'ON',
76849786=>'ON',
76859787=>'ON',
76869788=>'ON',
76879789=>'ON',
76889790=>'ON',
76899791=>'ON',
76909792=>'ON',
76919793=>'ON',
76929794=>'ON',
76939795=>'ON',
76949796=>'ON',
76959797=>'ON',
76969798=>'ON',
76979799=>'ON',
76989800=>'ON',
76999801=>'ON',
77009802=>'ON',
77019803=>'ON',
77029804=>'ON',
77039805=>'ON',
77049806=>'ON',
77059807=>'ON',
77069808=>'ON',
77079809=>'ON',
77089810=>'ON',
77099811=>'ON',
77109812=>'ON',
77119813=>'ON',
77129814=>'ON',
77139815=>'ON',
77149816=>'ON',
77159817=>'ON',
77169818=>'ON',
77179819=>'ON',
77189820=>'ON',
77199821=>'ON',
77209822=>'ON',
77219823=>'ON',
77229824=>'ON',
77239825=>'ON',
77249826=>'ON',
77259827=>'ON',
77269828=>'ON',
77279829=>'ON',
77289830=>'ON',
77299831=>'ON',
77309832=>'ON',
77319833=>'ON',
77329834=>'ON',
77339835=>'ON',
77349836=>'ON',
77359837=>'ON',
77369838=>'ON',
77379839=>'ON',
77389840=>'ON',
77399841=>'ON',
77409842=>'ON',
77419843=>'ON',
77429844=>'ON',
77439845=>'ON',
77449846=>'ON',
77459847=>'ON',
77469848=>'ON',
77479849=>'ON',
77489850=>'ON',
77499851=>'ON',
77509852=>'ON',
77519853=>'ON',
77529854=>'ON',
77539855=>'ON',
77549856=>'ON',
77559857=>'ON',
77569858=>'ON',
77579859=>'ON',
77589860=>'ON',
77599861=>'ON',
77609862=>'ON',
77619863=>'ON',
77629864=>'ON',
77639865=>'ON',
77649866=>'ON',
77659867=>'ON',
77669868=>'ON',
77679869=>'ON',
77689870=>'ON',
77699871=>'ON',
77709872=>'ON',
77719873=>'ON',
77729874=>'ON',
77739875=>'ON',
77749876=>'ON',
77759877=>'ON',
77769878=>'ON',
77779879=>'ON',
77789880=>'ON',
77799881=>'ON',
77809882=>'ON',
77819883=>'ON',
77829884=>'ON',
77839888=>'ON',
77849889=>'ON',
77859890=>'ON',
77869891=>'ON',
77879892=>'ON',
77889893=>'ON',
77899894=>'ON',
77909895=>'ON',
77919896=>'ON',
77929897=>'ON',
77939898=>'ON',
77949899=>'ON',
77959900=>'L',
77969901=>'ON',
77979902=>'ON',
77989903=>'ON',
77999904=>'ON',
78009905=>'ON',
78019906=>'ON',
78029985=>'ON',
78039986=>'ON',
78049987=>'ON',
78059988=>'ON',
78069990=>'ON',
78079991=>'ON',
78089992=>'ON',
78099993=>'ON',
78109996=>'ON',
78119997=>'ON',
78129998=>'ON',
78139999=>'ON',
781410000=>'ON',
781510001=>'ON',
781610002=>'ON',
781710003=>'ON',
781810004=>'ON',
781910005=>'ON',
782010006=>'ON',
782110007=>'ON',
782210008=>'ON',
782310009=>'ON',
782410010=>'ON',
782510011=>'ON',
782610012=>'ON',
782710013=>'ON',
782810014=>'ON',
782910015=>'ON',
783010016=>'ON',
783110017=>'ON',
783210018=>'ON',
783310019=>'ON',
783410020=>'ON',
783510021=>'ON',
783610022=>'ON',
783710023=>'ON',
783810025=>'ON',
783910026=>'ON',
784010027=>'ON',
784110028=>'ON',
784210029=>'ON',
784310030=>'ON',
784410031=>'ON',
784510032=>'ON',
784610033=>'ON',
784710034=>'ON',
784810035=>'ON',
784910036=>'ON',
785010037=>'ON',
785110038=>'ON',
785210039=>'ON',
785310040=>'ON',
785410041=>'ON',
785510042=>'ON',
785610043=>'ON',
785710044=>'ON',
785810045=>'ON',
785910046=>'ON',
786010047=>'ON',
786110048=>'ON',
786210049=>'ON',
786310050=>'ON',
786410051=>'ON',
786510052=>'ON',
786610053=>'ON',
786710054=>'ON',
786810055=>'ON',
786910056=>'ON',
787010057=>'ON',
787110058=>'ON',
787210059=>'ON',
787310061=>'ON',
787410063=>'ON',
787510064=>'ON',
787610065=>'ON',
787710066=>'ON',
787810070=>'ON',
787910072=>'ON',
788010073=>'ON',
788110074=>'ON',
788210075=>'ON',
788310076=>'ON',
788410077=>'ON',
788510078=>'ON',
788610081=>'ON',
788710082=>'ON',
788810083=>'ON',
788910084=>'ON',
789010085=>'ON',
789110086=>'ON',
789210087=>'ON',
789310088=>'ON',
789410089=>'ON',
789510090=>'ON',
789610091=>'ON',
789710092=>'ON',
789810093=>'ON',
789910094=>'ON',
790010095=>'ON',
790110096=>'ON',
790210097=>'ON',
790310098=>'ON',
790410099=>'ON',
790510100=>'ON',
790610101=>'ON',
790710102=>'ON',
790810103=>'ON',
790910104=>'ON',
791010105=>'ON',
791110106=>'ON',
791210107=>'ON',
791310108=>'ON',
791410109=>'ON',
791510110=>'ON',
791610111=>'ON',
791710112=>'ON',
791810113=>'ON',
791910114=>'ON',
792010115=>'ON',
792110116=>'ON',
792210117=>'ON',
792310118=>'ON',
792410119=>'ON',
792510120=>'ON',
792610121=>'ON',
792710122=>'ON',
792810123=>'ON',
792910124=>'ON',
793010125=>'ON',
793110126=>'ON',
793210127=>'ON',
793310128=>'ON',
793410129=>'ON',
793510130=>'ON',
793610131=>'ON',
793710132=>'ON',
793810136=>'ON',
793910137=>'ON',
794010138=>'ON',
794110139=>'ON',
794210140=>'ON',
794310141=>'ON',
794410142=>'ON',
794510143=>'ON',
794610144=>'ON',
794710145=>'ON',
794810146=>'ON',
794910147=>'ON',
795010148=>'ON',
795110149=>'ON',
795210150=>'ON',
795310151=>'ON',
795410152=>'ON',
795510153=>'ON',
795610154=>'ON',
795710155=>'ON',
795810156=>'ON',
795910157=>'ON',
796010158=>'ON',
796110159=>'ON',
796210161=>'ON',
796310162=>'ON',
796410163=>'ON',
796510164=>'ON',
796610165=>'ON',
796710166=>'ON',
796810167=>'ON',
796910168=>'ON',
797010169=>'ON',
797110170=>'ON',
797210171=>'ON',
797310172=>'ON',
797410173=>'ON',
797510174=>'ON',
797610176=>'ON',
797710177=>'ON',
797810178=>'ON',
797910179=>'ON',
798010180=>'ON',
798110181=>'ON',
798210182=>'ON',
798310183=>'ON',
798410184=>'ON',
798510185=>'ON',
798610186=>'ON',
798710192=>'ON',
798810193=>'ON',
798910194=>'ON',
799010195=>'ON',
799110196=>'ON',
799210197=>'ON',
799310198=>'ON',
799410199=>'ON',
799510200=>'ON',
799610201=>'ON',
799710202=>'ON',
799810203=>'ON',
799910204=>'ON',
800010205=>'ON',
800110206=>'ON',
800210207=>'ON',
800310208=>'ON',
800410209=>'ON',
800510210=>'ON',
800610211=>'ON',
800710212=>'ON',
800810213=>'ON',
800910214=>'ON',
801010215=>'ON',
801110216=>'ON',
801210217=>'ON',
801310218=>'ON',
801410219=>'ON',
801510224=>'ON',
801610225=>'ON',
801710226=>'ON',
801810227=>'ON',
801910228=>'ON',
802010229=>'ON',
802110230=>'ON',
802210231=>'ON',
802310232=>'ON',
802410233=>'ON',
802510234=>'ON',
802610235=>'ON',
802710236=>'ON',
802810237=>'ON',
802910238=>'ON',
803010239=>'ON',
803110240=>'L',
803210241=>'L',
803310242=>'L',
803410243=>'L',
803510244=>'L',
803610245=>'L',
803710246=>'L',
803810247=>'L',
803910248=>'L',
804010249=>'L',
804110250=>'L',
804210251=>'L',
804310252=>'L',
804410253=>'L',
804510254=>'L',
804610255=>'L',
804710256=>'L',
804810257=>'L',
804910258=>'L',
805010259=>'L',
805110260=>'L',
805210261=>'L',
805310262=>'L',
805410263=>'L',
805510264=>'L',
805610265=>'L',
805710266=>'L',
805810267=>'L',
805910268=>'L',
806010269=>'L',
806110270=>'L',
806210271=>'L',
806310272=>'L',
806410273=>'L',
806510274=>'L',
806610275=>'L',
806710276=>'L',
806810277=>'L',
806910278=>'L',
807010279=>'L',
807110280=>'L',
807210281=>'L',
807310282=>'L',
807410283=>'L',
807510284=>'L',
807610285=>'L',
807710286=>'L',
807810287=>'L',
807910288=>'L',
808010289=>'L',
808110290=>'L',
808210291=>'L',
808310292=>'L',
808410293=>'L',
808510294=>'L',
808610295=>'L',
808710296=>'L',
808810297=>'L',
808910298=>'L',
809010299=>'L',
809110300=>'L',
809210301=>'L',
809310302=>'L',
809410303=>'L',
809510304=>'L',
809610305=>'L',
809710306=>'L',
809810307=>'L',
809910308=>'L',
810010309=>'L',
810110310=>'L',
810210311=>'L',
810310312=>'L',
810410313=>'L',
810510314=>'L',
810610315=>'L',
810710316=>'L',
810810317=>'L',
810910318=>'L',
811010319=>'L',
811110320=>'L',
811210321=>'L',
811310322=>'L',
811410323=>'L',
811510324=>'L',
811610325=>'L',
811710326=>'L',
811810327=>'L',
811910328=>'L',
812010329=>'L',
812110330=>'L',
812210331=>'L',
812310332=>'L',
812410333=>'L',
812510334=>'L',
812610335=>'L',
812710336=>'L',
812810337=>'L',
812910338=>'L',
813010339=>'L',
813110340=>'L',
813210341=>'L',
813310342=>'L',
813410343=>'L',
813510344=>'L',
813610345=>'L',
813710346=>'L',
813810347=>'L',
813910348=>'L',
814010349=>'L',
814110350=>'L',
814210351=>'L',
814310352=>'L',
814410353=>'L',
814510354=>'L',
814610355=>'L',
814710356=>'L',
814810357=>'L',
814910358=>'L',
815010359=>'L',
815110360=>'L',
815210361=>'L',
815310362=>'L',
815410363=>'L',
815510364=>'L',
815610365=>'L',
815710366=>'L',
815810367=>'L',
815910368=>'L',
816010369=>'L',
816110370=>'L',
816210371=>'L',
816310372=>'L',
816410373=>'L',
816510374=>'L',
816610375=>'L',
816710376=>'L',
816810377=>'L',
816910378=>'L',
817010379=>'L',
817110380=>'L',
817210381=>'L',
817310382=>'L',
817410383=>'L',
817510384=>'L',
817610385=>'L',
817710386=>'L',
817810387=>'L',
817910388=>'L',
818010389=>'L',
818110390=>'L',
818210391=>'L',
818310392=>'L',
818410393=>'L',
818510394=>'L',
818610395=>'L',
818710396=>'L',
818810397=>'L',
818910398=>'L',
819010399=>'L',
819110400=>'L',
819210401=>'L',
819310402=>'L',
819410403=>'L',
819510404=>'L',
819610405=>'L',
819710406=>'L',
819810407=>'L',
819910408=>'L',
820010409=>'L',
820110410=>'L',
820210411=>'L',
820310412=>'L',
820410413=>'L',
820510414=>'L',
820610415=>'L',
820710416=>'L',
820810417=>'L',
820910418=>'L',
821010419=>'L',
821110420=>'L',
821210421=>'L',
821310422=>'L',
821410423=>'L',
821510424=>'L',
821610425=>'L',
821710426=>'L',
821810427=>'L',
821910428=>'L',
822010429=>'L',
822110430=>'L',
822210431=>'L',
822310432=>'L',
822410433=>'L',
822510434=>'L',
822610435=>'L',
822710436=>'L',
822810437=>'L',
822910438=>'L',
823010439=>'L',
823110440=>'L',
823210441=>'L',
823310442=>'L',
823410443=>'L',
823510444=>'L',
823610445=>'L',
823710446=>'L',
823810447=>'L',
823910448=>'L',
824010449=>'L',
824110450=>'L',
824210451=>'L',
824310452=>'L',
824410453=>'L',
824510454=>'L',
824610455=>'L',
824710456=>'L',
824810457=>'L',
824910458=>'L',
825010459=>'L',
825110460=>'L',
825210461=>'L',
825310462=>'L',
825410463=>'L',
825510464=>'L',
825610465=>'L',
825710466=>'L',
825810467=>'L',
825910468=>'L',
826010469=>'L',
826110470=>'L',
826210471=>'L',
826310472=>'L',
826410473=>'L',
826510474=>'L',
826610475=>'L',
826710476=>'L',
826810477=>'L',
826910478=>'L',
827010479=>'L',
827110480=>'L',
827210481=>'L',
827310482=>'L',
827410483=>'L',
827510484=>'L',
827610485=>'L',
827710486=>'L',
827810487=>'L',
827910488=>'L',
828010489=>'L',
828110490=>'L',
828210491=>'L',
828310492=>'L',
828410493=>'L',
828510494=>'L',
828610495=>'L',
828710496=>'ON',
828810497=>'ON',
828910498=>'ON',
829010499=>'ON',
829110500=>'ON',
829210501=>'ON',
829310502=>'ON',
829410503=>'ON',
829510504=>'ON',
829610505=>'ON',
829710506=>'ON',
829810507=>'ON',
829910508=>'ON',
830010509=>'ON',
830110510=>'ON',
830210511=>'ON',
830310512=>'ON',
830410513=>'ON',
830510514=>'ON',
830610515=>'ON',
830710516=>'ON',
830810517=>'ON',
830910518=>'ON',
831010519=>'ON',
831110520=>'ON',
831210521=>'ON',
831310522=>'ON',
831410523=>'ON',
831510524=>'ON',
831610525=>'ON',
831710526=>'ON',
831810527=>'ON',
831910528=>'ON',
832010529=>'ON',
832110530=>'ON',
832210531=>'ON',
832310532=>'ON',
832410533=>'ON',
832510534=>'ON',
832610535=>'ON',
832710536=>'ON',
832810537=>'ON',
832910538=>'ON',
833010539=>'ON',
833110540=>'ON',
833210541=>'ON',
833310542=>'ON',
833410543=>'ON',
833510544=>'ON',
833610545=>'ON',
833710546=>'ON',
833810547=>'ON',
833910548=>'ON',
834010549=>'ON',
834110550=>'ON',
834210551=>'ON',
834310552=>'ON',
834410553=>'ON',
834510554=>'ON',
834610555=>'ON',
834710556=>'ON',
834810557=>'ON',
834910558=>'ON',
835010559=>'ON',
835110560=>'ON',
835210561=>'ON',
835310562=>'ON',
835410563=>'ON',
835510564=>'ON',
835610565=>'ON',
835710566=>'ON',
835810567=>'ON',
835910568=>'ON',
836010569=>'ON',
836110570=>'ON',
836210571=>'ON',
836310572=>'ON',
836410573=>'ON',
836510574=>'ON',
836610575=>'ON',
836710576=>'ON',
836810577=>'ON',
836910578=>'ON',
837010579=>'ON',
837110580=>'ON',
837210581=>'ON',
837310582=>'ON',
837410583=>'ON',
837510584=>'ON',
837610585=>'ON',
837710586=>'ON',
837810587=>'ON',
837910588=>'ON',
838010589=>'ON',
838110590=>'ON',
838210591=>'ON',
838310592=>'ON',
838410593=>'ON',
838510594=>'ON',
838610595=>'ON',
838710596=>'ON',
838810597=>'ON',
838910598=>'ON',
839010599=>'ON',
839110600=>'ON',
839210601=>'ON',
839310602=>'ON',
839410603=>'ON',
839510604=>'ON',
839610605=>'ON',
839710606=>'ON',
839810607=>'ON',
839910608=>'ON',
840010609=>'ON',
840110610=>'ON',
840210611=>'ON',
840310612=>'ON',
840410613=>'ON',
840510614=>'ON',
840610615=>'ON',
840710616=>'ON',
840810617=>'ON',
840910618=>'ON',
841010619=>'ON',
841110620=>'ON',
841210621=>'ON',
841310622=>'ON',
841410623=>'ON',
841510624=>'ON',
841610625=>'ON',
841710626=>'ON',
841810627=>'ON',
841910628=>'ON',
842010629=>'ON',
842110630=>'ON',
842210631=>'ON',
842310632=>'ON',
842410633=>'ON',
842510634=>'ON',
842610635=>'ON',
842710636=>'ON',
842810637=>'ON',
842910638=>'ON',
843010639=>'ON',
843110640=>'ON',
843210641=>'ON',
843310642=>'ON',
843410643=>'ON',
843510644=>'ON',
843610645=>'ON',
843710646=>'ON',
843810647=>'ON',
843910648=>'ON',
844010649=>'ON',
844110650=>'ON',
844210651=>'ON',
844310652=>'ON',
844410653=>'ON',
844510654=>'ON',
844610655=>'ON',
844710656=>'ON',
844810657=>'ON',
844910658=>'ON',
845010659=>'ON',
845110660=>'ON',
845210661=>'ON',
845310662=>'ON',
845410663=>'ON',
845510664=>'ON',
845610665=>'ON',
845710666=>'ON',
845810667=>'ON',
845910668=>'ON',
846010669=>'ON',
846110670=>'ON',
846210671=>'ON',
846310672=>'ON',
846410673=>'ON',
846510674=>'ON',
846610675=>'ON',
846710676=>'ON',
846810677=>'ON',
846910678=>'ON',
847010679=>'ON',
847110680=>'ON',
847210681=>'ON',
847310682=>'ON',
847410683=>'ON',
847510684=>'ON',
847610685=>'ON',
847710686=>'ON',
847810687=>'ON',
847910688=>'ON',
848010689=>'ON',
848110690=>'ON',
848210691=>'ON',
848310692=>'ON',
848410693=>'ON',
848510694=>'ON',
848610695=>'ON',
848710696=>'ON',
848810697=>'ON',
848910698=>'ON',
849010699=>'ON',
849110700=>'ON',
849210701=>'ON',
849310702=>'ON',
849410703=>'ON',
849510704=>'ON',
849610705=>'ON',
849710706=>'ON',
849810707=>'ON',
849910708=>'ON',
850010709=>'ON',
850110710=>'ON',
850210711=>'ON',
850310712=>'ON',
850410713=>'ON',
850510714=>'ON',
850610715=>'ON',
850710716=>'ON',
850810717=>'ON',
850910718=>'ON',
851010719=>'ON',
851110720=>'ON',
851210721=>'ON',
851310722=>'ON',
851410723=>'ON',
851510724=>'ON',
851610725=>'ON',
851710726=>'ON',
851810727=>'ON',
851910728=>'ON',
852010729=>'ON',
852110730=>'ON',
852210731=>'ON',
852310732=>'ON',
852410733=>'ON',
852510734=>'ON',
852610735=>'ON',
852710736=>'ON',
852810737=>'ON',
852910738=>'ON',
853010739=>'ON',
853110740=>'ON',
853210741=>'ON',
853310742=>'ON',
853410743=>'ON',
853510744=>'ON',
853610745=>'ON',
853710746=>'ON',
853810747=>'ON',
853910748=>'ON',
854010749=>'ON',
854110750=>'ON',
854210751=>'ON',
854310752=>'ON',
854410753=>'ON',
854510754=>'ON',
854610755=>'ON',
854710756=>'ON',
854810757=>'ON',
854910758=>'ON',
855010759=>'ON',
855110760=>'ON',
855210761=>'ON',
855310762=>'ON',
855410763=>'ON',
855510764=>'ON',
855610765=>'ON',
855710766=>'ON',
855810767=>'ON',
855910768=>'ON',
856010769=>'ON',
856110770=>'ON',
856210771=>'ON',
856310772=>'ON',
856410773=>'ON',
856510774=>'ON',
856610775=>'ON',
856710776=>'ON',
856810777=>'ON',
856910778=>'ON',
857010779=>'ON',
857110780=>'ON',
857210781=>'ON',
857310782=>'ON',
857410783=>'ON',
857510784=>'ON',
857610785=>'ON',
857710786=>'ON',
857810787=>'ON',
857910788=>'ON',
858010789=>'ON',
858110790=>'ON',
858210791=>'ON',
858310792=>'ON',
858410793=>'ON',
858510794=>'ON',
858610795=>'ON',
858710796=>'ON',
858810797=>'ON',
858910798=>'ON',
859010799=>'ON',
859110800=>'ON',
859210801=>'ON',
859310802=>'ON',
859410803=>'ON',
859510804=>'ON',
859610805=>'ON',
859710806=>'ON',
859810807=>'ON',
859910808=>'ON',
860010809=>'ON',
860110810=>'ON',
860210811=>'ON',
860310812=>'ON',
860410813=>'ON',
860510814=>'ON',
860610815=>'ON',
860710816=>'ON',
860810817=>'ON',
860910818=>'ON',
861010819=>'ON',
861110820=>'ON',
861210821=>'ON',
861310822=>'ON',
861410823=>'ON',
861510824=>'ON',
861610825=>'ON',
861710826=>'ON',
861810827=>'ON',
861910828=>'ON',
862010829=>'ON',
862110830=>'ON',
862210831=>'ON',
862310832=>'ON',
862410833=>'ON',
862510834=>'ON',
862610835=>'ON',
862710836=>'ON',
862810837=>'ON',
862910838=>'ON',
863010839=>'ON',
863110840=>'ON',
863210841=>'ON',
863310842=>'ON',
863410843=>'ON',
863510844=>'ON',
863610845=>'ON',
863710846=>'ON',
863810847=>'ON',
863910848=>'ON',
864010849=>'ON',
864110850=>'ON',
864210851=>'ON',
864310852=>'ON',
864410853=>'ON',
864510854=>'ON',
864610855=>'ON',
864710856=>'ON',
864810857=>'ON',
864910858=>'ON',
865010859=>'ON',
865110860=>'ON',
865210861=>'ON',
865310862=>'ON',
865410863=>'ON',
865510864=>'ON',
865610865=>'ON',
865710866=>'ON',
865810867=>'ON',
865910868=>'ON',
866010869=>'ON',
866110870=>'ON',
866210871=>'ON',
866310872=>'ON',
866410873=>'ON',
866510874=>'ON',
866610875=>'ON',
866710876=>'ON',
866810877=>'ON',
866910878=>'ON',
867010879=>'ON',
867110880=>'ON',
867210881=>'ON',
867310882=>'ON',
867410883=>'ON',
867510884=>'ON',
867610885=>'ON',
867710886=>'ON',
867810887=>'ON',
867910888=>'ON',
868010889=>'ON',
868110890=>'ON',
868210891=>'ON',
868310892=>'ON',
868410893=>'ON',
868510894=>'ON',
868610895=>'ON',
868710896=>'ON',
868810897=>'ON',
868910898=>'ON',
869010899=>'ON',
869110900=>'ON',
869210901=>'ON',
869310902=>'ON',
869410903=>'ON',
869510904=>'ON',
869610905=>'ON',
869710906=>'ON',
869810907=>'ON',
869910908=>'ON',
870010909=>'ON',
870110910=>'ON',
870210911=>'ON',
870310912=>'ON',
870410913=>'ON',
870510914=>'ON',
870610915=>'ON',
870710916=>'ON',
870810917=>'ON',
870910918=>'ON',
871010919=>'ON',
871110920=>'ON',
871210921=>'ON',
871310922=>'ON',
871410923=>'ON',
871510924=>'ON',
871610925=>'ON',
871710926=>'ON',
871810927=>'ON',
871910928=>'ON',
872010929=>'ON',
872110930=>'ON',
872210931=>'ON',
872310932=>'ON',
872410933=>'ON',
872510934=>'ON',
872610935=>'ON',
872710936=>'ON',
872810937=>'ON',
872910938=>'ON',
873010939=>'ON',
873110940=>'ON',
873210941=>'ON',
873310942=>'ON',
873410943=>'ON',
873510944=>'ON',
873610945=>'ON',
873710946=>'ON',
873810947=>'ON',
873910948=>'ON',
874010949=>'ON',
874110950=>'ON',
874210951=>'ON',
874310952=>'ON',
874410953=>'ON',
874510954=>'ON',
874610955=>'ON',
874710956=>'ON',
874810957=>'ON',
874910958=>'ON',
875010959=>'ON',
875110960=>'ON',
875210961=>'ON',
875310962=>'ON',
875410963=>'ON',
875510964=>'ON',
875610965=>'ON',
875710966=>'ON',
875810967=>'ON',
875910968=>'ON',
876010969=>'ON',
876110970=>'ON',
876210971=>'ON',
876310972=>'ON',
876410973=>'ON',
876510974=>'ON',
876610975=>'ON',
876710976=>'ON',
876810977=>'ON',
876910978=>'ON',
877010979=>'ON',
877110980=>'ON',
877210981=>'ON',
877310982=>'ON',
877410983=>'ON',
877510984=>'ON',
877610985=>'ON',
877710986=>'ON',
877810987=>'ON',
877910988=>'ON',
878010989=>'ON',
878110990=>'ON',
878210991=>'ON',
878310992=>'ON',
878410993=>'ON',
878510994=>'ON',
878610995=>'ON',
878710996=>'ON',
878810997=>'ON',
878910998=>'ON',
879010999=>'ON',
879111000=>'ON',
879211001=>'ON',
879311002=>'ON',
879411003=>'ON',
879511004=>'ON',
879611005=>'ON',
879711006=>'ON',
879811007=>'ON',
879911008=>'ON',
880011009=>'ON',
880111010=>'ON',
880211011=>'ON',
880311012=>'ON',
880411013=>'ON',
880511014=>'ON',
880611015=>'ON',
880711016=>'ON',
880811017=>'ON',
880911018=>'ON',
881011019=>'ON',
881111020=>'ON',
881211021=>'ON',
881311022=>'ON',
881411023=>'ON',
881511024=>'ON',
881611025=>'ON',
881711026=>'ON',
881811027=>'ON',
881911028=>'ON',
882011029=>'ON',
882111030=>'ON',
882211031=>'ON',
882311032=>'ON',
882411033=>'ON',
882511034=>'ON',
882611040=>'ON',
882711041=>'ON',
882811042=>'ON',
882911043=>'ON',
883011264=>'L',
883111265=>'L',
883211266=>'L',
883311267=>'L',
883411268=>'L',
883511269=>'L',
883611270=>'L',
883711271=>'L',
883811272=>'L',
883911273=>'L',
884011274=>'L',
884111275=>'L',
884211276=>'L',
884311277=>'L',
884411278=>'L',
884511279=>'L',
884611280=>'L',
884711281=>'L',
884811282=>'L',
884911283=>'L',
885011284=>'L',
885111285=>'L',
885211286=>'L',
885311287=>'L',
885411288=>'L',
885511289=>'L',
885611290=>'L',
885711291=>'L',
885811292=>'L',
885911293=>'L',
886011294=>'L',
886111295=>'L',
886211296=>'L',
886311297=>'L',
886411298=>'L',
886511299=>'L',
886611300=>'L',
886711301=>'L',
886811302=>'L',
886911303=>'L',
887011304=>'L',
887111305=>'L',
887211306=>'L',
887311307=>'L',
887411308=>'L',
887511309=>'L',
887611310=>'L',
887711312=>'L',
887811313=>'L',
887911314=>'L',
888011315=>'L',
888111316=>'L',
888211317=>'L',
888311318=>'L',
888411319=>'L',
888511320=>'L',
888611321=>'L',
888711322=>'L',
888811323=>'L',
888911324=>'L',
889011325=>'L',
889111326=>'L',
889211327=>'L',
889311328=>'L',
889411329=>'L',
889511330=>'L',
889611331=>'L',
889711332=>'L',
889811333=>'L',
889911334=>'L',
890011335=>'L',
890111336=>'L',
890211337=>'L',
890311338=>'L',
890411339=>'L',
890511340=>'L',
890611341=>'L',
890711342=>'L',
890811343=>'L',
890911344=>'L',
891011345=>'L',
891111346=>'L',
891211347=>'L',
891311348=>'L',
891411349=>'L',
891511350=>'L',
891611351=>'L',
891711352=>'L',
891811353=>'L',
891911354=>'L',
892011355=>'L',
892111356=>'L',
892211357=>'L',
892311358=>'L',
892411360=>'L',
892511361=>'L',
892611362=>'L',
892711363=>'L',
892811364=>'L',
892911365=>'L',
893011366=>'L',
893111367=>'L',
893211368=>'L',
893311369=>'L',
893411370=>'L',
893511371=>'L',
893611372=>'L',
893711380=>'L',
893811381=>'L',
893911382=>'L',
894011383=>'L',
894111392=>'L',
894211393=>'L',
894311394=>'L',
894411395=>'L',
894511396=>'L',
894611397=>'L',
894711398=>'L',
894811399=>'L',
894911400=>'L',
895011401=>'L',
895111402=>'L',
895211403=>'L',
895311404=>'L',
895411405=>'L',
895511406=>'L',
895611407=>'L',
895711408=>'L',
895811409=>'L',
895911410=>'L',
896011411=>'L',
896111412=>'L',
896211413=>'L',
896311414=>'L',
896411415=>'L',
896511416=>'L',
896611417=>'L',
896711418=>'L',
896811419=>'L',
896911420=>'L',
897011421=>'L',
897111422=>'L',
897211423=>'L',
897311424=>'L',
897411425=>'L',
897511426=>'L',
897611427=>'L',
897711428=>'L',
897811429=>'L',
897911430=>'L',
898011431=>'L',
898111432=>'L',
898211433=>'L',
898311434=>'L',
898411435=>'L',
898511436=>'L',
898611437=>'L',
898711438=>'L',
898811439=>'L',
898911440=>'L',
899011441=>'L',
899111442=>'L',
899211443=>'L',
899311444=>'L',
899411445=>'L',
899511446=>'L',
899611447=>'L',
899711448=>'L',
899811449=>'L',
899911450=>'L',
900011451=>'L',
900111452=>'L',
900211453=>'L',
900311454=>'L',
900411455=>'L',
900511456=>'L',
900611457=>'L',
900711458=>'L',
900811459=>'L',
900911460=>'L',
901011461=>'L',
901111462=>'L',
901211463=>'L',
901311464=>'L',
901411465=>'L',
901511466=>'L',
901611467=>'L',
901711468=>'L',
901811469=>'L',
901911470=>'L',
902011471=>'L',
902111472=>'L',
902211473=>'L',
902311474=>'L',
902411475=>'L',
902511476=>'L',
902611477=>'L',
902711478=>'L',
902811479=>'L',
902911480=>'L',
903011481=>'L',
903111482=>'L',
903211483=>'L',
903311484=>'L',
903411485=>'L',
903511486=>'L',
903611487=>'L',
903711488=>'L',
903811489=>'L',
903911490=>'L',
904011491=>'L',
904111492=>'L',
904211493=>'ON',
904311494=>'ON',
904411495=>'ON',
904511496=>'ON',
904611497=>'ON',
904711498=>'ON',
904811513=>'ON',
904911514=>'ON',
905011515=>'ON',
905111516=>'ON',
905211517=>'ON',
905311518=>'ON',
905411519=>'ON',
905511520=>'L',
905611521=>'L',
905711522=>'L',
905811523=>'L',
905911524=>'L',
906011525=>'L',
906111526=>'L',
906211527=>'L',
906311528=>'L',
906411529=>'L',
906511530=>'L',
906611531=>'L',
906711532=>'L',
906811533=>'L',
906911534=>'L',
907011535=>'L',
907111536=>'L',
907211537=>'L',
907311538=>'L',
907411539=>'L',
907511540=>'L',
907611541=>'L',
907711542=>'L',
907811543=>'L',
907911544=>'L',
908011545=>'L',
908111546=>'L',
908211547=>'L',
908311548=>'L',
908411549=>'L',
908511550=>'L',
908611551=>'L',
908711552=>'L',
908811553=>'L',
908911554=>'L',
909011555=>'L',
909111556=>'L',
909211557=>'L',
909311568=>'L',
909411569=>'L',
909511570=>'L',
909611571=>'L',
909711572=>'L',
909811573=>'L',
909911574=>'L',
910011575=>'L',
910111576=>'L',
910211577=>'L',
910311578=>'L',
910411579=>'L',
910511580=>'L',
910611581=>'L',
910711582=>'L',
910811583=>'L',
910911584=>'L',
911011585=>'L',
911111586=>'L',
911211587=>'L',
911311588=>'L',
911411589=>'L',
911511590=>'L',
911611591=>'L',
911711592=>'L',
911811593=>'L',
911911594=>'L',
912011595=>'L',
912111596=>'L',
912211597=>'L',
912311598=>'L',
912411599=>'L',
912511600=>'L',
912611601=>'L',
912711602=>'L',
912811603=>'L',
912911604=>'L',
913011605=>'L',
913111606=>'L',
913211607=>'L',
913311608=>'L',
913411609=>'L',
913511610=>'L',
913611611=>'L',
913711612=>'L',
913811613=>'L',
913911614=>'L',
914011615=>'L',
914111616=>'L',
914211617=>'L',
914311618=>'L',
914411619=>'L',
914511620=>'L',
914611621=>'L',
914711631=>'L',
914811648=>'L',
914911649=>'L',
915011650=>'L',
915111651=>'L',
915211652=>'L',
915311653=>'L',
915411654=>'L',
915511655=>'L',
915611656=>'L',
915711657=>'L',
915811658=>'L',
915911659=>'L',
916011660=>'L',
916111661=>'L',
916211662=>'L',
916311663=>'L',
916411664=>'L',
916511665=>'L',
916611666=>'L',
916711667=>'L',
916811668=>'L',
916911669=>'L',
917011670=>'L',
917111680=>'L',
917211681=>'L',
917311682=>'L',
917411683=>'L',
917511684=>'L',
917611685=>'L',
917711686=>'L',
917811688=>'L',
917911689=>'L',
918011690=>'L',
918111691=>'L',
918211692=>'L',
918311693=>'L',
918411694=>'L',
918511696=>'L',
918611697=>'L',
918711698=>'L',
918811699=>'L',
918911700=>'L',
919011701=>'L',
919111702=>'L',
919211704=>'L',
919311705=>'L',
919411706=>'L',
919511707=>'L',
919611708=>'L',
919711709=>'L',
919811710=>'L',
919911712=>'L',
920011713=>'L',
920111714=>'L',
920211715=>'L',
920311716=>'L',
920411717=>'L',
920511718=>'L',
920611720=>'L',
920711721=>'L',
920811722=>'L',
920911723=>'L',
921011724=>'L',
921111725=>'L',
921211726=>'L',
921311728=>'L',
921411729=>'L',
921511730=>'L',
921611731=>'L',
921711732=>'L',
921811733=>'L',
921911734=>'L',
922011736=>'L',
922111737=>'L',
922211738=>'L',
922311739=>'L',
922411740=>'L',
922511741=>'L',
922611742=>'L',
922711776=>'ON',
922811777=>'ON',
922911778=>'ON',
923011779=>'ON',
923111780=>'ON',
923211781=>'ON',
923311782=>'ON',
923411783=>'ON',
923511784=>'ON',
923611785=>'ON',
923711786=>'ON',
923811787=>'ON',
923911788=>'ON',
924011789=>'ON',
924111790=>'ON',
924211791=>'ON',
924311792=>'ON',
924411793=>'ON',
924511794=>'ON',
924611795=>'ON',
924711796=>'ON',
924811797=>'ON',
924911798=>'ON',
925011799=>'ON',
925111804=>'ON',
925211805=>'ON',
925311904=>'ON',
925411905=>'ON',
925511906=>'ON',
925611907=>'ON',
925711908=>'ON',
925811909=>'ON',
925911910=>'ON',
926011911=>'ON',
926111912=>'ON',
926211913=>'ON',
926311914=>'ON',
926411915=>'ON',
926511916=>'ON',
926611917=>'ON',
926711918=>'ON',
926811919=>'ON',
926911920=>'ON',
927011921=>'ON',
927111922=>'ON',
927211923=>'ON',
927311924=>'ON',
927411925=>'ON',
927511926=>'ON',
927611927=>'ON',
927711928=>'ON',
927811929=>'ON',
927911931=>'ON',
928011932=>'ON',
928111933=>'ON',
928211934=>'ON',
928311935=>'ON',
928411936=>'ON',
928511937=>'ON',
928611938=>'ON',
928711939=>'ON',
928811940=>'ON',
928911941=>'ON',
929011942=>'ON',
929111943=>'ON',
929211944=>'ON',
929311945=>'ON',
929411946=>'ON',
929511947=>'ON',
929611948=>'ON',
929711949=>'ON',
929811950=>'ON',
929911951=>'ON',
930011952=>'ON',
930111953=>'ON',
930211954=>'ON',
930311955=>'ON',
930411956=>'ON',
930511957=>'ON',
930611958=>'ON',
930711959=>'ON',
930811960=>'ON',
930911961=>'ON',
931011962=>'ON',
931111963=>'ON',
931211964=>'ON',
931311965=>'ON',
931411966=>'ON',
931511967=>'ON',
931611968=>'ON',
931711969=>'ON',
931811970=>'ON',
931911971=>'ON',
932011972=>'ON',
932111973=>'ON',
932211974=>'ON',
932311975=>'ON',
932411976=>'ON',
932511977=>'ON',
932611978=>'ON',
932711979=>'ON',
932811980=>'ON',
932911981=>'ON',
933011982=>'ON',
933111983=>'ON',
933211984=>'ON',
933311985=>'ON',
933411986=>'ON',
933511987=>'ON',
933611988=>'ON',
933711989=>'ON',
933811990=>'ON',
933911991=>'ON',
934011992=>'ON',
934111993=>'ON',
934211994=>'ON',
934311995=>'ON',
934411996=>'ON',
934511997=>'ON',
934611998=>'ON',
934711999=>'ON',
934812000=>'ON',
934912001=>'ON',
935012002=>'ON',
935112003=>'ON',
935212004=>'ON',
935312005=>'ON',
935412006=>'ON',
935512007=>'ON',
935612008=>'ON',
935712009=>'ON',
935812010=>'ON',
935912011=>'ON',
936012012=>'ON',
936112013=>'ON',
936212014=>'ON',
936312015=>'ON',
936412016=>'ON',
936512017=>'ON',
936612018=>'ON',
936712019=>'ON',
936812032=>'ON',
936912033=>'ON',
937012034=>'ON',
937112035=>'ON',
937212036=>'ON',
937312037=>'ON',
937412038=>'ON',
937512039=>'ON',
937612040=>'ON',
937712041=>'ON',
937812042=>'ON',
937912043=>'ON',
938012044=>'ON',
938112045=>'ON',
938212046=>'ON',
938312047=>'ON',
938412048=>'ON',
938512049=>'ON',
938612050=>'ON',
938712051=>'ON',
938812052=>'ON',
938912053=>'ON',
939012054=>'ON',
939112055=>'ON',
939212056=>'ON',
939312057=>'ON',
939412058=>'ON',
939512059=>'ON',
939612060=>'ON',
939712061=>'ON',
939812062=>'ON',
939912063=>'ON',
940012064=>'ON',
940112065=>'ON',
940212066=>'ON',
940312067=>'ON',
940412068=>'ON',
940512069=>'ON',
940612070=>'ON',
940712071=>'ON',
940812072=>'ON',
940912073=>'ON',
941012074=>'ON',
941112075=>'ON',
941212076=>'ON',
941312077=>'ON',
941412078=>'ON',
941512079=>'ON',
941612080=>'ON',
941712081=>'ON',
941812082=>'ON',
941912083=>'ON',
942012084=>'ON',
942112085=>'ON',
942212086=>'ON',
942312087=>'ON',
942412088=>'ON',
942512089=>'ON',
942612090=>'ON',
942712091=>'ON',
942812092=>'ON',
942912093=>'ON',
943012094=>'ON',
943112095=>'ON',
943212096=>'ON',
943312097=>'ON',
943412098=>'ON',
943512099=>'ON',
943612100=>'ON',
943712101=>'ON',
943812102=>'ON',
943912103=>'ON',
944012104=>'ON',
944112105=>'ON',
944212106=>'ON',
944312107=>'ON',
944412108=>'ON',
944512109=>'ON',
944612110=>'ON',
944712111=>'ON',
944812112=>'ON',
944912113=>'ON',
945012114=>'ON',
945112115=>'ON',
945212116=>'ON',
945312117=>'ON',
945412118=>'ON',
945512119=>'ON',
945612120=>'ON',
945712121=>'ON',
945812122=>'ON',
945912123=>'ON',
946012124=>'ON',
946112125=>'ON',
946212126=>'ON',
946312127=>'ON',
946412128=>'ON',
946512129=>'ON',
946612130=>'ON',
946712131=>'ON',
946812132=>'ON',
946912133=>'ON',
947012134=>'ON',
947112135=>'ON',
947212136=>'ON',
947312137=>'ON',
947412138=>'ON',
947512139=>'ON',
947612140=>'ON',
947712141=>'ON',
947812142=>'ON',
947912143=>'ON',
948012144=>'ON',
948112145=>'ON',
948212146=>'ON',
948312147=>'ON',
948412148=>'ON',
948512149=>'ON',
948612150=>'ON',
948712151=>'ON',
948812152=>'ON',
948912153=>'ON',
949012154=>'ON',
949112155=>'ON',
949212156=>'ON',
949312157=>'ON',
949412158=>'ON',
949512159=>'ON',
949612160=>'ON',
949712161=>'ON',
949812162=>'ON',
949912163=>'ON',
950012164=>'ON',
950112165=>'ON',
950212166=>'ON',
950312167=>'ON',
950412168=>'ON',
950512169=>'ON',
950612170=>'ON',
950712171=>'ON',
950812172=>'ON',
950912173=>'ON',
951012174=>'ON',
951112175=>'ON',
951212176=>'ON',
951312177=>'ON',
951412178=>'ON',
951512179=>'ON',
951612180=>'ON',
951712181=>'ON',
951812182=>'ON',
951912183=>'ON',
952012184=>'ON',
952112185=>'ON',
952212186=>'ON',
952312187=>'ON',
952412188=>'ON',
952512189=>'ON',
952612190=>'ON',
952712191=>'ON',
952812192=>'ON',
952912193=>'ON',
953012194=>'ON',
953112195=>'ON',
953212196=>'ON',
953312197=>'ON',
953412198=>'ON',
953512199=>'ON',
953612200=>'ON',
953712201=>'ON',
953812202=>'ON',
953912203=>'ON',
954012204=>'ON',
954112205=>'ON',
954212206=>'ON',
954312207=>'ON',
954412208=>'ON',
954512209=>'ON',
954612210=>'ON',
954712211=>'ON',
954812212=>'ON',
954912213=>'ON',
955012214=>'ON',
955112215=>'ON',
955212216=>'ON',
955312217=>'ON',
955412218=>'ON',
955512219=>'ON',
955612220=>'ON',
955712221=>'ON',
955812222=>'ON',
955912223=>'ON',
956012224=>'ON',
956112225=>'ON',
956212226=>'ON',
956312227=>'ON',
956412228=>'ON',
956512229=>'ON',
956612230=>'ON',
956712231=>'ON',
956812232=>'ON',
956912233=>'ON',
957012234=>'ON',
957112235=>'ON',
957212236=>'ON',
957312237=>'ON',
957412238=>'ON',
957512239=>'ON',
957612240=>'ON',
957712241=>'ON',
957812242=>'ON',
957912243=>'ON',
958012244=>'ON',
958112245=>'ON',
958212272=>'ON',
958312273=>'ON',
958412274=>'ON',
958512275=>'ON',
958612276=>'ON',
958712277=>'ON',
958812278=>'ON',
958912279=>'ON',
959012280=>'ON',
959112281=>'ON',
959212282=>'ON',
959312283=>'ON',
959412288=>'WS',
959512289=>'ON',
959612290=>'ON',
959712291=>'ON',
959812292=>'ON',
959912293=>'L',
960012294=>'L',
960112295=>'L',
960212296=>'ON',
960312297=>'ON',
960412298=>'ON',
960512299=>'ON',
960612300=>'ON',
960712301=>'ON',
960812302=>'ON',
960912303=>'ON',
961012304=>'ON',
961112305=>'ON',
961212306=>'ON',
961312307=>'ON',
961412308=>'ON',
961512309=>'ON',
961612310=>'ON',
961712311=>'ON',
961812312=>'ON',
961912313=>'ON',
962012314=>'ON',
962112315=>'ON',
962212316=>'ON',
962312317=>'ON',
962412318=>'ON',
962512319=>'ON',
962612320=>'ON',
962712321=>'L',
962812322=>'L',
962912323=>'L',
963012324=>'L',
963112325=>'L',
963212326=>'L',
963312327=>'L',
963412328=>'L',
963512329=>'L',
963612330=>'NSM',
963712331=>'NSM',
963812332=>'NSM',
963912333=>'NSM',
964012334=>'NSM',
964112335=>'NSM',
964212336=>'ON',
964312337=>'L',
964412338=>'L',
964512339=>'L',
964612340=>'L',
964712341=>'L',
964812342=>'ON',
964912343=>'ON',
965012344=>'L',
965112345=>'L',
965212346=>'L',
965312347=>'L',
965412348=>'L',
965512349=>'ON',
965612350=>'ON',
965712351=>'ON',
965812353=>'L',
965912354=>'L',
966012355=>'L',
966112356=>'L',
966212357=>'L',
966312358=>'L',
966412359=>'L',
966512360=>'L',
966612361=>'L',
966712362=>'L',
966812363=>'L',
966912364=>'L',
967012365=>'L',
967112366=>'L',
967212367=>'L',
967312368=>'L',
967412369=>'L',
967512370=>'L',
967612371=>'L',
967712372=>'L',
967812373=>'L',
967912374=>'L',
968012375=>'L',
968112376=>'L',
968212377=>'L',
968312378=>'L',
968412379=>'L',
968512380=>'L',
968612381=>'L',
968712382=>'L',
968812383=>'L',
968912384=>'L',
969012385=>'L',
969112386=>'L',
969212387=>'L',
969312388=>'L',
969412389=>'L',
969512390=>'L',
969612391=>'L',
969712392=>'L',
969812393=>'L',
969912394=>'L',
970012395=>'L',
970112396=>'L',
970212397=>'L',
970312398=>'L',
970412399=>'L',
970512400=>'L',
970612401=>'L',
970712402=>'L',
970812403=>'L',
970912404=>'L',
971012405=>'L',
971112406=>'L',
971212407=>'L',
971312408=>'L',
971412409=>'L',
971512410=>'L',
971612411=>'L',
971712412=>'L',
971812413=>'L',
971912414=>'L',
972012415=>'L',
972112416=>'L',
972212417=>'L',
972312418=>'L',
972412419=>'L',
972512420=>'L',
972612421=>'L',
972712422=>'L',
972812423=>'L',
972912424=>'L',
973012425=>'L',
973112426=>'L',
973212427=>'L',
973312428=>'L',
973412429=>'L',
973512430=>'L',
973612431=>'L',
973712432=>'L',
973812433=>'L',
973912434=>'L',
974012435=>'L',
974112436=>'L',
974212437=>'L',
974312438=>'L',
974412441=>'NSM',
974512442=>'NSM',
974612443=>'ON',
974712444=>'ON',
974812445=>'L',
974912446=>'L',
975012447=>'L',
975112448=>'ON',
975212449=>'L',
975312450=>'L',
975412451=>'L',
975512452=>'L',
975612453=>'L',
975712454=>'L',
975812455=>'L',
975912456=>'L',
976012457=>'L',
976112458=>'L',
976212459=>'L',
976312460=>'L',
976412461=>'L',
976512462=>'L',
976612463=>'L',
976712464=>'L',
976812465=>'L',
976912466=>'L',
977012467=>'L',
977112468=>'L',
977212469=>'L',
977312470=>'L',
977412471=>'L',
977512472=>'L',
977612473=>'L',
977712474=>'L',
977812475=>'L',
977912476=>'L',
978012477=>'L',
978112478=>'L',
978212479=>'L',
978312480=>'L',
978412481=>'L',
978512482=>'L',
978612483=>'L',
978712484=>'L',
978812485=>'L',
978912486=>'L',
979012487=>'L',
979112488=>'L',
979212489=>'L',
979312490=>'L',
979412491=>'L',
979512492=>'L',
979612493=>'L',
979712494=>'L',
979812495=>'L',
979912496=>'L',
980012497=>'L',
980112498=>'L',
980212499=>'L',
980312500=>'L',
980412501=>'L',
980512502=>'L',
980612503=>'L',
980712504=>'L',
980812505=>'L',
980912506=>'L',
981012507=>'L',
981112508=>'L',
981212509=>'L',
981312510=>'L',
981412511=>'L',
981512512=>'L',
981612513=>'L',
981712514=>'L',
981812515=>'L',
981912516=>'L',
982012517=>'L',
982112518=>'L',
982212519=>'L',
982312520=>'L',
982412521=>'L',
982512522=>'L',
982612523=>'L',
982712524=>'L',
982812525=>'L',
982912526=>'L',
983012527=>'L',
983112528=>'L',
983212529=>'L',
983312530=>'L',
983412531=>'L',
983512532=>'L',
983612533=>'L',
983712534=>'L',
983812535=>'L',
983912536=>'L',
984012537=>'L',
984112538=>'L',
984212539=>'ON',
984312540=>'L',
984412541=>'L',
984512542=>'L',
984612543=>'L',
984712549=>'L',
984812550=>'L',
984912551=>'L',
985012552=>'L',
985112553=>'L',
985212554=>'L',
985312555=>'L',
985412556=>'L',
985512557=>'L',
985612558=>'L',
985712559=>'L',
985812560=>'L',
985912561=>'L',
986012562=>'L',
986112563=>'L',
986212564=>'L',
986312565=>'L',
986412566=>'L',
986512567=>'L',
986612568=>'L',
986712569=>'L',
986812570=>'L',
986912571=>'L',
987012572=>'L',
987112573=>'L',
987212574=>'L',
987312575=>'L',
987412576=>'L',
987512577=>'L',
987612578=>'L',
987712579=>'L',
987812580=>'L',
987912581=>'L',
988012582=>'L',
988112583=>'L',
988212584=>'L',
988312585=>'L',
988412586=>'L',
988512587=>'L',
988612588=>'L',
988712593=>'L',
988812594=>'L',
988912595=>'L',
989012596=>'L',
989112597=>'L',
989212598=>'L',
989312599=>'L',
989412600=>'L',
989512601=>'L',
989612602=>'L',
989712603=>'L',
989812604=>'L',
989912605=>'L',
990012606=>'L',
990112607=>'L',
990212608=>'L',
990312609=>'L',
990412610=>'L',
990512611=>'L',
990612612=>'L',
990712613=>'L',
990812614=>'L',
990912615=>'L',
991012616=>'L',
991112617=>'L',
991212618=>'L',
991312619=>'L',
991412620=>'L',
991512621=>'L',
991612622=>'L',
991712623=>'L',
991812624=>'L',
991912625=>'L',
992012626=>'L',
992112627=>'L',
992212628=>'L',
992312629=>'L',
992412630=>'L',
992512631=>'L',
992612632=>'L',
992712633=>'L',
992812634=>'L',
992912635=>'L',
993012636=>'L',
993112637=>'L',
993212638=>'L',
993312639=>'L',
993412640=>'L',
993512641=>'L',
993612642=>'L',
993712643=>'L',
993812644=>'L',
993912645=>'L',
994012646=>'L',
994112647=>'L',
994212648=>'L',
994312649=>'L',
994412650=>'L',
994512651=>'L',
994612652=>'L',
994712653=>'L',
994812654=>'L',
994912655=>'L',
995012656=>'L',
995112657=>'L',
995212658=>'L',
995312659=>'L',
995412660=>'L',
995512661=>'L',
995612662=>'L',
995712663=>'L',
995812664=>'L',
995912665=>'L',
996012666=>'L',
996112667=>'L',
996212668=>'L',
996312669=>'L',
996412670=>'L',
996512671=>'L',
996612672=>'L',
996712673=>'L',
996812674=>'L',
996912675=>'L',
997012676=>'L',
997112677=>'L',
997212678=>'L',
997312679=>'L',
997412680=>'L',
997512681=>'L',
997612682=>'L',
997712683=>'L',
997812684=>'L',
997912685=>'L',
998012686=>'L',
998112688=>'L',
998212689=>'L',
998312690=>'L',
998412691=>'L',
998512692=>'L',
998612693=>'L',
998712694=>'L',
998812695=>'L',
998912696=>'L',
999012697=>'L',
999112698=>'L',
999212699=>'L',
999312700=>'L',
999412701=>'L',
999512702=>'L',
999612703=>'L',
999712704=>'L',
999812705=>'L',
999912706=>'L',
1000012707=>'L',
1000112708=>'L',
1000212709=>'L',
1000312710=>'L',
1000412711=>'L',
1000512712=>'L',
1000612713=>'L',
1000712714=>'L',
1000812715=>'L',
1000912716=>'L',
1001012717=>'L',
1001112718=>'L',
1001212719=>'L',
1001312720=>'L',
1001412721=>'L',
1001512722=>'L',
1001612723=>'L',
1001712724=>'L',
1001812725=>'L',
1001912726=>'L',
1002012727=>'L',
1002112736=>'ON',
1002212737=>'ON',
1002312738=>'ON',
1002412739=>'ON',
1002512740=>'ON',
1002612741=>'ON',
1002712742=>'ON',
1002812743=>'ON',
1002912744=>'ON',
1003012745=>'ON',
1003112746=>'ON',
1003212747=>'ON',
1003312748=>'ON',
1003412749=>'ON',
1003512750=>'ON',
1003612751=>'ON',
1003712784=>'L',
1003812785=>'L',
1003912786=>'L',
1004012787=>'L',
1004112788=>'L',
1004212789=>'L',
1004312790=>'L',
1004412791=>'L',
1004512792=>'L',
1004612793=>'L',
1004712794=>'L',
1004812795=>'L',
1004912796=>'L',
1005012797=>'L',
1005112798=>'L',
1005212799=>'L',
1005312800=>'L',
1005412801=>'L',
1005512802=>'L',
1005612803=>'L',
1005712804=>'L',
1005812805=>'L',
1005912806=>'L',
1006012807=>'L',
1006112808=>'L',
1006212809=>'L',
1006312810=>'L',
1006412811=>'L',
1006512812=>'L',
1006612813=>'L',
1006712814=>'L',
1006812815=>'L',
1006912816=>'L',
1007012817=>'L',
1007112818=>'L',
1007212819=>'L',
1007312820=>'L',
1007412821=>'L',
1007512822=>'L',
1007612823=>'L',
1007712824=>'L',
1007812825=>'L',
1007912826=>'L',
1008012827=>'L',
1008112828=>'L',
1008212829=>'ON',
1008312830=>'ON',
1008412832=>'L',
1008512833=>'L',
1008612834=>'L',
1008712835=>'L',
1008812836=>'L',
1008912837=>'L',
1009012838=>'L',
1009112839=>'L',
1009212840=>'L',
1009312841=>'L',
1009412842=>'L',
1009512843=>'L',
1009612844=>'L',
1009712845=>'L',
1009812846=>'L',
1009912847=>'L',
1010012848=>'L',
1010112849=>'L',
1010212850=>'L',
1010312851=>'L',
1010412852=>'L',
1010512853=>'L',
1010612854=>'L',
1010712855=>'L',
1010812856=>'L',
1010912857=>'L',
1011012858=>'L',
1011112859=>'L',
1011212860=>'L',
1011312861=>'L',
1011412862=>'L',
1011512863=>'L',
1011612864=>'L',
1011712865=>'L',
1011812866=>'L',
1011912867=>'L',
1012012880=>'ON',
1012112881=>'ON',
1012212882=>'ON',
1012312883=>'ON',
1012412884=>'ON',
1012512885=>'ON',
1012612886=>'ON',
1012712887=>'ON',
1012812888=>'ON',
1012912889=>'ON',
1013012890=>'ON',
1013112891=>'ON',
1013212892=>'ON',
1013312893=>'ON',
1013412894=>'ON',
1013512895=>'ON',
1013612896=>'L',
1013712897=>'L',
1013812898=>'L',
1013912899=>'L',
1014012900=>'L',
1014112901=>'L',
1014212902=>'L',
1014312903=>'L',
1014412904=>'L',
1014512905=>'L',
1014612906=>'L',
1014712907=>'L',
1014812908=>'L',
1014912909=>'L',
1015012910=>'L',
1015112911=>'L',
1015212912=>'L',
1015312913=>'L',
1015412914=>'L',
1015512915=>'L',
1015612916=>'L',
1015712917=>'L',
1015812918=>'L',
1015912919=>'L',
1016012920=>'L',
1016112921=>'L',
1016212922=>'L',
1016312923=>'L',
1016412924=>'ON',
1016512925=>'ON',
1016612926=>'ON',
1016712927=>'L',
1016812928=>'L',
1016912929=>'L',
1017012930=>'L',
1017112931=>'L',
1017212932=>'L',
1017312933=>'L',
1017412934=>'L',
1017512935=>'L',
1017612936=>'L',
1017712937=>'L',
1017812938=>'L',
1017912939=>'L',
1018012940=>'L',
1018112941=>'L',
1018212942=>'L',
1018312943=>'L',
1018412944=>'L',
1018512945=>'L',
1018612946=>'L',
1018712947=>'L',
1018812948=>'L',
1018912949=>'L',
1019012950=>'L',
1019112951=>'L',
1019212952=>'L',
1019312953=>'L',
1019412954=>'L',
1019512955=>'L',
1019612956=>'L',
1019712957=>'L',
1019812958=>'L',
1019912959=>'L',
1020012960=>'L',
1020112961=>'L',
1020212962=>'L',
1020312963=>'L',
1020412964=>'L',
1020512965=>'L',
1020612966=>'L',
1020712967=>'L',
1020812968=>'L',
1020912969=>'L',
1021012970=>'L',
1021112971=>'L',
1021212972=>'L',
1021312973=>'L',
1021412974=>'L',
1021512975=>'L',
1021612976=>'L',
1021712977=>'ON',
1021812978=>'ON',
1021912979=>'ON',
1022012980=>'ON',
1022112981=>'ON',
1022212982=>'ON',
1022312983=>'ON',
1022412984=>'ON',
1022512985=>'ON',
1022612986=>'ON',
1022712987=>'ON',
1022812988=>'ON',
1022912989=>'ON',
1023012990=>'ON',
1023112991=>'ON',
1023212992=>'L',
1023312993=>'L',
1023412994=>'L',
1023512995=>'L',
1023612996=>'L',
1023712997=>'L',
1023812998=>'L',
1023912999=>'L',
1024013000=>'L',
1024113001=>'L',
1024213002=>'L',
1024313003=>'L',
1024413004=>'ON',
1024513005=>'ON',
1024613006=>'ON',
1024713007=>'ON',
1024813008=>'L',
1024913009=>'L',
1025013010=>'L',
1025113011=>'L',
1025213012=>'L',
1025313013=>'L',
1025413014=>'L',
1025513015=>'L',
1025613016=>'L',
1025713017=>'L',
1025813018=>'L',
1025913019=>'L',
1026013020=>'L',
1026113021=>'L',
1026213022=>'L',
1026313023=>'L',
1026413024=>'L',
1026513025=>'L',
1026613026=>'L',
1026713027=>'L',
1026813028=>'L',
1026913029=>'L',
1027013030=>'L',
1027113031=>'L',
1027213032=>'L',
1027313033=>'L',
1027413034=>'L',
1027513035=>'L',
1027613036=>'L',
1027713037=>'L',
1027813038=>'L',
1027913039=>'L',
1028013040=>'L',
1028113041=>'L',
1028213042=>'L',
1028313043=>'L',
1028413044=>'L',
1028513045=>'L',
1028613046=>'L',
1028713047=>'L',
1028813048=>'L',
1028913049=>'L',
1029013050=>'L',
1029113051=>'L',
1029213052=>'L',
1029313053=>'L',
1029413054=>'L',
1029513056=>'L',
1029613057=>'L',
1029713058=>'L',
1029813059=>'L',
1029913060=>'L',
1030013061=>'L',
1030113062=>'L',
1030213063=>'L',
1030313064=>'L',
1030413065=>'L',
1030513066=>'L',
1030613067=>'L',
1030713068=>'L',
1030813069=>'L',
1030913070=>'L',
1031013071=>'L',
1031113072=>'L',
1031213073=>'L',
1031313074=>'L',
1031413075=>'L',
1031513076=>'L',
1031613077=>'L',
1031713078=>'L',
1031813079=>'L',
1031913080=>'L',
1032013081=>'L',
1032113082=>'L',
1032213083=>'L',
1032313084=>'L',
1032413085=>'L',
1032513086=>'L',
1032613087=>'L',
1032713088=>'L',
1032813089=>'L',
1032913090=>'L',
1033013091=>'L',
1033113092=>'L',
1033213093=>'L',
1033313094=>'L',
1033413095=>'L',
1033513096=>'L',
1033613097=>'L',
1033713098=>'L',
1033813099=>'L',
1033913100=>'L',
1034013101=>'L',
1034113102=>'L',
1034213103=>'L',
1034313104=>'L',
1034413105=>'L',
1034513106=>'L',
1034613107=>'L',
1034713108=>'L',
1034813109=>'L',
1034913110=>'L',
1035013111=>'L',
1035113112=>'L',
1035213113=>'L',
1035313114=>'L',
1035413115=>'L',
1035513116=>'L',
1035613117=>'L',
1035713118=>'L',
1035813119=>'L',
1035913120=>'L',
1036013121=>'L',
1036113122=>'L',
1036213123=>'L',
1036313124=>'L',
1036413125=>'L',
1036513126=>'L',
1036613127=>'L',
1036713128=>'L',
1036813129=>'L',
1036913130=>'L',
1037013131=>'L',
1037113132=>'L',
1037213133=>'L',
1037313134=>'L',
1037413135=>'L',
1037513136=>'L',
1037613137=>'L',
1037713138=>'L',
1037813139=>'L',
1037913140=>'L',
1038013141=>'L',
1038113142=>'L',
1038213143=>'L',
1038313144=>'L',
1038413145=>'L',
1038513146=>'L',
1038613147=>'L',
1038713148=>'L',
1038813149=>'L',
1038913150=>'L',
1039013151=>'L',
1039113152=>'L',
1039213153=>'L',
1039313154=>'L',
1039413155=>'L',
1039513156=>'L',
1039613157=>'L',
1039713158=>'L',
1039813159=>'L',
1039913160=>'L',
1040013161=>'L',
1040113162=>'L',
1040213163=>'L',
1040313164=>'L',
1040413165=>'L',
1040513166=>'L',
1040613167=>'L',
1040713168=>'L',
1040813169=>'L',
1040913170=>'L',
1041013171=>'L',
1041113172=>'L',
1041213173=>'L',
1041313174=>'L',
1041413175=>'ON',
1041513176=>'ON',
1041613177=>'ON',
1041713178=>'ON',
1041813179=>'L',
1041913180=>'L',
1042013181=>'L',
1042113182=>'L',
1042213183=>'L',
1042313184=>'L',
1042413185=>'L',
1042513186=>'L',
1042613187=>'L',
1042713188=>'L',
1042813189=>'L',
1042913190=>'L',
1043013191=>'L',
1043113192=>'L',
1043213193=>'L',
1043313194=>'L',
1043413195=>'L',
1043513196=>'L',
1043613197=>'L',
1043713198=>'L',
1043813199=>'L',
1043913200=>'L',
1044013201=>'L',
1044113202=>'L',
1044213203=>'L',
1044313204=>'L',
1044413205=>'L',
1044513206=>'L',
1044613207=>'L',
1044713208=>'L',
1044813209=>'L',
1044913210=>'L',
1045013211=>'L',
1045113212=>'L',
1045213213=>'L',
1045313214=>'L',
1045413215=>'L',
1045513216=>'L',
1045613217=>'L',
1045713218=>'L',
1045813219=>'L',
1045913220=>'L',
1046013221=>'L',
1046113222=>'L',
1046213223=>'L',
1046313224=>'L',
1046413225=>'L',
1046513226=>'L',
1046613227=>'L',
1046713228=>'L',
1046813229=>'L',
1046913230=>'L',
1047013231=>'L',
1047113232=>'L',
1047213233=>'L',
1047313234=>'L',
1047413235=>'L',
1047513236=>'L',
1047613237=>'L',
1047713238=>'L',
1047813239=>'L',
1047913240=>'L',
1048013241=>'L',
1048113242=>'L',
1048213243=>'L',
1048313244=>'L',
1048413245=>'L',
1048513246=>'L',
1048613247=>'L',
1048713248=>'L',
1048813249=>'L',
1048913250=>'L',
1049013251=>'L',
1049113252=>'L',
1049213253=>'L',
1049313254=>'L',
1049413255=>'L',
1049513256=>'L',
1049613257=>'L',
1049713258=>'L',
1049813259=>'L',
1049913260=>'L',
1050013261=>'L',
1050113262=>'L',
1050213263=>'L',
1050313264=>'L',
1050413265=>'L',
1050513266=>'L',
1050613267=>'L',
1050713268=>'L',
1050813269=>'L',
1050913270=>'L',
1051013271=>'L',
1051113272=>'L',
1051213273=>'L',
1051313274=>'L',
1051413275=>'L',
1051513276=>'L',
1051613277=>'L',
1051713278=>'ON',
1051813279=>'ON',
1051913280=>'L',
1052013281=>'L',
1052113282=>'L',
1052213283=>'L',
1052313284=>'L',
1052413285=>'L',
1052513286=>'L',
1052613287=>'L',
1052713288=>'L',
1052813289=>'L',
1052913290=>'L',
1053013291=>'L',
1053113292=>'L',
1053213293=>'L',
1053313294=>'L',
1053413295=>'L',
1053513296=>'L',
1053613297=>'L',
1053713298=>'L',
1053813299=>'L',
1053913300=>'L',
1054013301=>'L',
1054113302=>'L',
1054213303=>'L',
1054313304=>'L',
1054413305=>'L',
1054513306=>'L',
1054613307=>'L',
1054713308=>'L',
1054813309=>'L',
1054913310=>'L',
1055013311=>'ON',
1055113312=>'L',
1055219893=>'L',
1055319904=>'ON',
1055419905=>'ON',
1055519906=>'ON',
1055619907=>'ON',
1055719908=>'ON',
1055819909=>'ON',
1055919910=>'ON',
1056019911=>'ON',
1056119912=>'ON',
1056219913=>'ON',
1056319914=>'ON',
1056419915=>'ON',
1056519916=>'ON',
1056619917=>'ON',
1056719918=>'ON',
1056819919=>'ON',
1056919920=>'ON',
1057019921=>'ON',
1057119922=>'ON',
1057219923=>'ON',
1057319924=>'ON',
1057419925=>'ON',
1057519926=>'ON',
1057619927=>'ON',
1057719928=>'ON',
1057819929=>'ON',
1057919930=>'ON',
1058019931=>'ON',
1058119932=>'ON',
1058219933=>'ON',
1058319934=>'ON',
1058419935=>'ON',
1058519936=>'ON',
1058619937=>'ON',
1058719938=>'ON',
1058819939=>'ON',
1058919940=>'ON',
1059019941=>'ON',
1059119942=>'ON',
1059219943=>'ON',
1059319944=>'ON',
1059419945=>'ON',
1059519946=>'ON',
1059619947=>'ON',
1059719948=>'ON',
1059819949=>'ON',
1059919950=>'ON',
1060019951=>'ON',
1060119952=>'ON',
1060219953=>'ON',
1060319954=>'ON',
1060419955=>'ON',
1060519956=>'ON',
1060619957=>'ON',
1060719958=>'ON',
1060819959=>'ON',
1060919960=>'ON',
1061019961=>'ON',
1061119962=>'ON',
1061219963=>'ON',
1061319964=>'ON',
1061419965=>'ON',
1061519966=>'ON',
1061619967=>'ON',
1061719968=>'L',
1061840891=>'L',
1061940960=>'L',
1062040961=>'L',
1062140962=>'L',
1062240963=>'L',
1062340964=>'L',
1062440965=>'L',
1062540966=>'L',
1062640967=>'L',
1062740968=>'L',
1062840969=>'L',
1062940970=>'L',
1063040971=>'L',
1063140972=>'L',
1063240973=>'L',
1063340974=>'L',
1063440975=>'L',
1063540976=>'L',
1063640977=>'L',
1063740978=>'L',
1063840979=>'L',
1063940980=>'L',
1064040981=>'L',
1064140982=>'L',
1064240983=>'L',
1064340984=>'L',
1064440985=>'L',
1064540986=>'L',
1064640987=>'L',
1064740988=>'L',
1064840989=>'L',
1064940990=>'L',
1065040991=>'L',
1065140992=>'L',
1065240993=>'L',
1065340994=>'L',
1065440995=>'L',
1065540996=>'L',
1065640997=>'L',
1065740998=>'L',
1065840999=>'L',
1065941000=>'L',
1066041001=>'L',
1066141002=>'L',
1066241003=>'L',
1066341004=>'L',
1066441005=>'L',
1066541006=>'L',
1066641007=>'L',
1066741008=>'L',
1066841009=>'L',
1066941010=>'L',
1067041011=>'L',
1067141012=>'L',
1067241013=>'L',
1067341014=>'L',
1067441015=>'L',
1067541016=>'L',
1067641017=>'L',
1067741018=>'L',
1067841019=>'L',
1067941020=>'L',
1068041021=>'L',
1068141022=>'L',
1068241023=>'L',
1068341024=>'L',
1068441025=>'L',
1068541026=>'L',
1068641027=>'L',
1068741028=>'L',
1068841029=>'L',
1068941030=>'L',
1069041031=>'L',
1069141032=>'L',
1069241033=>'L',
1069341034=>'L',
1069441035=>'L',
1069541036=>'L',
1069641037=>'L',
1069741038=>'L',
1069841039=>'L',
1069941040=>'L',
1070041041=>'L',
1070141042=>'L',
1070241043=>'L',
1070341044=>'L',
1070441045=>'L',
1070541046=>'L',
1070641047=>'L',
1070741048=>'L',
1070841049=>'L',
1070941050=>'L',
1071041051=>'L',
1071141052=>'L',
1071241053=>'L',
1071341054=>'L',
1071441055=>'L',
1071541056=>'L',
1071641057=>'L',
1071741058=>'L',
1071841059=>'L',
1071941060=>'L',
1072041061=>'L',
1072141062=>'L',
1072241063=>'L',
1072341064=>'L',
1072441065=>'L',
1072541066=>'L',
1072641067=>'L',
1072741068=>'L',
1072841069=>'L',
1072941070=>'L',
1073041071=>'L',
1073141072=>'L',
1073241073=>'L',
1073341074=>'L',
1073441075=>'L',
1073541076=>'L',
1073641077=>'L',
1073741078=>'L',
1073841079=>'L',
1073941080=>'L',
1074041081=>'L',
1074141082=>'L',
1074241083=>'L',
1074341084=>'L',
1074441085=>'L',
1074541086=>'L',
1074641087=>'L',
1074741088=>'L',
1074841089=>'L',
1074941090=>'L',
1075041091=>'L',
1075141092=>'L',
1075241093=>'L',
1075341094=>'L',
1075441095=>'L',
1075541096=>'L',
1075641097=>'L',
1075741098=>'L',
1075841099=>'L',
1075941100=>'L',
1076041101=>'L',
1076141102=>'L',
1076241103=>'L',
1076341104=>'L',
1076441105=>'L',
1076541106=>'L',
1076641107=>'L',
1076741108=>'L',
1076841109=>'L',
1076941110=>'L',
1077041111=>'L',
1077141112=>'L',
1077241113=>'L',
1077341114=>'L',
1077441115=>'L',
1077541116=>'L',
1077641117=>'L',
1077741118=>'L',
1077841119=>'L',
1077941120=>'L',
1078041121=>'L',
1078141122=>'L',
1078241123=>'L',
1078341124=>'L',
1078441125=>'L',
1078541126=>'L',
1078641127=>'L',
1078741128=>'L',
1078841129=>'L',
1078941130=>'L',
1079041131=>'L',
1079141132=>'L',
1079241133=>'L',
1079341134=>'L',
1079441135=>'L',
1079541136=>'L',
1079641137=>'L',
1079741138=>'L',
1079841139=>'L',
1079941140=>'L',
1080041141=>'L',
1080141142=>'L',
1080241143=>'L',
1080341144=>'L',
1080441145=>'L',
1080541146=>'L',
1080641147=>'L',
1080741148=>'L',
1080841149=>'L',
1080941150=>'L',
1081041151=>'L',
1081141152=>'L',
1081241153=>'L',
1081341154=>'L',
1081441155=>'L',
1081541156=>'L',
1081641157=>'L',
1081741158=>'L',
1081841159=>'L',
1081941160=>'L',
1082041161=>'L',
1082141162=>'L',
1082241163=>'L',
1082341164=>'L',
1082441165=>'L',
1082541166=>'L',
1082641167=>'L',
1082741168=>'L',
1082841169=>'L',
1082941170=>'L',
1083041171=>'L',
1083141172=>'L',
1083241173=>'L',
1083341174=>'L',
1083441175=>'L',
1083541176=>'L',
1083641177=>'L',
1083741178=>'L',
1083841179=>'L',
1083941180=>'L',
1084041181=>'L',
1084141182=>'L',
1084241183=>'L',
1084341184=>'L',
1084441185=>'L',
1084541186=>'L',
1084641187=>'L',
1084741188=>'L',
1084841189=>'L',
1084941190=>'L',
1085041191=>'L',
1085141192=>'L',
1085241193=>'L',
1085341194=>'L',
1085441195=>'L',
1085541196=>'L',
1085641197=>'L',
1085741198=>'L',
1085841199=>'L',
1085941200=>'L',
1086041201=>'L',
1086141202=>'L',
1086241203=>'L',
1086341204=>'L',
1086441205=>'L',
1086541206=>'L',
1086641207=>'L',
1086741208=>'L',
1086841209=>'L',
1086941210=>'L',
1087041211=>'L',
1087141212=>'L',
1087241213=>'L',
1087341214=>'L',
1087441215=>'L',
1087541216=>'L',
1087641217=>'L',
1087741218=>'L',
1087841219=>'L',
1087941220=>'L',
1088041221=>'L',
1088141222=>'L',
1088241223=>'L',
1088341224=>'L',
1088441225=>'L',
1088541226=>'L',
1088641227=>'L',
1088741228=>'L',
1088841229=>'L',
1088941230=>'L',
1089041231=>'L',
1089141232=>'L',
1089241233=>'L',
1089341234=>'L',
1089441235=>'L',
1089541236=>'L',
1089641237=>'L',
1089741238=>'L',
1089841239=>'L',
1089941240=>'L',
1090041241=>'L',
1090141242=>'L',
1090241243=>'L',
1090341244=>'L',
1090441245=>'L',
1090541246=>'L',
1090641247=>'L',
1090741248=>'L',
1090841249=>'L',
1090941250=>'L',
1091041251=>'L',
1091141252=>'L',
1091241253=>'L',
1091341254=>'L',
1091441255=>'L',
1091541256=>'L',
1091641257=>'L',
1091741258=>'L',
1091841259=>'L',
1091941260=>'L',
1092041261=>'L',
1092141262=>'L',
1092241263=>'L',
1092341264=>'L',
1092441265=>'L',
1092541266=>'L',
1092641267=>'L',
1092741268=>'L',
1092841269=>'L',
1092941270=>'L',
1093041271=>'L',
1093141272=>'L',
1093241273=>'L',
1093341274=>'L',
1093441275=>'L',
1093541276=>'L',
1093641277=>'L',
1093741278=>'L',
1093841279=>'L',
1093941280=>'L',
1094041281=>'L',
1094141282=>'L',
1094241283=>'L',
1094341284=>'L',
1094441285=>'L',
1094541286=>'L',
1094641287=>'L',
1094741288=>'L',
1094841289=>'L',
1094941290=>'L',
1095041291=>'L',
1095141292=>'L',
1095241293=>'L',
1095341294=>'L',
1095441295=>'L',
1095541296=>'L',
1095641297=>'L',
1095741298=>'L',
1095841299=>'L',
1095941300=>'L',
1096041301=>'L',
1096141302=>'L',
1096241303=>'L',
1096341304=>'L',
1096441305=>'L',
1096541306=>'L',
1096641307=>'L',
1096741308=>'L',
1096841309=>'L',
1096941310=>'L',
1097041311=>'L',
1097141312=>'L',
1097241313=>'L',
1097341314=>'L',
1097441315=>'L',
1097541316=>'L',
1097641317=>'L',
1097741318=>'L',
1097841319=>'L',
1097941320=>'L',
1098041321=>'L',
1098141322=>'L',
1098241323=>'L',
1098341324=>'L',
1098441325=>'L',
1098541326=>'L',
1098641327=>'L',
1098741328=>'L',
1098841329=>'L',
1098941330=>'L',
1099041331=>'L',
1099141332=>'L',
1099241333=>'L',
1099341334=>'L',
1099441335=>'L',
1099541336=>'L',
1099641337=>'L',
1099741338=>'L',
1099841339=>'L',
1099941340=>'L',
1100041341=>'L',
1100141342=>'L',
1100241343=>'L',
1100341344=>'L',
1100441345=>'L',
1100541346=>'L',
1100641347=>'L',
1100741348=>'L',
1100841349=>'L',
1100941350=>'L',
1101041351=>'L',
1101141352=>'L',
1101241353=>'L',
1101341354=>'L',
1101441355=>'L',
1101541356=>'L',
1101641357=>'L',
1101741358=>'L',
1101841359=>'L',
1101941360=>'L',
1102041361=>'L',
1102141362=>'L',
1102241363=>'L',
1102341364=>'L',
1102441365=>'L',
1102541366=>'L',
1102641367=>'L',
1102741368=>'L',
1102841369=>'L',
1102941370=>'L',
1103041371=>'L',
1103141372=>'L',
1103241373=>'L',
1103341374=>'L',
1103441375=>'L',
1103541376=>'L',
1103641377=>'L',
1103741378=>'L',
1103841379=>'L',
1103941380=>'L',
1104041381=>'L',
1104141382=>'L',
1104241383=>'L',
1104341384=>'L',
1104441385=>'L',
1104541386=>'L',
1104641387=>'L',
1104741388=>'L',
1104841389=>'L',
1104941390=>'L',
1105041391=>'L',
1105141392=>'L',
1105241393=>'L',
1105341394=>'L',
1105441395=>'L',
1105541396=>'L',
1105641397=>'L',
1105741398=>'L',
1105841399=>'L',
1105941400=>'L',
1106041401=>'L',
1106141402=>'L',
1106241403=>'L',
1106341404=>'L',
1106441405=>'L',
1106541406=>'L',
1106641407=>'L',
1106741408=>'L',
1106841409=>'L',
1106941410=>'L',
1107041411=>'L',
1107141412=>'L',
1107241413=>'L',
1107341414=>'L',
1107441415=>'L',
1107541416=>'L',
1107641417=>'L',
1107741418=>'L',
1107841419=>'L',
1107941420=>'L',
1108041421=>'L',
1108141422=>'L',
1108241423=>'L',
1108341424=>'L',
1108441425=>'L',
1108541426=>'L',
1108641427=>'L',
1108741428=>'L',
1108841429=>'L',
1108941430=>'L',
1109041431=>'L',
1109141432=>'L',
1109241433=>'L',
1109341434=>'L',
1109441435=>'L',
1109541436=>'L',
1109641437=>'L',
1109741438=>'L',
1109841439=>'L',
1109941440=>'L',
1110041441=>'L',
1110141442=>'L',
1110241443=>'L',
1110341444=>'L',
1110441445=>'L',
1110541446=>'L',
1110641447=>'L',
1110741448=>'L',
1110841449=>'L',
1110941450=>'L',
1111041451=>'L',
1111141452=>'L',
1111241453=>'L',
1111341454=>'L',
1111441455=>'L',
1111541456=>'L',
1111641457=>'L',
1111741458=>'L',
1111841459=>'L',
1111941460=>'L',
1112041461=>'L',
1112141462=>'L',
1112241463=>'L',
1112341464=>'L',
1112441465=>'L',
1112541466=>'L',
1112641467=>'L',
1112741468=>'L',
1112841469=>'L',
1112941470=>'L',
1113041471=>'L',
1113141472=>'L',
1113241473=>'L',
1113341474=>'L',
1113441475=>'L',
1113541476=>'L',
1113641477=>'L',
1113741478=>'L',
1113841479=>'L',
1113941480=>'L',
1114041481=>'L',
1114141482=>'L',
1114241483=>'L',
1114341484=>'L',
1114441485=>'L',
1114541486=>'L',
1114641487=>'L',
1114741488=>'L',
1114841489=>'L',
1114941490=>'L',
1115041491=>'L',
1115141492=>'L',
1115241493=>'L',
1115341494=>'L',
1115441495=>'L',
1115541496=>'L',
1115641497=>'L',
1115741498=>'L',
1115841499=>'L',
1115941500=>'L',
1116041501=>'L',
1116141502=>'L',
1116241503=>'L',
1116341504=>'L',
1116441505=>'L',
1116541506=>'L',
1116641507=>'L',
1116741508=>'L',
1116841509=>'L',
1116941510=>'L',
1117041511=>'L',
1117141512=>'L',
1117241513=>'L',
1117341514=>'L',
1117441515=>'L',
1117541516=>'L',
1117641517=>'L',
1117741518=>'L',
1117841519=>'L',
1117941520=>'L',
1118041521=>'L',
1118141522=>'L',
1118241523=>'L',
1118341524=>'L',
1118441525=>'L',
1118541526=>'L',
1118641527=>'L',
1118741528=>'L',
1118841529=>'L',
1118941530=>'L',
1119041531=>'L',
1119141532=>'L',
1119241533=>'L',
1119341534=>'L',
1119441535=>'L',
1119541536=>'L',
1119641537=>'L',
1119741538=>'L',
1119841539=>'L',
1119941540=>'L',
1120041541=>'L',
1120141542=>'L',
1120241543=>'L',
1120341544=>'L',
1120441545=>'L',
1120541546=>'L',
1120641547=>'L',
1120741548=>'L',
1120841549=>'L',
1120941550=>'L',
1121041551=>'L',
1121141552=>'L',
1121241553=>'L',
1121341554=>'L',
1121441555=>'L',
1121541556=>'L',
1121641557=>'L',
1121741558=>'L',
1121841559=>'L',
1121941560=>'L',
1122041561=>'L',
1122141562=>'L',
1122241563=>'L',
1122341564=>'L',
1122441565=>'L',
1122541566=>'L',
1122641567=>'L',
1122741568=>'L',
1122841569=>'L',
1122941570=>'L',
1123041571=>'L',
1123141572=>'L',
1123241573=>'L',
1123341574=>'L',
1123441575=>'L',
1123541576=>'L',
1123641577=>'L',
1123741578=>'L',
1123841579=>'L',
1123941580=>'L',
1124041581=>'L',
1124141582=>'L',
1124241583=>'L',
1124341584=>'L',
1124441585=>'L',
1124541586=>'L',
1124641587=>'L',
1124741588=>'L',
1124841589=>'L',
1124941590=>'L',
1125041591=>'L',
1125141592=>'L',
1125241593=>'L',
1125341594=>'L',
1125441595=>'L',
1125541596=>'L',
1125641597=>'L',
1125741598=>'L',
1125841599=>'L',
1125941600=>'L',
1126041601=>'L',
1126141602=>'L',
1126241603=>'L',
1126341604=>'L',
1126441605=>'L',
1126541606=>'L',
1126641607=>'L',
1126741608=>'L',
1126841609=>'L',
1126941610=>'L',
1127041611=>'L',
1127141612=>'L',
1127241613=>'L',
1127341614=>'L',
1127441615=>'L',
1127541616=>'L',
1127641617=>'L',
1127741618=>'L',
1127841619=>'L',
1127941620=>'L',
1128041621=>'L',
1128141622=>'L',
1128241623=>'L',
1128341624=>'L',
1128441625=>'L',
1128541626=>'L',
1128641627=>'L',
1128741628=>'L',
1128841629=>'L',
1128941630=>'L',
1129041631=>'L',
1129141632=>'L',
1129241633=>'L',
1129341634=>'L',
1129441635=>'L',
1129541636=>'L',
1129641637=>'L',
1129741638=>'L',
1129841639=>'L',
1129941640=>'L',
1130041641=>'L',
1130141642=>'L',
1130241643=>'L',
1130341644=>'L',
1130441645=>'L',
1130541646=>'L',
1130641647=>'L',
1130741648=>'L',
1130841649=>'L',
1130941650=>'L',
1131041651=>'L',
1131141652=>'L',
1131241653=>'L',
1131341654=>'L',
1131441655=>'L',
1131541656=>'L',
1131641657=>'L',
1131741658=>'L',
1131841659=>'L',
1131941660=>'L',
1132041661=>'L',
1132141662=>'L',
1132241663=>'L',
1132341664=>'L',
1132441665=>'L',
1132541666=>'L',
1132641667=>'L',
1132741668=>'L',
1132841669=>'L',
1132941670=>'L',
1133041671=>'L',
1133141672=>'L',
1133241673=>'L',
1133341674=>'L',
1133441675=>'L',
1133541676=>'L',
1133641677=>'L',
1133741678=>'L',
1133841679=>'L',
1133941680=>'L',
1134041681=>'L',
1134141682=>'L',
1134241683=>'L',
1134341684=>'L',
1134441685=>'L',
1134541686=>'L',
1134641687=>'L',
1134741688=>'L',
1134841689=>'L',
1134941690=>'L',
1135041691=>'L',
1135141692=>'L',
1135241693=>'L',
1135341694=>'L',
1135441695=>'L',
1135541696=>'L',
1135641697=>'L',
1135741698=>'L',
1135841699=>'L',
1135941700=>'L',
1136041701=>'L',
1136141702=>'L',
1136241703=>'L',
1136341704=>'L',
1136441705=>'L',
1136541706=>'L',
1136641707=>'L',
1136741708=>'L',
1136841709=>'L',
1136941710=>'L',
1137041711=>'L',
1137141712=>'L',
1137241713=>'L',
1137341714=>'L',
1137441715=>'L',
1137541716=>'L',
1137641717=>'L',
1137741718=>'L',
1137841719=>'L',
1137941720=>'L',
1138041721=>'L',
1138141722=>'L',
1138241723=>'L',
1138341724=>'L',
1138441725=>'L',
1138541726=>'L',
1138641727=>'L',
1138741728=>'L',
1138841729=>'L',
1138941730=>'L',
1139041731=>'L',
1139141732=>'L',
1139241733=>'L',
1139341734=>'L',
1139441735=>'L',
1139541736=>'L',
1139641737=>'L',
1139741738=>'L',
1139841739=>'L',
1139941740=>'L',
1140041741=>'L',
1140141742=>'L',
1140241743=>'L',
1140341744=>'L',
1140441745=>'L',
1140541746=>'L',
1140641747=>'L',
1140741748=>'L',
1140841749=>'L',
1140941750=>'L',
1141041751=>'L',
1141141752=>'L',
1141241753=>'L',
1141341754=>'L',
1141441755=>'L',
1141541756=>'L',
1141641757=>'L',
1141741758=>'L',
1141841759=>'L',
1141941760=>'L',
1142041761=>'L',
1142141762=>'L',
1142241763=>'L',
1142341764=>'L',
1142441765=>'L',
1142541766=>'L',
1142641767=>'L',
1142741768=>'L',
1142841769=>'L',
1142941770=>'L',
1143041771=>'L',
1143141772=>'L',
1143241773=>'L',
1143341774=>'L',
1143441775=>'L',
1143541776=>'L',
1143641777=>'L',
1143741778=>'L',
1143841779=>'L',
1143941780=>'L',
1144041781=>'L',
1144141782=>'L',
1144241783=>'L',
1144341784=>'L',
1144441785=>'L',
1144541786=>'L',
1144641787=>'L',
1144741788=>'L',
1144841789=>'L',
1144941790=>'L',
1145041791=>'L',
1145141792=>'L',
1145241793=>'L',
1145341794=>'L',
1145441795=>'L',
1145541796=>'L',
1145641797=>'L',
1145741798=>'L',
1145841799=>'L',
1145941800=>'L',
1146041801=>'L',
1146141802=>'L',
1146241803=>'L',
1146341804=>'L',
1146441805=>'L',
1146541806=>'L',
1146641807=>'L',
1146741808=>'L',
1146841809=>'L',
1146941810=>'L',
1147041811=>'L',
1147141812=>'L',
1147241813=>'L',
1147341814=>'L',
1147441815=>'L',
1147541816=>'L',
1147641817=>'L',
1147741818=>'L',
1147841819=>'L',
1147941820=>'L',
1148041821=>'L',
1148141822=>'L',
1148241823=>'L',
1148341824=>'L',
1148441825=>'L',
1148541826=>'L',
1148641827=>'L',
1148741828=>'L',
1148841829=>'L',
1148941830=>'L',
1149041831=>'L',
1149141832=>'L',
1149241833=>'L',
1149341834=>'L',
1149441835=>'L',
1149541836=>'L',
1149641837=>'L',
1149741838=>'L',
1149841839=>'L',
1149941840=>'L',
1150041841=>'L',
1150141842=>'L',
1150241843=>'L',
1150341844=>'L',
1150441845=>'L',
1150541846=>'L',
1150641847=>'L',
1150741848=>'L',
1150841849=>'L',
1150941850=>'L',
1151041851=>'L',
1151141852=>'L',
1151241853=>'L',
1151341854=>'L',
1151441855=>'L',
1151541856=>'L',
1151641857=>'L',
1151741858=>'L',
1151841859=>'L',
1151941860=>'L',
1152041861=>'L',
1152141862=>'L',
1152241863=>'L',
1152341864=>'L',
1152441865=>'L',
1152541866=>'L',
1152641867=>'L',
1152741868=>'L',
1152841869=>'L',
1152941870=>'L',
1153041871=>'L',
1153141872=>'L',
1153241873=>'L',
1153341874=>'L',
1153441875=>'L',
1153541876=>'L',
1153641877=>'L',
1153741878=>'L',
1153841879=>'L',
1153941880=>'L',
1154041881=>'L',
1154141882=>'L',
1154241883=>'L',
1154341884=>'L',
1154441885=>'L',
1154541886=>'L',
1154641887=>'L',
1154741888=>'L',
1154841889=>'L',
1154941890=>'L',
1155041891=>'L',
1155141892=>'L',
1155241893=>'L',
1155341894=>'L',
1155441895=>'L',
1155541896=>'L',
1155641897=>'L',
1155741898=>'L',
1155841899=>'L',
1155941900=>'L',
1156041901=>'L',
1156141902=>'L',
1156241903=>'L',
1156341904=>'L',
1156441905=>'L',
1156541906=>'L',
1156641907=>'L',
1156741908=>'L',
1156841909=>'L',
1156941910=>'L',
1157041911=>'L',
1157141912=>'L',
1157241913=>'L',
1157341914=>'L',
1157441915=>'L',
1157541916=>'L',
1157641917=>'L',
1157741918=>'L',
1157841919=>'L',
1157941920=>'L',
1158041921=>'L',
1158141922=>'L',
1158241923=>'L',
1158341924=>'L',
1158441925=>'L',
1158541926=>'L',
1158641927=>'L',
1158741928=>'L',
1158841929=>'L',
1158941930=>'L',
1159041931=>'L',
1159141932=>'L',
1159241933=>'L',
1159341934=>'L',
1159441935=>'L',
1159541936=>'L',
1159641937=>'L',
1159741938=>'L',
1159841939=>'L',
1159941940=>'L',
1160041941=>'L',
1160141942=>'L',
1160241943=>'L',
1160341944=>'L',
1160441945=>'L',
1160541946=>'L',
1160641947=>'L',
1160741948=>'L',
1160841949=>'L',
1160941950=>'L',
1161041951=>'L',
1161141952=>'L',
1161241953=>'L',
1161341954=>'L',
1161441955=>'L',
1161541956=>'L',
1161641957=>'L',
1161741958=>'L',
1161841959=>'L',
1161941960=>'L',
1162041961=>'L',
1162141962=>'L',
1162241963=>'L',
1162341964=>'L',
1162441965=>'L',
1162541966=>'L',
1162641967=>'L',
1162741968=>'L',
1162841969=>'L',
1162941970=>'L',
1163041971=>'L',
1163141972=>'L',
1163241973=>'L',
1163341974=>'L',
1163441975=>'L',
1163541976=>'L',
1163641977=>'L',
1163741978=>'L',
1163841979=>'L',
1163941980=>'L',
1164041981=>'L',
1164141982=>'L',
1164241983=>'L',
1164341984=>'L',
1164441985=>'L',
1164541986=>'L',
1164641987=>'L',
1164741988=>'L',
1164841989=>'L',
1164941990=>'L',
1165041991=>'L',
1165141992=>'L',
1165241993=>'L',
1165341994=>'L',
1165441995=>'L',
1165541996=>'L',
1165641997=>'L',
1165741998=>'L',
1165841999=>'L',
1165942000=>'L',
1166042001=>'L',
1166142002=>'L',
1166242003=>'L',
1166342004=>'L',
1166442005=>'L',
1166542006=>'L',
1166642007=>'L',
1166742008=>'L',
1166842009=>'L',
1166942010=>'L',
1167042011=>'L',
1167142012=>'L',
1167242013=>'L',
1167342014=>'L',
1167442015=>'L',
1167542016=>'L',
1167642017=>'L',
1167742018=>'L',
1167842019=>'L',
1167942020=>'L',
1168042021=>'L',
1168142022=>'L',
1168242023=>'L',
1168342024=>'L',
1168442025=>'L',
1168542026=>'L',
1168642027=>'L',
1168742028=>'L',
1168842029=>'L',
1168942030=>'L',
1169042031=>'L',
1169142032=>'L',
1169242033=>'L',
1169342034=>'L',
1169442035=>'L',
1169542036=>'L',
1169642037=>'L',
1169742038=>'L',
1169842039=>'L',
1169942040=>'L',
1170042041=>'L',
1170142042=>'L',
1170242043=>'L',
1170342044=>'L',
1170442045=>'L',
1170542046=>'L',
1170642047=>'L',
1170742048=>'L',
1170842049=>'L',
1170942050=>'L',
1171042051=>'L',
1171142052=>'L',
1171242053=>'L',
1171342054=>'L',
1171442055=>'L',
1171542056=>'L',
1171642057=>'L',
1171742058=>'L',
1171842059=>'L',
1171942060=>'L',
1172042061=>'L',
1172142062=>'L',
1172242063=>'L',
1172342064=>'L',
1172442065=>'L',
1172542066=>'L',
1172642067=>'L',
1172742068=>'L',
1172842069=>'L',
1172942070=>'L',
1173042071=>'L',
1173142072=>'L',
1173242073=>'L',
1173342074=>'L',
1173442075=>'L',
1173542076=>'L',
1173642077=>'L',
1173742078=>'L',
1173842079=>'L',
1173942080=>'L',
1174042081=>'L',
1174142082=>'L',
1174242083=>'L',
1174342084=>'L',
1174442085=>'L',
1174542086=>'L',
1174642087=>'L',
1174742088=>'L',
1174842089=>'L',
1174942090=>'L',
1175042091=>'L',
1175142092=>'L',
1175242093=>'L',
1175342094=>'L',
1175442095=>'L',
1175542096=>'L',
1175642097=>'L',
1175742098=>'L',
1175842099=>'L',
1175942100=>'L',
1176042101=>'L',
1176142102=>'L',
1176242103=>'L',
1176342104=>'L',
1176442105=>'L',
1176542106=>'L',
1176642107=>'L',
1176742108=>'L',
1176842109=>'L',
1176942110=>'L',
1177042111=>'L',
1177142112=>'L',
1177242113=>'L',
1177342114=>'L',
1177442115=>'L',
1177542116=>'L',
1177642117=>'L',
1177742118=>'L',
1177842119=>'L',
1177942120=>'L',
1178042121=>'L',
1178142122=>'L',
1178242123=>'L',
1178342124=>'L',
1178442128=>'ON',
1178542129=>'ON',
1178642130=>'ON',
1178742131=>'ON',
1178842132=>'ON',
1178942133=>'ON',
1179042134=>'ON',
1179142135=>'ON',
1179242136=>'ON',
1179342137=>'ON',
1179442138=>'ON',
1179542139=>'ON',
1179642140=>'ON',
1179742141=>'ON',
1179842142=>'ON',
1179942143=>'ON',
1180042144=>'ON',
1180142145=>'ON',
1180242146=>'ON',
1180342147=>'ON',
1180442148=>'ON',
1180542149=>'ON',
1180642150=>'ON',
1180742151=>'ON',
1180842152=>'ON',
1180942153=>'ON',
1181042154=>'ON',
1181142155=>'ON',
1181242156=>'ON',
1181342157=>'ON',
1181442158=>'ON',
1181542159=>'ON',
1181642160=>'ON',
1181742161=>'ON',
1181842162=>'ON',
1181942163=>'ON',
1182042164=>'ON',
1182142165=>'ON',
1182242166=>'ON',
1182342167=>'ON',
1182442168=>'ON',
1182542169=>'ON',
1182642170=>'ON',
1182742171=>'ON',
1182842172=>'ON',
1182942173=>'ON',
1183042174=>'ON',
1183142175=>'ON',
1183242176=>'ON',
1183342177=>'ON',
1183442178=>'ON',
1183542179=>'ON',
1183642180=>'ON',
1183742181=>'ON',
1183842182=>'ON',
1183942752=>'ON',
1184042753=>'ON',
1184142754=>'ON',
1184242755=>'ON',
1184342756=>'ON',
1184442757=>'ON',
1184542758=>'ON',
1184642759=>'ON',
1184742760=>'ON',
1184842761=>'ON',
1184942762=>'ON',
1185042763=>'ON',
1185142764=>'ON',
1185242765=>'ON',
1185342766=>'ON',
1185442767=>'ON',
1185542768=>'ON',
1185642769=>'ON',
1185742770=>'ON',
1185842771=>'ON',
1185942772=>'ON',
1186042773=>'ON',
1186142774=>'ON',
1186242775=>'ON',
1186342776=>'ON',
1186442777=>'ON',
1186542778=>'ON',
1186642784=>'ON',
1186742785=>'ON',
1186843008=>'L',
1186943009=>'L',
1187043010=>'NSM',
1187143011=>'L',
1187243012=>'L',
1187343013=>'L',
1187443014=>'NSM',
1187543015=>'L',
1187643016=>'L',
1187743017=>'L',
1187843018=>'L',
1187943019=>'NSM',
1188043020=>'L',
1188143021=>'L',
1188243022=>'L',
1188343023=>'L',
1188443024=>'L',
1188543025=>'L',
1188643026=>'L',
1188743027=>'L',
1188843028=>'L',
1188943029=>'L',
1189043030=>'L',
1189143031=>'L',
1189243032=>'L',
1189343033=>'L',
1189443034=>'L',
1189543035=>'L',
1189643036=>'L',
1189743037=>'L',
1189843038=>'L',
1189943039=>'L',
1190043040=>'L',
1190143041=>'L',
1190243042=>'L',
1190343043=>'L',
1190443044=>'L',
1190543045=>'NSM',
1190643046=>'NSM',
1190743047=>'L',
1190843048=>'ON',
1190943049=>'ON',
1191043050=>'ON',
1191143051=>'ON',
1191243072=>'L',
1191343073=>'L',
1191443074=>'L',
1191543075=>'L',
1191643076=>'L',
1191743077=>'L',
1191843078=>'L',
1191943079=>'L',
1192043080=>'L',
1192143081=>'L',
1192243082=>'L',
1192343083=>'L',
1192443084=>'L',
1192543085=>'L',
1192643086=>'L',
1192743087=>'L',
1192843088=>'L',
1192943089=>'L',
1193043090=>'L',
1193143091=>'L',
1193243092=>'L',
1193343093=>'L',
1193443094=>'L',
1193543095=>'L',
1193643096=>'L',
1193743097=>'L',
1193843098=>'L',
1193943099=>'L',
1194043100=>'L',
1194143101=>'L',
1194243102=>'L',
1194343103=>'L',
1194443104=>'L',
1194543105=>'L',
1194643106=>'L',
1194743107=>'L',
1194843108=>'L',
1194943109=>'L',
1195043110=>'L',
1195143111=>'L',
1195243112=>'L',
1195343113=>'L',
1195443114=>'L',
1195543115=>'L',
1195643116=>'L',
1195743117=>'L',
1195843118=>'L',
1195943119=>'L',
1196043120=>'L',
1196143121=>'L',
1196243122=>'L',
1196343123=>'L',
1196443124=>'ON',
1196543125=>'ON',
1196643126=>'ON',
1196743127=>'ON',
1196844032=>'L',
1196955203=>'L',
1197055296=>'L',
1197156191=>'L',
1197256192=>'L',
1197356319=>'L',
1197456320=>'L',
1197557343=>'L',
1197657344=>'L',
1197763743=>'L',
1197863744=>'L',
1197963745=>'L',
1198063746=>'L',
1198163747=>'L',
1198263748=>'L',
1198363749=>'L',
1198463750=>'L',
1198563751=>'L',
1198663752=>'L',
1198763753=>'L',
1198863754=>'L',
1198963755=>'L',
1199063756=>'L',
1199163757=>'L',
1199263758=>'L',
1199363759=>'L',
1199463760=>'L',
1199563761=>'L',
1199663762=>'L',
1199763763=>'L',
1199863764=>'L',
1199963765=>'L',
1200063766=>'L',
1200163767=>'L',
1200263768=>'L',
1200363769=>'L',
1200463770=>'L',
1200563771=>'L',
1200663772=>'L',
1200763773=>'L',
1200863774=>'L',
1200963775=>'L',
1201063776=>'L',
1201163777=>'L',
1201263778=>'L',
1201363779=>'L',
1201463780=>'L',
1201563781=>'L',
1201663782=>'L',
1201763783=>'L',
1201863784=>'L',
1201963785=>'L',
1202063786=>'L',
1202163787=>'L',
1202263788=>'L',
1202363789=>'L',
1202463790=>'L',
1202563791=>'L',
1202663792=>'L',
1202763793=>'L',
1202863794=>'L',
1202963795=>'L',
1203063796=>'L',
1203163797=>'L',
1203263798=>'L',
1203363799=>'L',
1203463800=>'L',
1203563801=>'L',
1203663802=>'L',
1203763803=>'L',
1203863804=>'L',
1203963805=>'L',
1204063806=>'L',
1204163807=>'L',
1204263808=>'L',
1204363809=>'L',
1204463810=>'L',
1204563811=>'L',
1204663812=>'L',
1204763813=>'L',
1204863814=>'L',
1204963815=>'L',
1205063816=>'L',
1205163817=>'L',
1205263818=>'L',
1205363819=>'L',
1205463820=>'L',
1205563821=>'L',
1205663822=>'L',
1205763823=>'L',
1205863824=>'L',
1205963825=>'L',
1206063826=>'L',
1206163827=>'L',
1206263828=>'L',
1206363829=>'L',
1206463830=>'L',
1206563831=>'L',
1206663832=>'L',
1206763833=>'L',
1206863834=>'L',
1206963835=>'L',
1207063836=>'L',
1207163837=>'L',
1207263838=>'L',
1207363839=>'L',
1207463840=>'L',
1207563841=>'L',
1207663842=>'L',
1207763843=>'L',
1207863844=>'L',
1207963845=>'L',
1208063846=>'L',
1208163847=>'L',
1208263848=>'L',
1208363849=>'L',
1208463850=>'L',
1208563851=>'L',
1208663852=>'L',
1208763853=>'L',
1208863854=>'L',
1208963855=>'L',
1209063856=>'L',
1209163857=>'L',
1209263858=>'L',
1209363859=>'L',
1209463860=>'L',
1209563861=>'L',
1209663862=>'L',
1209763863=>'L',
1209863864=>'L',
1209963865=>'L',
1210063866=>'L',
1210163867=>'L',
1210263868=>'L',
1210363869=>'L',
1210463870=>'L',
1210563871=>'L',
1210663872=>'L',
1210763873=>'L',
1210863874=>'L',
1210963875=>'L',
1211063876=>'L',
1211163877=>'L',
1211263878=>'L',
1211363879=>'L',
1211463880=>'L',
1211563881=>'L',
1211663882=>'L',
1211763883=>'L',
1211863884=>'L',
1211963885=>'L',
1212063886=>'L',
1212163887=>'L',
1212263888=>'L',
1212363889=>'L',
1212463890=>'L',
1212563891=>'L',
1212663892=>'L',
1212763893=>'L',
1212863894=>'L',
1212963895=>'L',
1213063896=>'L',
1213163897=>'L',
1213263898=>'L',
1213363899=>'L',
1213463900=>'L',
1213563901=>'L',
1213663902=>'L',
1213763903=>'L',
1213863904=>'L',
1213963905=>'L',
1214063906=>'L',
1214163907=>'L',
1214263908=>'L',
1214363909=>'L',
1214463910=>'L',
1214563911=>'L',
1214663912=>'L',
1214763913=>'L',
1214863914=>'L',
1214963915=>'L',
1215063916=>'L',
1215163917=>'L',
1215263918=>'L',
1215363919=>'L',
1215463920=>'L',
1215563921=>'L',
1215663922=>'L',
1215763923=>'L',
1215863924=>'L',
1215963925=>'L',
1216063926=>'L',
1216163927=>'L',
1216263928=>'L',
1216363929=>'L',
1216463930=>'L',
1216563931=>'L',
1216663932=>'L',
1216763933=>'L',
1216863934=>'L',
1216963935=>'L',
1217063936=>'L',
1217163937=>'L',
1217263938=>'L',
1217363939=>'L',
1217463940=>'L',
1217563941=>'L',
1217663942=>'L',
1217763943=>'L',
1217863944=>'L',
1217963945=>'L',
1218063946=>'L',
1218163947=>'L',
1218263948=>'L',
1218363949=>'L',
1218463950=>'L',
1218563951=>'L',
1218663952=>'L',
1218763953=>'L',
1218863954=>'L',
1218963955=>'L',
1219063956=>'L',
1219163957=>'L',
1219263958=>'L',
1219363959=>'L',
1219463960=>'L',
1219563961=>'L',
1219663962=>'L',
1219763963=>'L',
1219863964=>'L',
1219963965=>'L',
1220063966=>'L',
1220163967=>'L',
1220263968=>'L',
1220363969=>'L',
1220463970=>'L',
1220563971=>'L',
1220663972=>'L',
1220763973=>'L',
1220863974=>'L',
1220963975=>'L',
1221063976=>'L',
1221163977=>'L',
1221263978=>'L',
1221363979=>'L',
1221463980=>'L',
1221563981=>'L',
1221663982=>'L',
1221763983=>'L',
1221863984=>'L',
1221963985=>'L',
1222063986=>'L',
1222163987=>'L',
1222263988=>'L',
1222363989=>'L',
1222463990=>'L',
1222563991=>'L',
1222663992=>'L',
1222763993=>'L',
1222863994=>'L',
1222963995=>'L',
1223063996=>'L',
1223163997=>'L',
1223263998=>'L',
1223363999=>'L',
1223464000=>'L',
1223564001=>'L',
1223664002=>'L',
1223764003=>'L',
1223864004=>'L',
1223964005=>'L',
1224064006=>'L',
1224164007=>'L',
1224264008=>'L',
1224364009=>'L',
1224464010=>'L',
1224564011=>'L',
1224664012=>'L',
1224764013=>'L',
1224864014=>'L',
1224964015=>'L',
1225064016=>'L',
1225164017=>'L',
1225264018=>'L',
1225364019=>'L',
1225464020=>'L',
1225564021=>'L',
1225664022=>'L',
1225764023=>'L',
1225864024=>'L',
1225964025=>'L',
1226064026=>'L',
1226164027=>'L',
1226264028=>'L',
1226364029=>'L',
1226464030=>'L',
1226564031=>'L',
1226664032=>'L',
1226764033=>'L',
1226864034=>'L',
1226964035=>'L',
1227064036=>'L',
1227164037=>'L',
1227264038=>'L',
1227364039=>'L',
1227464040=>'L',
1227564041=>'L',
1227664042=>'L',
1227764043=>'L',
1227864044=>'L',
1227964045=>'L',
1228064048=>'L',
1228164049=>'L',
1228264050=>'L',
1228364051=>'L',
1228464052=>'L',
1228564053=>'L',
1228664054=>'L',
1228764055=>'L',
1228864056=>'L',
1228964057=>'L',
1229064058=>'L',
1229164059=>'L',
1229264060=>'L',
1229364061=>'L',
1229464062=>'L',
1229564063=>'L',
1229664064=>'L',
1229764065=>'L',
1229864066=>'L',
1229964067=>'L',
1230064068=>'L',
1230164069=>'L',
1230264070=>'L',
1230364071=>'L',
1230464072=>'L',
1230564073=>'L',
1230664074=>'L',
1230764075=>'L',
1230864076=>'L',
1230964077=>'L',
1231064078=>'L',
1231164079=>'L',
1231264080=>'L',
1231364081=>'L',
1231464082=>'L',
1231564083=>'L',
1231664084=>'L',
1231764085=>'L',
1231864086=>'L',
1231964087=>'L',
1232064088=>'L',
1232164089=>'L',
1232264090=>'L',
1232364091=>'L',
1232464092=>'L',
1232564093=>'L',
1232664094=>'L',
1232764095=>'L',
1232864096=>'L',
1232964097=>'L',
1233064098=>'L',
1233164099=>'L',
1233264100=>'L',
1233364101=>'L',
1233464102=>'L',
1233564103=>'L',
1233664104=>'L',
1233764105=>'L',
1233864106=>'L',
1233964112=>'L',
1234064113=>'L',
1234164114=>'L',
1234264115=>'L',
1234364116=>'L',
1234464117=>'L',
1234564118=>'L',
1234664119=>'L',
1234764120=>'L',
1234864121=>'L',
1234964122=>'L',
1235064123=>'L',
1235164124=>'L',
1235264125=>'L',
1235364126=>'L',
1235464127=>'L',
1235564128=>'L',
1235664129=>'L',
1235764130=>'L',
1235864131=>'L',
1235964132=>'L',
1236064133=>'L',
1236164134=>'L',
1236264135=>'L',
1236364136=>'L',
1236464137=>'L',
1236564138=>'L',
1236664139=>'L',
1236764140=>'L',
1236864141=>'L',
1236964142=>'L',
1237064143=>'L',
1237164144=>'L',
1237264145=>'L',
1237364146=>'L',
1237464147=>'L',
1237564148=>'L',
1237664149=>'L',
1237764150=>'L',
1237864151=>'L',
1237964152=>'L',
1238064153=>'L',
1238164154=>'L',
1238264155=>'L',
1238364156=>'L',
1238464157=>'L',
1238564158=>'L',
1238664159=>'L',
1238764160=>'L',
1238864161=>'L',
1238964162=>'L',
1239064163=>'L',
1239164164=>'L',
1239264165=>'L',
1239364166=>'L',
1239464167=>'L',
1239564168=>'L',
1239664169=>'L',
1239764170=>'L',
1239864171=>'L',
1239964172=>'L',
1240064173=>'L',
1240164174=>'L',
1240264175=>'L',
1240364176=>'L',
1240464177=>'L',
1240564178=>'L',
1240664179=>'L',
1240764180=>'L',
1240864181=>'L',
1240964182=>'L',
1241064183=>'L',
1241164184=>'L',
1241264185=>'L',
1241364186=>'L',
1241464187=>'L',
1241564188=>'L',
1241664189=>'L',
1241764190=>'L',
1241864191=>'L',
1241964192=>'L',
1242064193=>'L',
1242164194=>'L',
1242264195=>'L',
1242364196=>'L',
1242464197=>'L',
1242564198=>'L',
1242664199=>'L',
1242764200=>'L',
1242864201=>'L',
1242964202=>'L',
1243064203=>'L',
1243164204=>'L',
1243264205=>'L',
1243364206=>'L',
1243464207=>'L',
1243564208=>'L',
1243664209=>'L',
1243764210=>'L',
1243864211=>'L',
1243964212=>'L',
1244064213=>'L',
1244164214=>'L',
1244264215=>'L',
1244364216=>'L',
1244464217=>'L',
1244564256=>'L',
1244664257=>'L',
1244764258=>'L',
1244864259=>'L',
1244964260=>'L',
1245064261=>'L',
1245164262=>'L',
1245264275=>'L',
1245364276=>'L',
1245464277=>'L',
1245564278=>'L',
1245664279=>'L',
1245764285=>'R',
1245864286=>'NSM',
1245964287=>'R',
1246064288=>'R',
1246164289=>'R',
1246264290=>'R',
1246364291=>'R',
1246464292=>'R',
1246564293=>'R',
1246664294=>'R',
1246764295=>'R',
1246864296=>'R',
1246964297=>'ES',
1247064298=>'R',
1247164299=>'R',
1247264300=>'R',
1247364301=>'R',
1247464302=>'R',
1247564303=>'R',
1247664304=>'R',
1247764305=>'R',
1247864306=>'R',
1247964307=>'R',
1248064308=>'R',
1248164309=>'R',
1248264310=>'R',
1248364312=>'R',
1248464313=>'R',
1248564314=>'R',
1248664315=>'R',
1248764316=>'R',
1248864318=>'R',
1248964320=>'R',
1249064321=>'R',
1249164323=>'R',
1249264324=>'R',
1249364326=>'R',
1249464327=>'R',
1249564328=>'R',
1249664329=>'R',
1249764330=>'R',
1249864331=>'R',
1249964332=>'R',
1250064333=>'R',
1250164334=>'R',
1250264335=>'R',
1250364336=>'AL',
1250464337=>'AL',
1250564338=>'AL',
1250664339=>'AL',
1250764340=>'AL',
1250864341=>'AL',
1250964342=>'AL',
1251064343=>'AL',
1251164344=>'AL',
1251264345=>'AL',
1251364346=>'AL',
1251464347=>'AL',
1251564348=>'AL',
1251664349=>'AL',
1251764350=>'AL',
1251864351=>'AL',
1251964352=>'AL',
1252064353=>'AL',
1252164354=>'AL',
1252264355=>'AL',
1252364356=>'AL',
1252464357=>'AL',
1252564358=>'AL',
1252664359=>'AL',
1252764360=>'AL',
1252864361=>'AL',
1252964362=>'AL',
1253064363=>'AL',
1253164364=>'AL',
1253264365=>'AL',
1253364366=>'AL',
1253464367=>'AL',
1253564368=>'AL',
1253664369=>'AL',
1253764370=>'AL',
1253864371=>'AL',
1253964372=>'AL',
1254064373=>'AL',
1254164374=>'AL',
1254264375=>'AL',
1254364376=>'AL',
1254464377=>'AL',
1254564378=>'AL',
1254664379=>'AL',
1254764380=>'AL',
1254864381=>'AL',
1254964382=>'AL',
1255064383=>'AL',
1255164384=>'AL',
1255264385=>'AL',
1255364386=>'AL',
1255464387=>'AL',
1255564388=>'AL',
1255664389=>'AL',
1255764390=>'AL',
1255864391=>'AL',
1255964392=>'AL',
1256064393=>'AL',
1256164394=>'AL',
1256264395=>'AL',
1256364396=>'AL',
1256464397=>'AL',
1256564398=>'AL',
1256664399=>'AL',
1256764400=>'AL',
1256864401=>'AL',
1256964402=>'AL',
1257064403=>'AL',
1257164404=>'AL',
1257264405=>'AL',
1257364406=>'AL',
1257464407=>'AL',
1257564408=>'AL',
1257664409=>'AL',
1257764410=>'AL',
1257864411=>'AL',
1257964412=>'AL',
1258064413=>'AL',
1258164414=>'AL',
1258264415=>'AL',
1258364416=>'AL',
1258464417=>'AL',
1258564418=>'AL',
1258664419=>'AL',
1258764420=>'AL',
1258864421=>'AL',
1258964422=>'AL',
1259064423=>'AL',
1259164424=>'AL',
1259264425=>'AL',
1259364426=>'AL',
1259464427=>'AL',
1259564428=>'AL',
1259664429=>'AL',
1259764430=>'AL',
1259864431=>'AL',
1259964432=>'AL',
1260064433=>'AL',
1260164467=>'AL',
1260264468=>'AL',
1260364469=>'AL',
1260464470=>'AL',
1260564471=>'AL',
1260664472=>'AL',
1260764473=>'AL',
1260864474=>'AL',
1260964475=>'AL',
1261064476=>'AL',
1261164477=>'AL',
1261264478=>'AL',
1261364479=>'AL',
1261464480=>'AL',
1261564481=>'AL',
1261664482=>'AL',
1261764483=>'AL',
1261864484=>'AL',
1261964485=>'AL',
1262064486=>'AL',
1262164487=>'AL',
1262264488=>'AL',
1262364489=>'AL',
1262464490=>'AL',
1262564491=>'AL',
1262664492=>'AL',
1262764493=>'AL',
1262864494=>'AL',
1262964495=>'AL',
1263064496=>'AL',
1263164497=>'AL',
1263264498=>'AL',
1263364499=>'AL',
1263464500=>'AL',
1263564501=>'AL',
1263664502=>'AL',
1263764503=>'AL',
1263864504=>'AL',
1263964505=>'AL',
1264064506=>'AL',
1264164507=>'AL',
1264264508=>'AL',
1264364509=>'AL',
1264464510=>'AL',
1264564511=>'AL',
1264664512=>'AL',
1264764513=>'AL',
1264864514=>'AL',
1264964515=>'AL',
1265064516=>'AL',
1265164517=>'AL',
1265264518=>'AL',
1265364519=>'AL',
1265464520=>'AL',
1265564521=>'AL',
1265664522=>'AL',
1265764523=>'AL',
1265864524=>'AL',
1265964525=>'AL',
1266064526=>'AL',
1266164527=>'AL',
1266264528=>'AL',
1266364529=>'AL',
1266464530=>'AL',
1266564531=>'AL',
1266664532=>'AL',
1266764533=>'AL',
1266864534=>'AL',
1266964535=>'AL',
1267064536=>'AL',
1267164537=>'AL',
1267264538=>'AL',
1267364539=>'AL',
1267464540=>'AL',
1267564541=>'AL',
1267664542=>'AL',
1267764543=>'AL',
1267864544=>'AL',
1267964545=>'AL',
1268064546=>'AL',
1268164547=>'AL',
1268264548=>'AL',
1268364549=>'AL',
1268464550=>'AL',
1268564551=>'AL',
1268664552=>'AL',
1268764553=>'AL',
1268864554=>'AL',
1268964555=>'AL',
1269064556=>'AL',
1269164557=>'AL',
1269264558=>'AL',
1269364559=>'AL',
1269464560=>'AL',
1269564561=>'AL',
1269664562=>'AL',
1269764563=>'AL',
1269864564=>'AL',
1269964565=>'AL',
1270064566=>'AL',
1270164567=>'AL',
1270264568=>'AL',
1270364569=>'AL',
1270464570=>'AL',
1270564571=>'AL',
1270664572=>'AL',
1270764573=>'AL',
1270864574=>'AL',
1270964575=>'AL',
1271064576=>'AL',
1271164577=>'AL',
1271264578=>'AL',
1271364579=>'AL',
1271464580=>'AL',
1271564581=>'AL',
1271664582=>'AL',
1271764583=>'AL',
1271864584=>'AL',
1271964585=>'AL',
1272064586=>'AL',
1272164587=>'AL',
1272264588=>'AL',
1272364589=>'AL',
1272464590=>'AL',
1272564591=>'AL',
1272664592=>'AL',
1272764593=>'AL',
1272864594=>'AL',
1272964595=>'AL',
1273064596=>'AL',
1273164597=>'AL',
1273264598=>'AL',
1273364599=>'AL',
1273464600=>'AL',
1273564601=>'AL',
1273664602=>'AL',
1273764603=>'AL',
1273864604=>'AL',
1273964605=>'AL',
1274064606=>'AL',
1274164607=>'AL',
1274264608=>'AL',
1274364609=>'AL',
1274464610=>'AL',
1274564611=>'AL',
1274664612=>'AL',
1274764613=>'AL',
1274864614=>'AL',
1274964615=>'AL',
1275064616=>'AL',
1275164617=>'AL',
1275264618=>'AL',
1275364619=>'AL',
1275464620=>'AL',
1275564621=>'AL',
1275664622=>'AL',
1275764623=>'AL',
1275864624=>'AL',
1275964625=>'AL',
1276064626=>'AL',
1276164627=>'AL',
1276264628=>'AL',
1276364629=>'AL',
1276464630=>'AL',
1276564631=>'AL',
1276664632=>'AL',
1276764633=>'AL',
1276864634=>'AL',
1276964635=>'AL',
1277064636=>'AL',
1277164637=>'AL',
1277264638=>'AL',
1277364639=>'AL',
1277464640=>'AL',
1277564641=>'AL',
1277664642=>'AL',
1277764643=>'AL',
1277864644=>'AL',
1277964645=>'AL',
1278064646=>'AL',
1278164647=>'AL',
1278264648=>'AL',
1278364649=>'AL',
1278464650=>'AL',
1278564651=>'AL',
1278664652=>'AL',
1278764653=>'AL',
1278864654=>'AL',
1278964655=>'AL',
1279064656=>'AL',
1279164657=>'AL',
1279264658=>'AL',
1279364659=>'AL',
1279464660=>'AL',
1279564661=>'AL',
1279664662=>'AL',
1279764663=>'AL',
1279864664=>'AL',
1279964665=>'AL',
1280064666=>'AL',
1280164667=>'AL',
1280264668=>'AL',
1280364669=>'AL',
1280464670=>'AL',
1280564671=>'AL',
1280664672=>'AL',
1280764673=>'AL',
1280864674=>'AL',
1280964675=>'AL',
1281064676=>'AL',
1281164677=>'AL',
1281264678=>'AL',
1281364679=>'AL',
1281464680=>'AL',
1281564681=>'AL',
1281664682=>'AL',
1281764683=>'AL',
1281864684=>'AL',
1281964685=>'AL',
1282064686=>'AL',
1282164687=>'AL',
1282264688=>'AL',
1282364689=>'AL',
1282464690=>'AL',
1282564691=>'AL',
1282664692=>'AL',
1282764693=>'AL',
1282864694=>'AL',
1282964695=>'AL',
1283064696=>'AL',
1283164697=>'AL',
1283264698=>'AL',
1283364699=>'AL',
1283464700=>'AL',
1283564701=>'AL',
1283664702=>'AL',
1283764703=>'AL',
1283864704=>'AL',
1283964705=>'AL',
1284064706=>'AL',
1284164707=>'AL',
1284264708=>'AL',
1284364709=>'AL',
1284464710=>'AL',
1284564711=>'AL',
1284664712=>'AL',
1284764713=>'AL',
1284864714=>'AL',
1284964715=>'AL',
1285064716=>'AL',
1285164717=>'AL',
1285264718=>'AL',
1285364719=>'AL',
1285464720=>'AL',
1285564721=>'AL',
1285664722=>'AL',
1285764723=>'AL',
1285864724=>'AL',
1285964725=>'AL',
1286064726=>'AL',
1286164727=>'AL',
1286264728=>'AL',
1286364729=>'AL',
1286464730=>'AL',
1286564731=>'AL',
1286664732=>'AL',
1286764733=>'AL',
1286864734=>'AL',
1286964735=>'AL',
1287064736=>'AL',
1287164737=>'AL',
1287264738=>'AL',
1287364739=>'AL',
1287464740=>'AL',
1287564741=>'AL',
1287664742=>'AL',
1287764743=>'AL',
1287864744=>'AL',
1287964745=>'AL',
1288064746=>'AL',
1288164747=>'AL',
1288264748=>'AL',
1288364749=>'AL',
1288464750=>'AL',
1288564751=>'AL',
1288664752=>'AL',
1288764753=>'AL',
1288864754=>'AL',
1288964755=>'AL',
1289064756=>'AL',
1289164757=>'AL',
1289264758=>'AL',
1289364759=>'AL',
1289464760=>'AL',
1289564761=>'AL',
1289664762=>'AL',
1289764763=>'AL',
1289864764=>'AL',
1289964765=>'AL',
1290064766=>'AL',
1290164767=>'AL',
1290264768=>'AL',
1290364769=>'AL',
1290464770=>'AL',
1290564771=>'AL',
1290664772=>'AL',
1290764773=>'AL',
1290864774=>'AL',
1290964775=>'AL',
1291064776=>'AL',
1291164777=>'AL',
1291264778=>'AL',
1291364779=>'AL',
1291464780=>'AL',
1291564781=>'AL',
1291664782=>'AL',
1291764783=>'AL',
1291864784=>'AL',
1291964785=>'AL',
1292064786=>'AL',
1292164787=>'AL',
1292264788=>'AL',
1292364789=>'AL',
1292464790=>'AL',
1292564791=>'AL',
1292664792=>'AL',
1292764793=>'AL',
1292864794=>'AL',
1292964795=>'AL',
1293064796=>'AL',
1293164797=>'AL',
1293264798=>'AL',
1293364799=>'AL',
1293464800=>'AL',
1293564801=>'AL',
1293664802=>'AL',
1293764803=>'AL',
1293864804=>'AL',
1293964805=>'AL',
1294064806=>'AL',
1294164807=>'AL',
1294264808=>'AL',
1294364809=>'AL',
1294464810=>'AL',
1294564811=>'AL',
1294664812=>'AL',
1294764813=>'AL',
1294864814=>'AL',
1294964815=>'AL',
1295064816=>'AL',
1295164817=>'AL',
1295264818=>'AL',
1295364819=>'AL',
1295464820=>'AL',
1295564821=>'AL',
1295664822=>'AL',
1295764823=>'AL',
1295864824=>'AL',
1295964825=>'AL',
1296064826=>'AL',
1296164827=>'AL',
1296264828=>'AL',
1296364829=>'AL',
1296464830=>'ON',
1296564831=>'ON',
1296664848=>'AL',
1296764849=>'AL',
1296864850=>'AL',
1296964851=>'AL',
1297064852=>'AL',
1297164853=>'AL',
1297264854=>'AL',
1297364855=>'AL',
1297464856=>'AL',
1297564857=>'AL',
1297664858=>'AL',
1297764859=>'AL',
1297864860=>'AL',
1297964861=>'AL',
1298064862=>'AL',
1298164863=>'AL',
1298264864=>'AL',
1298364865=>'AL',
1298464866=>'AL',
1298564867=>'AL',
1298664868=>'AL',
1298764869=>'AL',
1298864870=>'AL',
1298964871=>'AL',
1299064872=>'AL',
1299164873=>'AL',
1299264874=>'AL',
1299364875=>'AL',
1299464876=>'AL',
1299564877=>'AL',
1299664878=>'AL',
1299764879=>'AL',
1299864880=>'AL',
1299964881=>'AL',
1300064882=>'AL',
1300164883=>'AL',
1300264884=>'AL',
1300364885=>'AL',
1300464886=>'AL',
1300564887=>'AL',
1300664888=>'AL',
1300764889=>'AL',
1300864890=>'AL',
1300964891=>'AL',
1301064892=>'AL',
1301164893=>'AL',
1301264894=>'AL',
1301364895=>'AL',
1301464896=>'AL',
1301564897=>'AL',
1301664898=>'AL',
1301764899=>'AL',
1301864900=>'AL',
1301964901=>'AL',
1302064902=>'AL',
1302164903=>'AL',
1302264904=>'AL',
1302364905=>'AL',
1302464906=>'AL',
1302564907=>'AL',
1302664908=>'AL',
1302764909=>'AL',
1302864910=>'AL',
1302964911=>'AL',
1303064914=>'AL',
1303164915=>'AL',
1303264916=>'AL',
1303364917=>'AL',
1303464918=>'AL',
1303564919=>'AL',
1303664920=>'AL',
1303764921=>'AL',
1303864922=>'AL',
1303964923=>'AL',
1304064924=>'AL',
1304164925=>'AL',
1304264926=>'AL',
1304364927=>'AL',
1304464928=>'AL',
1304564929=>'AL',
1304664930=>'AL',
1304764931=>'AL',
1304864932=>'AL',
1304964933=>'AL',
1305064934=>'AL',
1305164935=>'AL',
1305264936=>'AL',
1305364937=>'AL',
1305464938=>'AL',
1305564939=>'AL',
1305664940=>'AL',
1305764941=>'AL',
1305864942=>'AL',
1305964943=>'AL',
1306064944=>'AL',
1306164945=>'AL',
1306264946=>'AL',
1306364947=>'AL',
1306464948=>'AL',
1306564949=>'AL',
1306664950=>'AL',
1306764951=>'AL',
1306864952=>'AL',
1306964953=>'AL',
1307064954=>'AL',
1307164955=>'AL',
1307264956=>'AL',
1307364957=>'AL',
1307464958=>'AL',
1307564959=>'AL',
1307664960=>'AL',
1307764961=>'AL',
1307864962=>'AL',
1307964963=>'AL',
1308064964=>'AL',
1308164965=>'AL',
1308264966=>'AL',
1308364967=>'AL',
1308465008=>'AL',
1308565009=>'AL',
1308665010=>'AL',
1308765011=>'AL',
1308865012=>'AL',
1308965013=>'AL',
1309065014=>'AL',
1309165015=>'AL',
1309265016=>'AL',
1309365017=>'AL',
1309465018=>'AL',
1309565019=>'AL',
1309665020=>'AL',
1309765021=>'ON',
1309865024=>'NSM',
1309965025=>'NSM',
1310065026=>'NSM',
1310165027=>'NSM',
1310265028=>'NSM',
1310365029=>'NSM',
1310465030=>'NSM',
1310565031=>'NSM',
1310665032=>'NSM',
1310765033=>'NSM',
1310865034=>'NSM',
1310965035=>'NSM',
1311065036=>'NSM',
1311165037=>'NSM',
1311265038=>'NSM',
1311365039=>'NSM',
1311465040=>'ON',
1311565041=>'ON',
1311665042=>'ON',
1311765043=>'ON',
1311865044=>'ON',
1311965045=>'ON',
1312065046=>'ON',
1312165047=>'ON',
1312265048=>'ON',
1312365049=>'ON',
1312465056=>'NSM',
1312565057=>'NSM',
1312665058=>'NSM',
1312765059=>'NSM',
1312865072=>'ON',
1312965073=>'ON',
1313065074=>'ON',
1313165075=>'ON',
1313265076=>'ON',
1313365077=>'ON',
1313465078=>'ON',
1313565079=>'ON',
1313665080=>'ON',
1313765081=>'ON',
1313865082=>'ON',
1313965083=>'ON',
1314065084=>'ON',
1314165085=>'ON',
1314265086=>'ON',
1314365087=>'ON',
1314465088=>'ON',
1314565089=>'ON',
1314665090=>'ON',
1314765091=>'ON',
1314865092=>'ON',
1314965093=>'ON',
1315065094=>'ON',
1315165095=>'ON',
1315265096=>'ON',
1315365097=>'ON',
1315465098=>'ON',
1315565099=>'ON',
1315665100=>'ON',
1315765101=>'ON',
1315865102=>'ON',
1315965103=>'ON',
1316065104=>'CS',
1316165105=>'ON',
1316265106=>'CS',
1316365108=>'ON',
1316465109=>'CS',
1316565110=>'ON',
1316665111=>'ON',
1316765112=>'ON',
1316865113=>'ON',
1316965114=>'ON',
1317065115=>'ON',
1317165116=>'ON',
1317265117=>'ON',
1317365118=>'ON',
1317465119=>'ET',
1317565120=>'ON',
1317665121=>'ON',
1317765122=>'ES',
1317865123=>'ES',
1317965124=>'ON',
1318065125=>'ON',
1318165126=>'ON',
1318265128=>'ON',
1318365129=>'ET',
1318465130=>'ET',
1318565131=>'ON',
1318665136=>'AL',
1318765137=>'AL',
1318865138=>'AL',
1318965139=>'AL',
1319065140=>'AL',
1319165142=>'AL',
1319265143=>'AL',
1319365144=>'AL',
1319465145=>'AL',
1319565146=>'AL',
1319665147=>'AL',
1319765148=>'AL',
1319865149=>'AL',
1319965150=>'AL',
1320065151=>'AL',
1320165152=>'AL',
1320265153=>'AL',
1320365154=>'AL',
1320465155=>'AL',
1320565156=>'AL',
1320665157=>'AL',
1320765158=>'AL',
1320865159=>'AL',
1320965160=>'AL',
1321065161=>'AL',
1321165162=>'AL',
1321265163=>'AL',
1321365164=>'AL',
1321465165=>'AL',
1321565166=>'AL',
1321665167=>'AL',
1321765168=>'AL',
1321865169=>'AL',
1321965170=>'AL',
1322065171=>'AL',
1322165172=>'AL',
1322265173=>'AL',
1322365174=>'AL',
1322465175=>'AL',
1322565176=>'AL',
1322665177=>'AL',
1322765178=>'AL',
1322865179=>'AL',
1322965180=>'AL',
1323065181=>'AL',
1323165182=>'AL',
1323265183=>'AL',
1323365184=>'AL',
1323465185=>'AL',
1323565186=>'AL',
1323665187=>'AL',
1323765188=>'AL',
1323865189=>'AL',
1323965190=>'AL',
1324065191=>'AL',
1324165192=>'AL',
1324265193=>'AL',
1324365194=>'AL',
1324465195=>'AL',
1324565196=>'AL',
1324665197=>'AL',
1324765198=>'AL',
1324865199=>'AL',
1324965200=>'AL',
1325065201=>'AL',
1325165202=>'AL',
1325265203=>'AL',
1325365204=>'AL',
1325465205=>'AL',
1325565206=>'AL',
1325665207=>'AL',
1325765208=>'AL',
1325865209=>'AL',
1325965210=>'AL',
1326065211=>'AL',
1326165212=>'AL',
1326265213=>'AL',
1326365214=>'AL',
1326465215=>'AL',
1326565216=>'AL',
1326665217=>'AL',
1326765218=>'AL',
1326865219=>'AL',
1326965220=>'AL',
1327065221=>'AL',
1327165222=>'AL',
1327265223=>'AL',
1327365224=>'AL',
1327465225=>'AL',
1327565226=>'AL',
1327665227=>'AL',
1327765228=>'AL',
1327865229=>'AL',
1327965230=>'AL',
1328065231=>'AL',
1328165232=>'AL',
1328265233=>'AL',
1328365234=>'AL',
1328465235=>'AL',
1328565236=>'AL',
1328665237=>'AL',
1328765238=>'AL',
1328865239=>'AL',
1328965240=>'AL',
1329065241=>'AL',
1329165242=>'AL',
1329265243=>'AL',
1329365244=>'AL',
1329465245=>'AL',
1329565246=>'AL',
1329665247=>'AL',
1329765248=>'AL',
1329865249=>'AL',
1329965250=>'AL',
1330065251=>'AL',
1330165252=>'AL',
1330265253=>'AL',
1330365254=>'AL',
1330465255=>'AL',
1330565256=>'AL',
1330665257=>'AL',
1330765258=>'AL',
1330865259=>'AL',
1330965260=>'AL',
1331065261=>'AL',
1331165262=>'AL',
1331265263=>'AL',
1331365264=>'AL',
1331465265=>'AL',
1331565266=>'AL',
1331665267=>'AL',
1331765268=>'AL',
1331865269=>'AL',
1331965270=>'AL',
1332065271=>'AL',
1332165272=>'AL',
1332265273=>'AL',
1332365274=>'AL',
1332465275=>'AL',
1332565276=>'AL',
1332665279=>'BN',
1332765281=>'ON',
1332865282=>'ON',
1332965283=>'ET',
1333065284=>'ET',
1333165285=>'ET',
1333265286=>'ON',
1333365287=>'ON',
1333465288=>'ON',
1333565289=>'ON',
1333665290=>'ON',
1333765291=>'ES',
1333865292=>'CS',
1333965293=>'ES',
1334065294=>'CS',
1334165295=>'CS',
1334265296=>'EN',
1334365297=>'EN',
1334465298=>'EN',
1334565299=>'EN',
1334665300=>'EN',
1334765301=>'EN',
1334865302=>'EN',
1334965303=>'EN',
1335065304=>'EN',
1335165305=>'EN',
1335265306=>'CS',
1335365307=>'ON',
1335465308=>'ON',
1335565309=>'ON',
1335665310=>'ON',
1335765311=>'ON',
1335865312=>'ON',
1335965313=>'L',
1336065314=>'L',
1336165315=>'L',
1336265316=>'L',
1336365317=>'L',
1336465318=>'L',
1336565319=>'L',
1336665320=>'L',
1336765321=>'L',
1336865322=>'L',
1336965323=>'L',
1337065324=>'L',
1337165325=>'L',
1337265326=>'L',
1337365327=>'L',
1337465328=>'L',
1337565329=>'L',
1337665330=>'L',
1337765331=>'L',
1337865332=>'L',
1337965333=>'L',
1338065334=>'L',
1338165335=>'L',
1338265336=>'L',
1338365337=>'L',
1338465338=>'L',
1338565339=>'ON',
1338665340=>'ON',
1338765341=>'ON',
1338865342=>'ON',
1338965343=>'ON',
1339065344=>'ON',
1339165345=>'L',
1339265346=>'L',
1339365347=>'L',
1339465348=>'L',
1339565349=>'L',
1339665350=>'L',
1339765351=>'L',
1339865352=>'L',
1339965353=>'L',
1340065354=>'L',
1340165355=>'L',
1340265356=>'L',
1340365357=>'L',
1340465358=>'L',
1340565359=>'L',
1340665360=>'L',
1340765361=>'L',
1340865362=>'L',
1340965363=>'L',
1341065364=>'L',
1341165365=>'L',
1341265366=>'L',
1341365367=>'L',
1341465368=>'L',
1341565369=>'L',
1341665370=>'L',
1341765371=>'ON',
1341865372=>'ON',
1341965373=>'ON',
1342065374=>'ON',
1342165375=>'ON',
1342265376=>'ON',
1342365377=>'ON',
1342465378=>'ON',
1342565379=>'ON',
1342665380=>'ON',
1342765381=>'ON',
1342865382=>'L',
1342965383=>'L',
1343065384=>'L',
1343165385=>'L',
1343265386=>'L',
1343365387=>'L',
1343465388=>'L',
1343565389=>'L',
1343665390=>'L',
1343765391=>'L',
1343865392=>'L',
1343965393=>'L',
1344065394=>'L',
1344165395=>'L',
1344265396=>'L',
1344365397=>'L',
1344465398=>'L',
1344565399=>'L',
1344665400=>'L',
1344765401=>'L',
1344865402=>'L',
1344965403=>'L',
1345065404=>'L',
1345165405=>'L',
1345265406=>'L',
1345365407=>'L',
1345465408=>'L',
1345565409=>'L',
1345665410=>'L',
1345765411=>'L',
1345865412=>'L',
1345965413=>'L',
1346065414=>'L',
1346165415=>'L',
1346265416=>'L',
1346365417=>'L',
1346465418=>'L',
1346565419=>'L',
1346665420=>'L',
1346765421=>'L',
1346865422=>'L',
1346965423=>'L',
1347065424=>'L',
1347165425=>'L',
1347265426=>'L',
1347365427=>'L',
1347465428=>'L',
1347565429=>'L',
1347665430=>'L',
1347765431=>'L',
1347865432=>'L',
1347965433=>'L',
1348065434=>'L',
1348165435=>'L',
1348265436=>'L',
1348365437=>'L',
1348465438=>'L',
1348565439=>'L',
1348665440=>'L',
1348765441=>'L',
1348865442=>'L',
1348965443=>'L',
1349065444=>'L',
1349165445=>'L',
1349265446=>'L',
1349365447=>'L',
1349465448=>'L',
1349565449=>'L',
1349665450=>'L',
1349765451=>'L',
1349865452=>'L',
1349965453=>'L',
1350065454=>'L',
1350165455=>'L',
1350265456=>'L',
1350365457=>'L',
1350465458=>'L',
1350565459=>'L',
1350665460=>'L',
1350765461=>'L',
1350865462=>'L',
1350965463=>'L',
1351065464=>'L',
1351165465=>'L',
1351265466=>'L',
1351365467=>'L',
1351465468=>'L',
1351565469=>'L',
1351665470=>'L',
1351765474=>'L',
1351865475=>'L',
1351965476=>'L',
1352065477=>'L',
1352165478=>'L',
1352265479=>'L',
1352365482=>'L',
1352465483=>'L',
1352565484=>'L',
1352665485=>'L',
1352765486=>'L',
1352865487=>'L',
1352965490=>'L',
1353065491=>'L',
1353165492=>'L',
1353265493=>'L',
1353365494=>'L',
1353465495=>'L',
1353565498=>'L',
1353665499=>'L',
1353765500=>'L',
1353865504=>'ET',
1353965505=>'ET',
1354065506=>'ON',
1354165507=>'ON',
1354265508=>'ON',
1354365509=>'ET',
1354465510=>'ET',
1354565512=>'ON',
1354665513=>'ON',
1354765514=>'ON',
1354865515=>'ON',
1354965516=>'ON',
1355065517=>'ON',
1355165518=>'ON',
1355265529=>'ON',
1355365530=>'ON',
1355465531=>'ON',
1355565532=>'ON',
1355665533=>'ON',
1355765536=>'L',
1355865537=>'L',
1355965538=>'L',
1356065539=>'L',
1356165540=>'L',
1356265541=>'L',
1356365542=>'L',
1356465543=>'L',
1356565544=>'L',
1356665545=>'L',
1356765546=>'L',
1356865547=>'L',
1356965549=>'L',
1357065550=>'L',
1357165551=>'L',
1357265552=>'L',
1357365553=>'L',
1357465554=>'L',
1357565555=>'L',
1357665556=>'L',
1357765557=>'L',
1357865558=>'L',
1357965559=>'L',
1358065560=>'L',
1358165561=>'L',
1358265562=>'L',
1358365563=>'L',
1358465564=>'L',
1358565565=>'L',
1358665566=>'L',
1358765567=>'L',
1358865568=>'L',
1358965569=>'L',
1359065570=>'L',
1359165571=>'L',
1359265572=>'L',
1359365573=>'L',
1359465574=>'L',
1359565576=>'L',
1359665577=>'L',
1359765578=>'L',
1359865579=>'L',
1359965580=>'L',
1360065581=>'L',
1360165582=>'L',
1360265583=>'L',
1360365584=>'L',
1360465585=>'L',
1360565586=>'L',
1360665587=>'L',
1360765588=>'L',
1360865589=>'L',
1360965590=>'L',
1361065591=>'L',
1361165592=>'L',
1361265593=>'L',
1361365594=>'L',
1361465596=>'L',
1361565597=>'L',
1361665599=>'L',
1361765600=>'L',
1361865601=>'L',
1361965602=>'L',
1362065603=>'L',
1362165604=>'L',
1362265605=>'L',
1362365606=>'L',
1362465607=>'L',
1362565608=>'L',
1362665609=>'L',
1362765610=>'L',
1362865611=>'L',
1362965612=>'L',
1363065613=>'L',
1363165616=>'L',
1363265617=>'L',
1363365618=>'L',
1363465619=>'L',
1363565620=>'L',
1363665621=>'L',
1363765622=>'L',
1363865623=>'L',
1363965624=>'L',
1364065625=>'L',
1364165626=>'L',
1364265627=>'L',
1364365628=>'L',
1364465629=>'L',
1364565664=>'L',
1364665665=>'L',
1364765666=>'L',
1364865667=>'L',
1364965668=>'L',
1365065669=>'L',
1365165670=>'L',
1365265671=>'L',
1365365672=>'L',
1365465673=>'L',
1365565674=>'L',
1365665675=>'L',
1365765676=>'L',
1365865677=>'L',
1365965678=>'L',
1366065679=>'L',
1366165680=>'L',
1366265681=>'L',
1366365682=>'L',
1366465683=>'L',
1366565684=>'L',
1366665685=>'L',
1366765686=>'L',
1366865687=>'L',
1366965688=>'L',
1367065689=>'L',
1367165690=>'L',
1367265691=>'L',
1367365692=>'L',
1367465693=>'L',
1367565694=>'L',
1367665695=>'L',
1367765696=>'L',
1367865697=>'L',
1367965698=>'L',
1368065699=>'L',
1368165700=>'L',
1368265701=>'L',
1368365702=>'L',
1368465703=>'L',
1368565704=>'L',
1368665705=>'L',
1368765706=>'L',
1368865707=>'L',
1368965708=>'L',
1369065709=>'L',
1369165710=>'L',
1369265711=>'L',
1369365712=>'L',
1369465713=>'L',
1369565714=>'L',
1369665715=>'L',
1369765716=>'L',
1369865717=>'L',
1369965718=>'L',
1370065719=>'L',
1370165720=>'L',
1370265721=>'L',
1370365722=>'L',
1370465723=>'L',
1370565724=>'L',
1370665725=>'L',
1370765726=>'L',
1370865727=>'L',
1370965728=>'L',
1371065729=>'L',
1371165730=>'L',
1371265731=>'L',
1371365732=>'L',
1371465733=>'L',
1371565734=>'L',
1371665735=>'L',
1371765736=>'L',
1371865737=>'L',
1371965738=>'L',
1372065739=>'L',
1372165740=>'L',
1372265741=>'L',
1372365742=>'L',
1372465743=>'L',
1372565744=>'L',
1372665745=>'L',
1372765746=>'L',
1372865747=>'L',
1372965748=>'L',
1373065749=>'L',
1373165750=>'L',
1373265751=>'L',
1373365752=>'L',
1373465753=>'L',
1373565754=>'L',
1373665755=>'L',
1373765756=>'L',
1373865757=>'L',
1373965758=>'L',
1374065759=>'L',
1374165760=>'L',
1374265761=>'L',
1374365762=>'L',
1374465763=>'L',
1374565764=>'L',
1374665765=>'L',
1374765766=>'L',
1374865767=>'L',
1374965768=>'L',
1375065769=>'L',
1375165770=>'L',
1375265771=>'L',
1375365772=>'L',
1375465773=>'L',
1375565774=>'L',
1375665775=>'L',
1375765776=>'L',
1375865777=>'L',
1375965778=>'L',
1376065779=>'L',
1376165780=>'L',
1376265781=>'L',
1376365782=>'L',
1376465783=>'L',
1376565784=>'L',
1376665785=>'L',
1376765786=>'L',
1376865792=>'L',
1376965793=>'ON',
1377065794=>'L',
1377165799=>'L',
1377265800=>'L',
1377365801=>'L',
1377465802=>'L',
1377565803=>'L',
1377665804=>'L',
1377765805=>'L',
1377865806=>'L',
1377965807=>'L',
1378065808=>'L',
1378165809=>'L',
1378265810=>'L',
1378365811=>'L',
1378465812=>'L',
1378565813=>'L',
1378665814=>'L',
1378765815=>'L',
1378865816=>'L',
1378965817=>'L',
1379065818=>'L',
1379165819=>'L',
1379265820=>'L',
1379365821=>'L',
1379465822=>'L',
1379565823=>'L',
1379665824=>'L',
1379765825=>'L',
1379865826=>'L',
1379965827=>'L',
1380065828=>'L',
1380165829=>'L',
1380265830=>'L',
1380365831=>'L',
1380465832=>'L',
1380565833=>'L',
1380665834=>'L',
1380765835=>'L',
1380865836=>'L',
1380965837=>'L',
1381065838=>'L',
1381165839=>'L',
1381265840=>'L',
1381365841=>'L',
1381465842=>'L',
1381565843=>'L',
1381665847=>'L',
1381765848=>'L',
1381865849=>'L',
1381965850=>'L',
1382065851=>'L',
1382165852=>'L',
1382265853=>'L',
1382365854=>'L',
1382465855=>'L',
1382565856=>'ON',
1382665857=>'ON',
1382765858=>'ON',
1382865859=>'ON',
1382965860=>'ON',
1383065861=>'ON',
1383165862=>'ON',
1383265863=>'ON',
1383365864=>'ON',
1383465865=>'ON',
1383565866=>'ON',
1383665867=>'ON',
1383765868=>'ON',
1383865869=>'ON',
1383965870=>'ON',
1384065871=>'ON',
1384165872=>'ON',
1384265873=>'ON',
1384365874=>'ON',
1384465875=>'ON',
1384565876=>'ON',
1384665877=>'ON',
1384765878=>'ON',
1384865879=>'ON',
1384965880=>'ON',
1385065881=>'ON',
1385165882=>'ON',
1385265883=>'ON',
1385365884=>'ON',
1385465885=>'ON',
1385565886=>'ON',
1385665887=>'ON',
1385765888=>'ON',
1385865889=>'ON',
1385965890=>'ON',
1386065891=>'ON',
1386165892=>'ON',
1386265893=>'ON',
1386365894=>'ON',
1386465895=>'ON',
1386565896=>'ON',
1386665897=>'ON',
1386765898=>'ON',
1386865899=>'ON',
1386965900=>'ON',
1387065901=>'ON',
1387165902=>'ON',
1387265903=>'ON',
1387365904=>'ON',
1387465905=>'ON',
1387565906=>'ON',
1387665907=>'ON',
1387765908=>'ON',
1387865909=>'ON',
1387965910=>'ON',
1388065911=>'ON',
1388165912=>'ON',
1388265913=>'ON',
1388365914=>'ON',
1388465915=>'ON',
1388565916=>'ON',
1388665917=>'ON',
1388765918=>'ON',
1388865919=>'ON',
1388965920=>'ON',
1389065921=>'ON',
1389165922=>'ON',
1389265923=>'ON',
1389365924=>'ON',
1389465925=>'ON',
1389565926=>'ON',
1389665927=>'ON',
1389765928=>'ON',
1389865929=>'ON',
1389965930=>'ON',
1390066304=>'L',
1390166305=>'L',
1390266306=>'L',
1390366307=>'L',
1390466308=>'L',
1390566309=>'L',
1390666310=>'L',
1390766311=>'L',
1390866312=>'L',
1390966313=>'L',
1391066314=>'L',
1391166315=>'L',
1391266316=>'L',
1391366317=>'L',
1391466318=>'L',
1391566319=>'L',
1391666320=>'L',
1391766321=>'L',
1391866322=>'L',
1391966323=>'L',
1392066324=>'L',
1392166325=>'L',
1392266326=>'L',
1392366327=>'L',
1392466328=>'L',
1392566329=>'L',
1392666330=>'L',
1392766331=>'L',
1392866332=>'L',
1392966333=>'L',
1393066334=>'L',
1393166336=>'L',
1393266337=>'L',
1393366338=>'L',
1393466339=>'L',
1393566352=>'L',
1393666353=>'L',
1393766354=>'L',
1393866355=>'L',
1393966356=>'L',
1394066357=>'L',
1394166358=>'L',
1394266359=>'L',
1394366360=>'L',
1394466361=>'L',
1394566362=>'L',
1394666363=>'L',
1394766364=>'L',
1394866365=>'L',
1394966366=>'L',
1395066367=>'L',
1395166368=>'L',
1395266369=>'L',
1395366370=>'L',
1395466371=>'L',
1395566372=>'L',
1395666373=>'L',
1395766374=>'L',
1395866375=>'L',
1395966376=>'L',
1396066377=>'L',
1396166378=>'L',
1396266432=>'L',
1396366433=>'L',
1396466434=>'L',
1396566435=>'L',
1396666436=>'L',
1396766437=>'L',
1396866438=>'L',
1396966439=>'L',
1397066440=>'L',
1397166441=>'L',
1397266442=>'L',
1397366443=>'L',
1397466444=>'L',
1397566445=>'L',
1397666446=>'L',
1397766447=>'L',
1397866448=>'L',
1397966449=>'L',
1398066450=>'L',
1398166451=>'L',
1398266452=>'L',
1398366453=>'L',
1398466454=>'L',
1398566455=>'L',
1398666456=>'L',
1398766457=>'L',
1398866458=>'L',
1398966459=>'L',
1399066460=>'L',
1399166461=>'L',
1399266463=>'L',
1399366464=>'L',
1399466465=>'L',
1399566466=>'L',
1399666467=>'L',
1399766468=>'L',
1399866469=>'L',
1399966470=>'L',
1400066471=>'L',
1400166472=>'L',
1400266473=>'L',
1400366474=>'L',
1400466475=>'L',
1400566476=>'L',
1400666477=>'L',
1400766478=>'L',
1400866479=>'L',
1400966480=>'L',
1401066481=>'L',
1401166482=>'L',
1401266483=>'L',
1401366484=>'L',
1401466485=>'L',
1401566486=>'L',
1401666487=>'L',
1401766488=>'L',
1401866489=>'L',
1401966490=>'L',
1402066491=>'L',
1402166492=>'L',
1402266493=>'L',
1402366494=>'L',
1402466495=>'L',
1402566496=>'L',
1402666497=>'L',
1402766498=>'L',
1402866499=>'L',
1402966504=>'L',
1403066505=>'L',
1403166506=>'L',
1403266507=>'L',
1403366508=>'L',
1403466509=>'L',
1403566510=>'L',
1403666511=>'L',
1403766512=>'L',
1403866513=>'L',
1403966514=>'L',
1404066515=>'L',
1404166516=>'L',
1404266517=>'L',
1404366560=>'L',
1404466561=>'L',
1404566562=>'L',
1404666563=>'L',
1404766564=>'L',
1404866565=>'L',
1404966566=>'L',
1405066567=>'L',
1405166568=>'L',
1405266569=>'L',
1405366570=>'L',
1405466571=>'L',
1405566572=>'L',
1405666573=>'L',
1405766574=>'L',
1405866575=>'L',
1405966576=>'L',
1406066577=>'L',
1406166578=>'L',
1406266579=>'L',
1406366580=>'L',
1406466581=>'L',
1406566582=>'L',
1406666583=>'L',
1406766584=>'L',
1406866585=>'L',
1406966586=>'L',
1407066587=>'L',
1407166588=>'L',
1407266589=>'L',
1407366590=>'L',
1407466591=>'L',
1407566592=>'L',
1407666593=>'L',
1407766594=>'L',
1407866595=>'L',
1407966596=>'L',
1408066597=>'L',
1408166598=>'L',
1408266599=>'L',
1408366600=>'L',
1408466601=>'L',
1408566602=>'L',
1408666603=>'L',
1408766604=>'L',
1408866605=>'L',
1408966606=>'L',
1409066607=>'L',
1409166608=>'L',
1409266609=>'L',
1409366610=>'L',
1409466611=>'L',
1409566612=>'L',
1409666613=>'L',
1409766614=>'L',
1409866615=>'L',
1409966616=>'L',
1410066617=>'L',
1410166618=>'L',
1410266619=>'L',
1410366620=>'L',
1410466621=>'L',
1410566622=>'L',
1410666623=>'L',
1410766624=>'L',
1410866625=>'L',
1410966626=>'L',
1411066627=>'L',
1411166628=>'L',
1411266629=>'L',
1411366630=>'L',
1411466631=>'L',
1411566632=>'L',
1411666633=>'L',
1411766634=>'L',
1411866635=>'L',
1411966636=>'L',
1412066637=>'L',
1412166638=>'L',
1412266639=>'L',
1412366640=>'L',
1412466641=>'L',
1412566642=>'L',
1412666643=>'L',
1412766644=>'L',
1412866645=>'L',
1412966646=>'L',
1413066647=>'L',
1413166648=>'L',
1413266649=>'L',
1413366650=>'L',
1413466651=>'L',
1413566652=>'L',
1413666653=>'L',
1413766654=>'L',
1413866655=>'L',
1413966656=>'L',
1414066657=>'L',
1414166658=>'L',
1414266659=>'L',
1414366660=>'L',
1414466661=>'L',
1414566662=>'L',
1414666663=>'L',
1414766664=>'L',
1414866665=>'L',
1414966666=>'L',
1415066667=>'L',
1415166668=>'L',
1415266669=>'L',
1415366670=>'L',
1415466671=>'L',
1415566672=>'L',
1415666673=>'L',
1415766674=>'L',
1415866675=>'L',
1415966676=>'L',
1416066677=>'L',
1416166678=>'L',
1416266679=>'L',
1416366680=>'L',
1416466681=>'L',
1416566682=>'L',
1416666683=>'L',
1416766684=>'L',
1416866685=>'L',
1416966686=>'L',
1417066687=>'L',
1417166688=>'L',
1417266689=>'L',
1417366690=>'L',
1417466691=>'L',
1417566692=>'L',
1417666693=>'L',
1417766694=>'L',
1417866695=>'L',
1417966696=>'L',
1418066697=>'L',
1418166698=>'L',
1418266699=>'L',
1418366700=>'L',
1418466701=>'L',
1418566702=>'L',
1418666703=>'L',
1418766704=>'L',
1418866705=>'L',
1418966706=>'L',
1419066707=>'L',
1419166708=>'L',
1419266709=>'L',
1419366710=>'L',
1419466711=>'L',
1419566712=>'L',
1419666713=>'L',
1419766714=>'L',
1419866715=>'L',
1419966716=>'L',
1420066717=>'L',
1420166720=>'L',
1420266721=>'L',
1420366722=>'L',
1420466723=>'L',
1420566724=>'L',
1420666725=>'L',
1420766726=>'L',
1420866727=>'L',
1420966728=>'L',
1421066729=>'L',
1421167584=>'R',
1421267585=>'R',
1421367586=>'R',
1421467587=>'R',
1421567588=>'R',
1421667589=>'R',
1421767592=>'R',
1421867594=>'R',
1421967595=>'R',
1422067596=>'R',
1422167597=>'R',
1422267598=>'R',
1422367599=>'R',
1422467600=>'R',
1422567601=>'R',
1422667602=>'R',
1422767603=>'R',
1422867604=>'R',
1422967605=>'R',
1423067606=>'R',
1423167607=>'R',
1423267608=>'R',
1423367609=>'R',
1423467610=>'R',
1423567611=>'R',
1423667612=>'R',
1423767613=>'R',
1423867614=>'R',
1423967615=>'R',
1424067616=>'R',
1424167617=>'R',
1424267618=>'R',
1424367619=>'R',
1424467620=>'R',
1424567621=>'R',
1424667622=>'R',
1424767623=>'R',
1424867624=>'R',
1424967625=>'R',
1425067626=>'R',
1425167627=>'R',
1425267628=>'R',
1425367629=>'R',
1425467630=>'R',
1425567631=>'R',
1425667632=>'R',
1425767633=>'R',
1425867634=>'R',
1425967635=>'R',
1426067636=>'R',
1426167637=>'R',
1426267639=>'R',
1426367640=>'R',
1426467644=>'R',
1426567647=>'R',
1426667840=>'R',
1426767841=>'R',
1426867842=>'R',
1426967843=>'R',
1427067844=>'R',
1427167845=>'R',
1427267846=>'R',
1427367847=>'R',
1427467848=>'R',
1427567849=>'R',
1427667850=>'R',
1427767851=>'R',
1427867852=>'R',
1427967853=>'R',
1428067854=>'R',
1428167855=>'R',
1428267856=>'R',
1428367857=>'R',
1428467858=>'R',
1428567859=>'R',
1428667860=>'R',
1428767861=>'R',
1428867862=>'R',
1428967863=>'R',
1429067864=>'R',
1429167865=>'R',
1429267871=>'ON',
1429368096=>'R',
1429468097=>'NSM',
1429568098=>'NSM',
1429668099=>'NSM',
1429768101=>'NSM',
1429868102=>'NSM',
1429968108=>'NSM',
1430068109=>'NSM',
1430168110=>'NSM',
1430268111=>'NSM',
1430368112=>'R',
1430468113=>'R',
1430568114=>'R',
1430668115=>'R',
1430768117=>'R',
1430868118=>'R',
1430968119=>'R',
1431068121=>'R',
1431168122=>'R',
1431268123=>'R',
1431368124=>'R',
1431468125=>'R',
1431568126=>'R',
1431668127=>'R',
1431768128=>'R',
1431868129=>'R',
1431968130=>'R',
1432068131=>'R',
1432168132=>'R',
1432268133=>'R',
1432368134=>'R',
1432468135=>'R',
1432568136=>'R',
1432668137=>'R',
1432768138=>'R',
1432868139=>'R',
1432968140=>'R',
1433068141=>'R',
1433168142=>'R',
1433268143=>'R',
1433368144=>'R',
1433468145=>'R',
1433568146=>'R',
1433668147=>'R',
1433768152=>'NSM',
1433868153=>'NSM',
1433968154=>'NSM',
1434068159=>'NSM',
1434168160=>'R',
1434268161=>'R',
1434368162=>'R',
1434468163=>'R',
1434568164=>'R',
1434668165=>'R',
1434768166=>'R',
1434868167=>'R',
1434968176=>'R',
1435068177=>'R',
1435168178=>'R',
1435268179=>'R',
1435368180=>'R',
1435468181=>'R',
1435568182=>'R',
1435668183=>'R',
1435768184=>'R',
1435873728=>'L',
1435973729=>'L',
1436073730=>'L',
1436173731=>'L',
1436273732=>'L',
1436373733=>'L',
1436473734=>'L',
1436573735=>'L',
1436673736=>'L',
1436773737=>'L',
1436873738=>'L',
1436973739=>'L',
1437073740=>'L',
1437173741=>'L',
1437273742=>'L',
1437373743=>'L',
1437473744=>'L',
1437573745=>'L',
1437673746=>'L',
1437773747=>'L',
1437873748=>'L',
1437973749=>'L',
1438073750=>'L',
1438173751=>'L',
1438273752=>'L',
1438373753=>'L',
1438473754=>'L',
1438573755=>'L',
1438673756=>'L',
1438773757=>'L',
1438873758=>'L',
1438973759=>'L',
1439073760=>'L',
1439173761=>'L',
1439273762=>'L',
1439373763=>'L',
1439473764=>'L',
1439573765=>'L',
1439673766=>'L',
1439773767=>'L',
1439873768=>'L',
1439973769=>'L',
1440073770=>'L',
1440173771=>'L',
1440273772=>'L',
1440373773=>'L',
1440473774=>'L',
1440573775=>'L',
1440673776=>'L',
1440773777=>'L',
1440873778=>'L',
1440973779=>'L',
1441073780=>'L',
1441173781=>'L',
1441273782=>'L',
1441373783=>'L',
1441473784=>'L',
1441573785=>'L',
1441673786=>'L',
1441773787=>'L',
1441873788=>'L',
1441973789=>'L',
1442073790=>'L',
1442173791=>'L',
1442273792=>'L',
1442373793=>'L',
1442473794=>'L',
1442573795=>'L',
1442673796=>'L',
1442773797=>'L',
1442873798=>'L',
1442973799=>'L',
1443073800=>'L',
1443173801=>'L',
1443273802=>'L',
1443373803=>'L',
1443473804=>'L',
1443573805=>'L',
1443673806=>'L',
1443773807=>'L',
1443873808=>'L',
1443973809=>'L',
1444073810=>'L',
1444173811=>'L',
1444273812=>'L',
1444373813=>'L',
1444473814=>'L',
1444573815=>'L',
1444673816=>'L',
1444773817=>'L',
1444873818=>'L',
1444973819=>'L',
1445073820=>'L',
1445173821=>'L',
1445273822=>'L',
1445373823=>'L',
1445473824=>'L',
1445573825=>'L',
1445673826=>'L',
1445773827=>'L',
1445873828=>'L',
1445973829=>'L',
1446073830=>'L',
1446173831=>'L',
1446273832=>'L',
1446373833=>'L',
1446473834=>'L',
1446573835=>'L',
1446673836=>'L',
1446773837=>'L',
1446873838=>'L',
1446973839=>'L',
1447073840=>'L',
1447173841=>'L',
1447273842=>'L',
1447373843=>'L',
1447473844=>'L',
1447573845=>'L',
1447673846=>'L',
1447773847=>'L',
1447873848=>'L',
1447973849=>'L',
1448073850=>'L',
1448173851=>'L',
1448273852=>'L',
1448373853=>'L',
1448473854=>'L',
1448573855=>'L',
1448673856=>'L',
1448773857=>'L',
1448873858=>'L',
1448973859=>'L',
1449073860=>'L',
1449173861=>'L',
1449273862=>'L',
1449373863=>'L',
1449473864=>'L',
1449573865=>'L',
1449673866=>'L',
1449773867=>'L',
1449873868=>'L',
1449973869=>'L',
1450073870=>'L',
1450173871=>'L',
1450273872=>'L',
1450373873=>'L',
1450473874=>'L',
1450573875=>'L',
1450673876=>'L',
1450773877=>'L',
1450873878=>'L',
1450973879=>'L',
1451073880=>'L',
1451173881=>'L',
1451273882=>'L',
1451373883=>'L',
1451473884=>'L',
1451573885=>'L',
1451673886=>'L',
1451773887=>'L',
1451873888=>'L',
1451973889=>'L',
1452073890=>'L',
1452173891=>'L',
1452273892=>'L',
1452373893=>'L',
1452473894=>'L',
1452573895=>'L',
1452673896=>'L',
1452773897=>'L',
1452873898=>'L',
1452973899=>'L',
1453073900=>'L',
1453173901=>'L',
1453273902=>'L',
1453373903=>'L',
1453473904=>'L',
1453573905=>'L',
1453673906=>'L',
1453773907=>'L',
1453873908=>'L',
1453973909=>'L',
1454073910=>'L',
1454173911=>'L',
1454273912=>'L',
1454373913=>'L',
1454473914=>'L',
1454573915=>'L',
1454673916=>'L',
1454773917=>'L',
1454873918=>'L',
1454973919=>'L',
1455073920=>'L',
1455173921=>'L',
1455273922=>'L',
1455373923=>'L',
1455473924=>'L',
1455573925=>'L',
1455673926=>'L',
1455773927=>'L',
1455873928=>'L',
1455973929=>'L',
1456073930=>'L',
1456173931=>'L',
1456273932=>'L',
1456373933=>'L',
1456473934=>'L',
1456573935=>'L',
1456673936=>'L',
1456773937=>'L',
1456873938=>'L',
1456973939=>'L',
1457073940=>'L',
1457173941=>'L',
1457273942=>'L',
1457373943=>'L',
1457473944=>'L',
1457573945=>'L',
1457673946=>'L',
1457773947=>'L',
1457873948=>'L',
1457973949=>'L',
1458073950=>'L',
1458173951=>'L',
1458273952=>'L',
1458373953=>'L',
1458473954=>'L',
1458573955=>'L',
1458673956=>'L',
1458773957=>'L',
1458873958=>'L',
1458973959=>'L',
1459073960=>'L',
1459173961=>'L',
1459273962=>'L',
1459373963=>'L',
1459473964=>'L',
1459573965=>'L',
1459673966=>'L',
1459773967=>'L',
1459873968=>'L',
1459973969=>'L',
1460073970=>'L',
1460173971=>'L',
1460273972=>'L',
1460373973=>'L',
1460473974=>'L',
1460573975=>'L',
1460673976=>'L',
1460773977=>'L',
1460873978=>'L',
1460973979=>'L',
1461073980=>'L',
1461173981=>'L',
1461273982=>'L',
1461373983=>'L',
1461473984=>'L',
1461573985=>'L',
1461673986=>'L',
1461773987=>'L',
1461873988=>'L',
1461973989=>'L',
1462073990=>'L',
1462173991=>'L',
1462273992=>'L',
1462373993=>'L',
1462473994=>'L',
1462573995=>'L',
1462673996=>'L',
1462773997=>'L',
1462873998=>'L',
1462973999=>'L',
1463074000=>'L',
1463174001=>'L',
1463274002=>'L',
1463374003=>'L',
1463474004=>'L',
1463574005=>'L',
1463674006=>'L',
1463774007=>'L',
1463874008=>'L',
1463974009=>'L',
1464074010=>'L',
1464174011=>'L',
1464274012=>'L',
1464374013=>'L',
1464474014=>'L',
1464574015=>'L',
1464674016=>'L',
1464774017=>'L',
1464874018=>'L',
1464974019=>'L',
1465074020=>'L',
1465174021=>'L',
1465274022=>'L',
1465374023=>'L',
1465474024=>'L',
1465574025=>'L',
1465674026=>'L',
1465774027=>'L',
1465874028=>'L',
1465974029=>'L',
1466074030=>'L',
1466174031=>'L',
1466274032=>'L',
1466374033=>'L',
1466474034=>'L',
1466574035=>'L',
1466674036=>'L',
1466774037=>'L',
1466874038=>'L',
1466974039=>'L',
1467074040=>'L',
1467174041=>'L',
1467274042=>'L',
1467374043=>'L',
1467474044=>'L',
1467574045=>'L',
1467674046=>'L',
1467774047=>'L',
1467874048=>'L',
1467974049=>'L',
1468074050=>'L',
1468174051=>'L',
1468274052=>'L',
1468374053=>'L',
1468474054=>'L',
1468574055=>'L',
1468674056=>'L',
1468774057=>'L',
1468874058=>'L',
1468974059=>'L',
1469074060=>'L',
1469174061=>'L',
1469274062=>'L',
1469374063=>'L',
1469474064=>'L',
1469574065=>'L',
1469674066=>'L',
1469774067=>'L',
1469874068=>'L',
1469974069=>'L',
1470074070=>'L',
1470174071=>'L',
1470274072=>'L',
1470374073=>'L',
1470474074=>'L',
1470574075=>'L',
1470674076=>'L',
1470774077=>'L',
1470874078=>'L',
1470974079=>'L',
1471074080=>'L',
1471174081=>'L',
1471274082=>'L',
1471374083=>'L',
1471474084=>'L',
1471574085=>'L',
1471674086=>'L',
1471774087=>'L',
1471874088=>'L',
1471974089=>'L',
1472074090=>'L',
1472174091=>'L',
1472274092=>'L',
1472374093=>'L',
1472474094=>'L',
1472574095=>'L',
1472674096=>'L',
1472774097=>'L',
1472874098=>'L',
1472974099=>'L',
1473074100=>'L',
1473174101=>'L',
1473274102=>'L',
1473374103=>'L',
1473474104=>'L',
1473574105=>'L',
1473674106=>'L',
1473774107=>'L',
1473874108=>'L',
1473974109=>'L',
1474074110=>'L',
1474174111=>'L',
1474274112=>'L',
1474374113=>'L',
1474474114=>'L',
1474574115=>'L',
1474674116=>'L',
1474774117=>'L',
1474874118=>'L',
1474974119=>'L',
1475074120=>'L',
1475174121=>'L',
1475274122=>'L',
1475374123=>'L',
1475474124=>'L',
1475574125=>'L',
1475674126=>'L',
1475774127=>'L',
1475874128=>'L',
1475974129=>'L',
1476074130=>'L',
1476174131=>'L',
1476274132=>'L',
1476374133=>'L',
1476474134=>'L',
1476574135=>'L',
1476674136=>'L',
1476774137=>'L',
1476874138=>'L',
1476974139=>'L',
1477074140=>'L',
1477174141=>'L',
1477274142=>'L',
1477374143=>'L',
1477474144=>'L',
1477574145=>'L',
1477674146=>'L',
1477774147=>'L',
1477874148=>'L',
1477974149=>'L',
1478074150=>'L',
1478174151=>'L',
1478274152=>'L',
1478374153=>'L',
1478474154=>'L',
1478574155=>'L',
1478674156=>'L',
1478774157=>'L',
1478874158=>'L',
1478974159=>'L',
1479074160=>'L',
1479174161=>'L',
1479274162=>'L',
1479374163=>'L',
1479474164=>'L',
1479574165=>'L',
1479674166=>'L',
1479774167=>'L',
1479874168=>'L',
1479974169=>'L',
1480074170=>'L',
1480174171=>'L',
1480274172=>'L',
1480374173=>'L',
1480474174=>'L',
1480574175=>'L',
1480674176=>'L',
1480774177=>'L',
1480874178=>'L',
1480974179=>'L',
1481074180=>'L',
1481174181=>'L',
1481274182=>'L',
1481374183=>'L',
1481474184=>'L',
1481574185=>'L',
1481674186=>'L',
1481774187=>'L',
1481874188=>'L',
1481974189=>'L',
1482074190=>'L',
1482174191=>'L',
1482274192=>'L',
1482374193=>'L',
1482474194=>'L',
1482574195=>'L',
1482674196=>'L',
1482774197=>'L',
1482874198=>'L',
1482974199=>'L',
1483074200=>'L',
1483174201=>'L',
1483274202=>'L',
1483374203=>'L',
1483474204=>'L',
1483574205=>'L',
1483674206=>'L',
1483774207=>'L',
1483874208=>'L',
1483974209=>'L',
1484074210=>'L',
1484174211=>'L',
1484274212=>'L',
1484374213=>'L',
1484474214=>'L',
1484574215=>'L',
1484674216=>'L',
1484774217=>'L',
1484874218=>'L',
1484974219=>'L',
1485074220=>'L',
1485174221=>'L',
1485274222=>'L',
1485374223=>'L',
1485474224=>'L',
1485574225=>'L',
1485674226=>'L',
1485774227=>'L',
1485874228=>'L',
1485974229=>'L',
1486074230=>'L',
1486174231=>'L',
1486274232=>'L',
1486374233=>'L',
1486474234=>'L',
1486574235=>'L',
1486674236=>'L',
1486774237=>'L',
1486874238=>'L',
1486974239=>'L',
1487074240=>'L',
1487174241=>'L',
1487274242=>'L',
1487374243=>'L',
1487474244=>'L',
1487574245=>'L',
1487674246=>'L',
1487774247=>'L',
1487874248=>'L',
1487974249=>'L',
1488074250=>'L',
1488174251=>'L',
1488274252=>'L',
1488374253=>'L',
1488474254=>'L',
1488574255=>'L',
1488674256=>'L',
1488774257=>'L',
1488874258=>'L',
1488974259=>'L',
1489074260=>'L',
1489174261=>'L',
1489274262=>'L',
1489374263=>'L',
1489474264=>'L',
1489574265=>'L',
1489674266=>'L',
1489774267=>'L',
1489874268=>'L',
1489974269=>'L',
1490074270=>'L',
1490174271=>'L',
1490274272=>'L',
1490374273=>'L',
1490474274=>'L',
1490574275=>'L',
1490674276=>'L',
1490774277=>'L',
1490874278=>'L',
1490974279=>'L',
1491074280=>'L',
1491174281=>'L',
1491274282=>'L',
1491374283=>'L',
1491474284=>'L',
1491574285=>'L',
1491674286=>'L',
1491774287=>'L',
1491874288=>'L',
1491974289=>'L',
1492074290=>'L',
1492174291=>'L',
1492274292=>'L',
1492374293=>'L',
1492474294=>'L',
1492574295=>'L',
1492674296=>'L',
1492774297=>'L',
1492874298=>'L',
1492974299=>'L',
1493074300=>'L',
1493174301=>'L',
1493274302=>'L',
1493374303=>'L',
1493474304=>'L',
1493574305=>'L',
1493674306=>'L',
1493774307=>'L',
1493874308=>'L',
1493974309=>'L',
1494074310=>'L',
1494174311=>'L',
1494274312=>'L',
1494374313=>'L',
1494474314=>'L',
1494574315=>'L',
1494674316=>'L',
1494774317=>'L',
1494874318=>'L',
1494974319=>'L',
1495074320=>'L',
1495174321=>'L',
1495274322=>'L',
1495374323=>'L',
1495474324=>'L',
1495574325=>'L',
1495674326=>'L',
1495774327=>'L',
1495874328=>'L',
1495974329=>'L',
1496074330=>'L',
1496174331=>'L',
1496274332=>'L',
1496374333=>'L',
1496474334=>'L',
1496574335=>'L',
1496674336=>'L',
1496774337=>'L',
1496874338=>'L',
1496974339=>'L',
1497074340=>'L',
1497174341=>'L',
1497274342=>'L',
1497374343=>'L',
1497474344=>'L',
1497574345=>'L',
1497674346=>'L',
1497774347=>'L',
1497874348=>'L',
1497974349=>'L',
1498074350=>'L',
1498174351=>'L',
1498274352=>'L',
1498374353=>'L',
1498474354=>'L',
1498574355=>'L',
1498674356=>'L',
1498774357=>'L',
1498874358=>'L',
1498974359=>'L',
1499074360=>'L',
1499174361=>'L',
1499274362=>'L',
1499374363=>'L',
1499474364=>'L',
1499574365=>'L',
1499674366=>'L',
1499774367=>'L',
1499874368=>'L',
1499974369=>'L',
1500074370=>'L',
1500174371=>'L',
1500274372=>'L',
1500374373=>'L',
1500474374=>'L',
1500574375=>'L',
1500674376=>'L',
1500774377=>'L',
1500874378=>'L',
1500974379=>'L',
1501074380=>'L',
1501174381=>'L',
1501274382=>'L',
1501374383=>'L',
1501474384=>'L',
1501574385=>'L',
1501674386=>'L',
1501774387=>'L',
1501874388=>'L',
1501974389=>'L',
1502074390=>'L',
1502174391=>'L',
1502274392=>'L',
1502374393=>'L',
1502474394=>'L',
1502574395=>'L',
1502674396=>'L',
1502774397=>'L',
1502874398=>'L',
1502974399=>'L',
1503074400=>'L',
1503174401=>'L',
1503274402=>'L',
1503374403=>'L',
1503474404=>'L',
1503574405=>'L',
1503674406=>'L',
1503774407=>'L',
1503874408=>'L',
1503974409=>'L',
1504074410=>'L',
1504174411=>'L',
1504274412=>'L',
1504374413=>'L',
1504474414=>'L',
1504574415=>'L',
1504674416=>'L',
1504774417=>'L',
1504874418=>'L',
1504974419=>'L',
1505074420=>'L',
1505174421=>'L',
1505274422=>'L',
1505374423=>'L',
1505474424=>'L',
1505574425=>'L',
1505674426=>'L',
1505774427=>'L',
1505874428=>'L',
1505974429=>'L',
1506074430=>'L',
1506174431=>'L',
1506274432=>'L',
1506374433=>'L',
1506474434=>'L',
1506574435=>'L',
1506674436=>'L',
1506774437=>'L',
1506874438=>'L',
1506974439=>'L',
1507074440=>'L',
1507174441=>'L',
1507274442=>'L',
1507374443=>'L',
1507474444=>'L',
1507574445=>'L',
1507674446=>'L',
1507774447=>'L',
1507874448=>'L',
1507974449=>'L',
1508074450=>'L',
1508174451=>'L',
1508274452=>'L',
1508374453=>'L',
1508474454=>'L',
1508574455=>'L',
1508674456=>'L',
1508774457=>'L',
1508874458=>'L',
1508974459=>'L',
1509074460=>'L',
1509174461=>'L',
1509274462=>'L',
1509374463=>'L',
1509474464=>'L',
1509574465=>'L',
1509674466=>'L',
1509774467=>'L',
1509874468=>'L',
1509974469=>'L',
1510074470=>'L',
1510174471=>'L',
1510274472=>'L',
1510374473=>'L',
1510474474=>'L',
1510574475=>'L',
1510674476=>'L',
1510774477=>'L',
1510874478=>'L',
1510974479=>'L',
1511074480=>'L',
1511174481=>'L',
1511274482=>'L',
1511374483=>'L',
1511474484=>'L',
1511574485=>'L',
1511674486=>'L',
1511774487=>'L',
1511874488=>'L',
1511974489=>'L',
1512074490=>'L',
1512174491=>'L',
1512274492=>'L',
1512374493=>'L',
1512474494=>'L',
1512574495=>'L',
1512674496=>'L',
1512774497=>'L',
1512874498=>'L',
1512974499=>'L',
1513074500=>'L',
1513174501=>'L',
1513274502=>'L',
1513374503=>'L',
1513474504=>'L',
1513574505=>'L',
1513674506=>'L',
1513774507=>'L',
1513874508=>'L',
1513974509=>'L',
1514074510=>'L',
1514174511=>'L',
1514274512=>'L',
1514374513=>'L',
1514474514=>'L',
1514574515=>'L',
1514674516=>'L',
1514774517=>'L',
1514874518=>'L',
1514974519=>'L',
1515074520=>'L',
1515174521=>'L',
1515274522=>'L',
1515374523=>'L',
1515474524=>'L',
1515574525=>'L',
1515674526=>'L',
1515774527=>'L',
1515874528=>'L',
1515974529=>'L',
1516074530=>'L',
1516174531=>'L',
1516274532=>'L',
1516374533=>'L',
1516474534=>'L',
1516574535=>'L',
1516674536=>'L',
1516774537=>'L',
1516874538=>'L',
1516974539=>'L',
1517074540=>'L',
1517174541=>'L',
1517274542=>'L',
1517374543=>'L',
1517474544=>'L',
1517574545=>'L',
1517674546=>'L',
1517774547=>'L',
1517874548=>'L',
1517974549=>'L',
1518074550=>'L',
1518174551=>'L',
1518274552=>'L',
1518374553=>'L',
1518474554=>'L',
1518574555=>'L',
1518674556=>'L',
1518774557=>'L',
1518874558=>'L',
1518974559=>'L',
1519074560=>'L',
1519174561=>'L',
1519274562=>'L',
1519374563=>'L',
1519474564=>'L',
1519574565=>'L',
1519674566=>'L',
1519774567=>'L',
1519874568=>'L',
1519974569=>'L',
1520074570=>'L',
1520174571=>'L',
1520274572=>'L',
1520374573=>'L',
1520474574=>'L',
1520574575=>'L',
1520674576=>'L',
1520774577=>'L',
1520874578=>'L',
1520974579=>'L',
1521074580=>'L',
1521174581=>'L',
1521274582=>'L',
1521374583=>'L',
1521474584=>'L',
1521574585=>'L',
1521674586=>'L',
1521774587=>'L',
1521874588=>'L',
1521974589=>'L',
1522074590=>'L',
1522174591=>'L',
1522274592=>'L',
1522374593=>'L',
1522474594=>'L',
1522574595=>'L',
1522674596=>'L',
1522774597=>'L',
1522874598=>'L',
1522974599=>'L',
1523074600=>'L',
1523174601=>'L',
1523274602=>'L',
1523374603=>'L',
1523474604=>'L',
1523574605=>'L',
1523674606=>'L',
1523774752=>'L',
1523874753=>'L',
1523974754=>'L',
1524074755=>'L',
1524174756=>'L',
1524274757=>'L',
1524374758=>'L',
1524474759=>'L',
1524574760=>'L',
1524674761=>'L',
1524774762=>'L',
1524874763=>'L',
1524974764=>'L',
1525074765=>'L',
1525174766=>'L',
1525274767=>'L',
1525374768=>'L',
1525474769=>'L',
1525574770=>'L',
1525674771=>'L',
1525774772=>'L',
1525874773=>'L',
1525974774=>'L',
1526074775=>'L',
1526174776=>'L',
1526274777=>'L',
1526374778=>'L',
1526474779=>'L',
1526574780=>'L',
1526674781=>'L',
1526774782=>'L',
1526874783=>'L',
1526974784=>'L',
1527074785=>'L',
1527174786=>'L',
1527274787=>'L',
1527374788=>'L',
1527474789=>'L',
1527574790=>'L',
1527674791=>'L',
1527774792=>'L',
1527874793=>'L',
1527974794=>'L',
1528074795=>'L',
1528174796=>'L',
1528274797=>'L',
1528374798=>'L',
1528474799=>'L',
1528574800=>'L',
1528674801=>'L',
1528774802=>'L',
1528874803=>'L',
1528974804=>'L',
1529074805=>'L',
1529174806=>'L',
1529274807=>'L',
1529374808=>'L',
1529474809=>'L',
1529574810=>'L',
1529674811=>'L',
1529774812=>'L',
1529874813=>'L',
1529974814=>'L',
1530074815=>'L',
1530174816=>'L',
1530274817=>'L',
1530374818=>'L',
1530474819=>'L',
1530574820=>'L',
1530674821=>'L',
1530774822=>'L',
1530874823=>'L',
1530974824=>'L',
1531074825=>'L',
1531174826=>'L',
1531274827=>'L',
1531374828=>'L',
1531474829=>'L',
1531574830=>'L',
1531674831=>'L',
1531774832=>'L',
1531874833=>'L',
1531974834=>'L',
1532074835=>'L',
1532174836=>'L',
1532274837=>'L',
1532374838=>'L',
1532474839=>'L',
1532574840=>'L',
1532674841=>'L',
1532774842=>'L',
1532874843=>'L',
1532974844=>'L',
1533074845=>'L',
1533174846=>'L',
1533274847=>'L',
1533374848=>'L',
1533474849=>'L',
1533574850=>'L',
1533674864=>'L',
1533774865=>'L',
1533874866=>'L',
1533974867=>'L',
15340118784=>'L',
15341118785=>'L',
15342118786=>'L',
15343118787=>'L',
15344118788=>'L',
15345118789=>'L',
15346118790=>'L',
15347118791=>'L',
15348118792=>'L',
15349118793=>'L',
15350118794=>'L',
15351118795=>'L',
15352118796=>'L',
15353118797=>'L',
15354118798=>'L',
15355118799=>'L',
15356118800=>'L',
15357118801=>'L',
15358118802=>'L',
15359118803=>'L',
15360118804=>'L',
15361118805=>'L',
15362118806=>'L',
15363118807=>'L',
15364118808=>'L',
15365118809=>'L',
15366118810=>'L',
15367118811=>'L',
15368118812=>'L',
15369118813=>'L',
15370118814=>'L',
15371118815=>'L',
15372118816=>'L',
15373118817=>'L',
15374118818=>'L',
15375118819=>'L',
15376118820=>'L',
15377118821=>'L',
15378118822=>'L',
15379118823=>'L',
15380118824=>'L',
15381118825=>'L',
15382118826=>'L',
15383118827=>'L',
15384118828=>'L',
15385118829=>'L',
15386118830=>'L',
15387118831=>'L',
15388118832=>'L',
15389118833=>'L',
15390118834=>'L',
15391118835=>'L',
15392118836=>'L',
15393118837=>'L',
15394118838=>'L',
15395118839=>'L',
15396118840=>'L',
15397118841=>'L',
15398118842=>'L',
15399118843=>'L',
15400118844=>'L',
15401118845=>'L',
15402118846=>'L',
15403118847=>'L',
15404118848=>'L',
15405118849=>'L',
15406118850=>'L',
15407118851=>'L',
15408118852=>'L',
15409118853=>'L',
15410118854=>'L',
15411118855=>'L',
15412118856=>'L',
15413118857=>'L',
15414118858=>'L',
15415118859=>'L',
15416118860=>'L',
15417118861=>'L',
15418118862=>'L',
15419118863=>'L',
15420118864=>'L',
15421118865=>'L',
15422118866=>'L',
15423118867=>'L',
15424118868=>'L',
15425118869=>'L',
15426118870=>'L',
15427118871=>'L',
15428118872=>'L',
15429118873=>'L',
15430118874=>'L',
15431118875=>'L',
15432118876=>'L',
15433118877=>'L',
15434118878=>'L',
15435118879=>'L',
15436118880=>'L',
15437118881=>'L',
15438118882=>'L',
15439118883=>'L',
15440118884=>'L',
15441118885=>'L',
15442118886=>'L',
15443118887=>'L',
15444118888=>'L',
15445118889=>'L',
15446118890=>'L',
15447118891=>'L',
15448118892=>'L',
15449118893=>'L',
15450118894=>'L',
15451118895=>'L',
15452118896=>'L',
15453118897=>'L',
15454118898=>'L',
15455118899=>'L',
15456118900=>'L',
15457118901=>'L',
15458118902=>'L',
15459118903=>'L',
15460118904=>'L',
15461118905=>'L',
15462118906=>'L',
15463118907=>'L',
15464118908=>'L',
15465118909=>'L',
15466118910=>'L',
15467118911=>'L',
15468118912=>'L',
15469118913=>'L',
15470118914=>'L',
15471118915=>'L',
15472118916=>'L',
15473118917=>'L',
15474118918=>'L',
15475118919=>'L',
15476118920=>'L',
15477118921=>'L',
15478118922=>'L',
15479118923=>'L',
15480118924=>'L',
15481118925=>'L',
15482118926=>'L',
15483118927=>'L',
15484118928=>'L',
15485118929=>'L',
15486118930=>'L',
15487118931=>'L',
15488118932=>'L',
15489118933=>'L',
15490118934=>'L',
15491118935=>'L',
15492118936=>'L',
15493118937=>'L',
15494118938=>'L',
15495118939=>'L',
15496118940=>'L',
15497118941=>'L',
15498118942=>'L',
15499118943=>'L',
15500118944=>'L',
15501118945=>'L',
15502118946=>'L',
15503118947=>'L',
15504118948=>'L',
15505118949=>'L',
15506118950=>'L',
15507118951=>'L',
15508118952=>'L',
15509118953=>'L',
15510118954=>'L',
15511118955=>'L',
15512118956=>'L',
15513118957=>'L',
15514118958=>'L',
15515118959=>'L',
15516118960=>'L',
15517118961=>'L',
15518118962=>'L',
15519118963=>'L',
15520118964=>'L',
15521118965=>'L',
15522118966=>'L',
15523118967=>'L',
15524118968=>'L',
15525118969=>'L',
15526118970=>'L',
15527118971=>'L',
15528118972=>'L',
15529118973=>'L',
15530118974=>'L',
15531118975=>'L',
15532118976=>'L',
15533118977=>'L',
15534118978=>'L',
15535118979=>'L',
15536118980=>'L',
15537118981=>'L',
15538118982=>'L',
15539118983=>'L',
15540118984=>'L',
15541118985=>'L',
15542118986=>'L',
15543118987=>'L',
15544118988=>'L',
15545118989=>'L',
15546118990=>'L',
15547118991=>'L',
15548118992=>'L',
15549118993=>'L',
15550118994=>'L',
15551118995=>'L',
15552118996=>'L',
15553118997=>'L',
15554118998=>'L',
15555118999=>'L',
15556119000=>'L',
15557119001=>'L',
15558119002=>'L',
15559119003=>'L',
15560119004=>'L',
15561119005=>'L',
15562119006=>'L',
15563119007=>'L',
15564119008=>'L',
15565119009=>'L',
15566119010=>'L',
15567119011=>'L',
15568119012=>'L',
15569119013=>'L',
15570119014=>'L',
15571119015=>'L',
15572119016=>'L',
15573119017=>'L',
15574119018=>'L',
15575119019=>'L',
15576119020=>'L',
15577119021=>'L',
15578119022=>'L',
15579119023=>'L',
15580119024=>'L',
15581119025=>'L',
15582119026=>'L',
15583119027=>'L',
15584119028=>'L',
15585119029=>'L',
15586119040=>'L',
15587119041=>'L',
15588119042=>'L',
15589119043=>'L',
15590119044=>'L',
15591119045=>'L',
15592119046=>'L',
15593119047=>'L',
15594119048=>'L',
15595119049=>'L',
15596119050=>'L',
15597119051=>'L',
15598119052=>'L',
15599119053=>'L',
15600119054=>'L',
15601119055=>'L',
15602119056=>'L',
15603119057=>'L',
15604119058=>'L',
15605119059=>'L',
15606119060=>'L',
15607119061=>'L',
15608119062=>'L',
15609119063=>'L',
15610119064=>'L',
15611119065=>'L',
15612119066=>'L',
15613119067=>'L',
15614119068=>'L',
15615119069=>'L',
15616119070=>'L',
15617119071=>'L',
15618119072=>'L',
15619119073=>'L',
15620119074=>'L',
15621119075=>'L',
15622119076=>'L',
15623119077=>'L',
15624119078=>'L',
15625119082=>'L',
15626119083=>'L',
15627119084=>'L',
15628119085=>'L',
15629119086=>'L',
15630119087=>'L',
15631119088=>'L',
15632119089=>'L',
15633119090=>'L',
15634119091=>'L',
15635119092=>'L',
15636119093=>'L',
15637119094=>'L',
15638119095=>'L',
15639119096=>'L',
15640119097=>'L',
15641119098=>'L',
15642119099=>'L',
15643119100=>'L',
15644119101=>'L',
15645119102=>'L',
15646119103=>'L',
15647119104=>'L',
15648119105=>'L',
15649119106=>'L',
15650119107=>'L',
15651119108=>'L',
15652119109=>'L',
15653119110=>'L',
15654119111=>'L',
15655119112=>'L',
15656119113=>'L',
15657119114=>'L',
15658119115=>'L',
15659119116=>'L',
15660119117=>'L',
15661119118=>'L',
15662119119=>'L',
15663119120=>'L',
15664119121=>'L',
15665119122=>'L',
15666119123=>'L',
15667119124=>'L',
15668119125=>'L',
15669119126=>'L',
15670119127=>'L',
15671119128=>'L',
15672119129=>'L',
15673119130=>'L',
15674119131=>'L',
15675119132=>'L',
15676119133=>'L',
15677119134=>'L',
15678119135=>'L',
15679119136=>'L',
15680119137=>'L',
15681119138=>'L',
15682119139=>'L',
15683119140=>'L',
15684119141=>'L',
15685119142=>'L',
15686119143=>'NSM',
15687119144=>'NSM',
15688119145=>'NSM',
15689119146=>'L',
15690119147=>'L',
15691119148=>'L',
15692119149=>'L',
15693119150=>'L',
15694119151=>'L',
15695119152=>'L',
15696119153=>'L',
15697119154=>'L',
15698119155=>'BN',
15699119156=>'BN',
15700119157=>'BN',
15701119158=>'BN',
15702119159=>'BN',
15703119160=>'BN',
15704119161=>'BN',
15705119162=>'BN',
15706119163=>'NSM',
15707119164=>'NSM',
15708119165=>'NSM',
15709119166=>'NSM',
15710119167=>'NSM',
15711119168=>'NSM',
15712119169=>'NSM',
15713119170=>'NSM',
15714119171=>'L',
15715119172=>'L',
15716119173=>'NSM',
15717119174=>'NSM',
15718119175=>'NSM',
15719119176=>'NSM',
15720119177=>'NSM',
15721119178=>'NSM',
15722119179=>'NSM',
15723119180=>'L',
15724119181=>'L',
15725119182=>'L',
15726119183=>'L',
15727119184=>'L',
15728119185=>'L',
15729119186=>'L',
15730119187=>'L',
15731119188=>'L',
15732119189=>'L',
15733119190=>'L',
15734119191=>'L',
15735119192=>'L',
15736119193=>'L',
15737119194=>'L',
15738119195=>'L',
15739119196=>'L',
15740119197=>'L',
15741119198=>'L',
15742119199=>'L',
15743119200=>'L',
15744119201=>'L',
15745119202=>'L',
15746119203=>'L',
15747119204=>'L',
15748119205=>'L',
15749119206=>'L',
15750119207=>'L',
15751119208=>'L',
15752119209=>'L',
15753119210=>'NSM',
15754119211=>'NSM',
15755119212=>'NSM',
15756119213=>'NSM',
15757119214=>'L',
15758119215=>'L',
15759119216=>'L',
15760119217=>'L',
15761119218=>'L',
15762119219=>'L',
15763119220=>'L',
15764119221=>'L',
15765119222=>'L',
15766119223=>'L',
15767119224=>'L',
15768119225=>'L',
15769119226=>'L',
15770119227=>'L',
15771119228=>'L',
15772119229=>'L',
15773119230=>'L',
15774119231=>'L',
15775119232=>'L',
15776119233=>'L',
15777119234=>'L',
15778119235=>'L',
15779119236=>'L',
15780119237=>'L',
15781119238=>'L',
15782119239=>'L',
15783119240=>'L',
15784119241=>'L',
15785119242=>'L',
15786119243=>'L',
15787119244=>'L',
15788119245=>'L',
15789119246=>'L',
15790119247=>'L',
15791119248=>'L',
15792119249=>'L',
15793119250=>'L',
15794119251=>'L',
15795119252=>'L',
15796119253=>'L',
15797119254=>'L',
15798119255=>'L',
15799119256=>'L',
15800119257=>'L',
15801119258=>'L',
15802119259=>'L',
15803119260=>'L',
15804119261=>'L',
15805119296=>'ON',
15806119297=>'ON',
15807119298=>'ON',
15808119299=>'ON',
15809119300=>'ON',
15810119301=>'ON',
15811119302=>'ON',
15812119303=>'ON',
15813119304=>'ON',
15814119305=>'ON',
15815119306=>'ON',
15816119307=>'ON',
15817119308=>'ON',
15818119309=>'ON',
15819119310=>'ON',
15820119311=>'ON',
15821119312=>'ON',
15822119313=>'ON',
15823119314=>'ON',
15824119315=>'ON',
15825119316=>'ON',
15826119317=>'ON',
15827119318=>'ON',
15828119319=>'ON',
15829119320=>'ON',
15830119321=>'ON',
15831119322=>'ON',
15832119323=>'ON',
15833119324=>'ON',
15834119325=>'ON',
15835119326=>'ON',
15836119327=>'ON',
15837119328=>'ON',
15838119329=>'ON',
15839119330=>'ON',
15840119331=>'ON',
15841119332=>'ON',
15842119333=>'ON',
15843119334=>'ON',
15844119335=>'ON',
15845119336=>'ON',
15846119337=>'ON',
15847119338=>'ON',
15848119339=>'ON',
15849119340=>'ON',
15850119341=>'ON',
15851119342=>'ON',
15852119343=>'ON',
15853119344=>'ON',
15854119345=>'ON',
15855119346=>'ON',
15856119347=>'ON',
15857119348=>'ON',
15858119349=>'ON',
15859119350=>'ON',
15860119351=>'ON',
15861119352=>'ON',
15862119353=>'ON',
15863119354=>'ON',
15864119355=>'ON',
15865119356=>'ON',
15866119357=>'ON',
15867119358=>'ON',
15868119359=>'ON',
15869119360=>'ON',
15870119361=>'ON',
15871119362=>'NSM',
15872119363=>'NSM',
15873119364=>'NSM',
15874119365=>'ON',
15875119552=>'ON',
15876119553=>'ON',
15877119554=>'ON',
15878119555=>'ON',
15879119556=>'ON',
15880119557=>'ON',
15881119558=>'ON',
15882119559=>'ON',
15883119560=>'ON',
15884119561=>'ON',
15885119562=>'ON',
15886119563=>'ON',
15887119564=>'ON',
15888119565=>'ON',
15889119566=>'ON',
15890119567=>'ON',
15891119568=>'ON',
15892119569=>'ON',
15893119570=>'ON',
15894119571=>'ON',
15895119572=>'ON',
15896119573=>'ON',
15897119574=>'ON',
15898119575=>'ON',
15899119576=>'ON',
15900119577=>'ON',
15901119578=>'ON',
15902119579=>'ON',
15903119580=>'ON',
15904119581=>'ON',
15905119582=>'ON',
15906119583=>'ON',
15907119584=>'ON',
15908119585=>'ON',
15909119586=>'ON',
15910119587=>'ON',
15911119588=>'ON',
15912119589=>'ON',
15913119590=>'ON',
15914119591=>'ON',
15915119592=>'ON',
15916119593=>'ON',
15917119594=>'ON',
15918119595=>'ON',
15919119596=>'ON',
15920119597=>'ON',
15921119598=>'ON',
15922119599=>'ON',
15923119600=>'ON',
15924119601=>'ON',
15925119602=>'ON',
15926119603=>'ON',
15927119604=>'ON',
15928119605=>'ON',
15929119606=>'ON',
15930119607=>'ON',
15931119608=>'ON',
15932119609=>'ON',
15933119610=>'ON',
15934119611=>'ON',
15935119612=>'ON',
15936119613=>'ON',
15937119614=>'ON',
15938119615=>'ON',
15939119616=>'ON',
15940119617=>'ON',
15941119618=>'ON',
15942119619=>'ON',
15943119620=>'ON',
15944119621=>'ON',
15945119622=>'ON',
15946119623=>'ON',
15947119624=>'ON',
15948119625=>'ON',
15949119626=>'ON',
15950119627=>'ON',
15951119628=>'ON',
15952119629=>'ON',
15953119630=>'ON',
15954119631=>'ON',
15955119632=>'ON',
15956119633=>'ON',
15957119634=>'ON',
15958119635=>'ON',
15959119636=>'ON',
15960119637=>'ON',
15961119638=>'ON',
15962119648=>'L',
15963119649=>'L',
15964119650=>'L',
15965119651=>'L',
15966119652=>'L',
15967119653=>'L',
15968119654=>'L',
15969119655=>'L',
15970119656=>'L',
15971119657=>'L',
15972119658=>'L',
15973119659=>'L',
15974119660=>'L',
15975119661=>'L',
15976119662=>'L',
15977119663=>'L',
15978119664=>'L',
15979119665=>'L',
15980119808=>'L',
15981119809=>'L',
15982119810=>'L',
15983119811=>'L',
15984119812=>'L',
15985119813=>'L',
15986119814=>'L',
15987119815=>'L',
15988119816=>'L',
15989119817=>'L',
15990119818=>'L',
15991119819=>'L',
15992119820=>'L',
15993119821=>'L',
15994119822=>'L',
15995119823=>'L',
15996119824=>'L',
15997119825=>'L',
15998119826=>'L',
15999119827=>'L',
16000119828=>'L',
16001119829=>'L',
16002119830=>'L',
16003119831=>'L',
16004119832=>'L',
16005119833=>'L',
16006119834=>'L',
16007119835=>'L',
16008119836=>'L',
16009119837=>'L',
16010119838=>'L',
16011119839=>'L',
16012119840=>'L',
16013119841=>'L',
16014119842=>'L',
16015119843=>'L',
16016119844=>'L',
16017119845=>'L',
16018119846=>'L',
16019119847=>'L',
16020119848=>'L',
16021119849=>'L',
16022119850=>'L',
16023119851=>'L',
16024119852=>'L',
16025119853=>'L',
16026119854=>'L',
16027119855=>'L',
16028119856=>'L',
16029119857=>'L',
16030119858=>'L',
16031119859=>'L',
16032119860=>'L',
16033119861=>'L',
16034119862=>'L',
16035119863=>'L',
16036119864=>'L',
16037119865=>'L',
16038119866=>'L',
16039119867=>'L',
16040119868=>'L',
16041119869=>'L',
16042119870=>'L',
16043119871=>'L',
16044119872=>'L',
16045119873=>'L',
16046119874=>'L',
16047119875=>'L',
16048119876=>'L',
16049119877=>'L',
16050119878=>'L',
16051119879=>'L',
16052119880=>'L',
16053119881=>'L',
16054119882=>'L',
16055119883=>'L',
16056119884=>'L',
16057119885=>'L',
16058119886=>'L',
16059119887=>'L',
16060119888=>'L',
16061119889=>'L',
16062119890=>'L',
16063119891=>'L',
16064119892=>'L',
16065119894=>'L',
16066119895=>'L',
16067119896=>'L',
16068119897=>'L',
16069119898=>'L',
16070119899=>'L',
16071119900=>'L',
16072119901=>'L',
16073119902=>'L',
16074119903=>'L',
16075119904=>'L',
16076119905=>'L',
16077119906=>'L',
16078119907=>'L',
16079119908=>'L',
16080119909=>'L',
16081119910=>'L',
16082119911=>'L',
16083119912=>'L',
16084119913=>'L',
16085119914=>'L',
16086119915=>'L',
16087119916=>'L',
16088119917=>'L',
16089119918=>'L',
16090119919=>'L',
16091119920=>'L',
16092119921=>'L',
16093119922=>'L',
16094119923=>'L',
16095119924=>'L',
16096119925=>'L',
16097119926=>'L',
16098119927=>'L',
16099119928=>'L',
16100119929=>'L',
16101119930=>'L',
16102119931=>'L',
16103119932=>'L',
16104119933=>'L',
16105119934=>'L',
16106119935=>'L',
16107119936=>'L',
16108119937=>'L',
16109119938=>'L',
16110119939=>'L',
16111119940=>'L',
16112119941=>'L',
16113119942=>'L',
16114119943=>'L',
16115119944=>'L',
16116119945=>'L',
16117119946=>'L',
16118119947=>'L',
16119119948=>'L',
16120119949=>'L',
16121119950=>'L',
16122119951=>'L',
16123119952=>'L',
16124119953=>'L',
16125119954=>'L',
16126119955=>'L',
16127119956=>'L',
16128119957=>'L',
16129119958=>'L',
16130119959=>'L',
16131119960=>'L',
16132119961=>'L',
16133119962=>'L',
16134119963=>'L',
16135119964=>'L',
16136119966=>'L',
16137119967=>'L',
16138119970=>'L',
16139119973=>'L',
16140119974=>'L',
16141119977=>'L',
16142119978=>'L',
16143119979=>'L',
16144119980=>'L',
16145119982=>'L',
16146119983=>'L',
16147119984=>'L',
16148119985=>'L',
16149119986=>'L',
16150119987=>'L',
16151119988=>'L',
16152119989=>'L',
16153119990=>'L',
16154119991=>'L',
16155119992=>'L',
16156119993=>'L',
16157119995=>'L',
16158119997=>'L',
16159119998=>'L',
16160119999=>'L',
16161120000=>'L',
16162120001=>'L',
16163120002=>'L',
16164120003=>'L',
16165120005=>'L',
16166120006=>'L',
16167120007=>'L',
16168120008=>'L',
16169120009=>'L',
16170120010=>'L',
16171120011=>'L',
16172120012=>'L',
16173120013=>'L',
16174120014=>'L',
16175120015=>'L',
16176120016=>'L',
16177120017=>'L',
16178120018=>'L',
16179120019=>'L',
16180120020=>'L',
16181120021=>'L',
16182120022=>'L',
16183120023=>'L',
16184120024=>'L',
16185120025=>'L',
16186120026=>'L',
16187120027=>'L',
16188120028=>'L',
16189120029=>'L',
16190120030=>'L',
16191120031=>'L',
16192120032=>'L',
16193120033=>'L',
16194120034=>'L',
16195120035=>'L',
16196120036=>'L',
16197120037=>'L',
16198120038=>'L',
16199120039=>'L',
16200120040=>'L',
16201120041=>'L',
16202120042=>'L',
16203120043=>'L',
16204120044=>'L',
16205120045=>'L',
16206120046=>'L',
16207120047=>'L',
16208120048=>'L',
16209120049=>'L',
16210120050=>'L',
16211120051=>'L',
16212120052=>'L',
16213120053=>'L',
16214120054=>'L',
16215120055=>'L',
16216120056=>'L',
16217120057=>'L',
16218120058=>'L',
16219120059=>'L',
16220120060=>'L',
16221120061=>'L',
16222120062=>'L',
16223120063=>'L',
16224120064=>'L',
16225120065=>'L',
16226120066=>'L',
16227120067=>'L',
16228120068=>'L',
16229120069=>'L',
16230120071=>'L',
16231120072=>'L',
16232120073=>'L',
16233120074=>'L',
16234120077=>'L',
16235120078=>'L',
16236120079=>'L',
16237120080=>'L',
16238120081=>'L',
16239120082=>'L',
16240120083=>'L',
16241120084=>'L',
16242120086=>'L',
16243120087=>'L',
16244120088=>'L',
16245120089=>'L',
16246120090=>'L',
16247120091=>'L',
16248120092=>'L',
16249120094=>'L',
16250120095=>'L',
16251120096=>'L',
16252120097=>'L',
16253120098=>'L',
16254120099=>'L',
16255120100=>'L',
16256120101=>'L',
16257120102=>'L',
16258120103=>'L',
16259120104=>'L',
16260120105=>'L',
16261120106=>'L',
16262120107=>'L',
16263120108=>'L',
16264120109=>'L',
16265120110=>'L',
16266120111=>'L',
16267120112=>'L',
16268120113=>'L',
16269120114=>'L',
16270120115=>'L',
16271120116=>'L',
16272120117=>'L',
16273120118=>'L',
16274120119=>'L',
16275120120=>'L',
16276120121=>'L',
16277120123=>'L',
16278120124=>'L',
16279120125=>'L',
16280120126=>'L',
16281120128=>'L',
16282120129=>'L',
16283120130=>'L',
16284120131=>'L',
16285120132=>'L',
16286120134=>'L',
16287120138=>'L',
16288120139=>'L',
16289120140=>'L',
16290120141=>'L',
16291120142=>'L',
16292120143=>'L',
16293120144=>'L',
16294120146=>'L',
16295120147=>'L',
16296120148=>'L',
16297120149=>'L',
16298120150=>'L',
16299120151=>'L',
16300120152=>'L',
16301120153=>'L',
16302120154=>'L',
16303120155=>'L',
16304120156=>'L',
16305120157=>'L',
16306120158=>'L',
16307120159=>'L',
16308120160=>'L',
16309120161=>'L',
16310120162=>'L',
16311120163=>'L',
16312120164=>'L',
16313120165=>'L',
16314120166=>'L',
16315120167=>'L',
16316120168=>'L',
16317120169=>'L',
16318120170=>'L',
16319120171=>'L',
16320120172=>'L',
16321120173=>'L',
16322120174=>'L',
16323120175=>'L',
16324120176=>'L',
16325120177=>'L',
16326120178=>'L',
16327120179=>'L',
16328120180=>'L',
16329120181=>'L',
16330120182=>'L',
16331120183=>'L',
16332120184=>'L',
16333120185=>'L',
16334120186=>'L',
16335120187=>'L',
16336120188=>'L',
16337120189=>'L',
16338120190=>'L',
16339120191=>'L',
16340120192=>'L',
16341120193=>'L',
16342120194=>'L',
16343120195=>'L',
16344120196=>'L',
16345120197=>'L',
16346120198=>'L',
16347120199=>'L',
16348120200=>'L',
16349120201=>'L',
16350120202=>'L',
16351120203=>'L',
16352120204=>'L',
16353120205=>'L',
16354120206=>'L',
16355120207=>'L',
16356120208=>'L',
16357120209=>'L',
16358120210=>'L',
16359120211=>'L',
16360120212=>'L',
16361120213=>'L',
16362120214=>'L',
16363120215=>'L',
16364120216=>'L',
16365120217=>'L',
16366120218=>'L',
16367120219=>'L',
16368120220=>'L',
16369120221=>'L',
16370120222=>'L',
16371120223=>'L',
16372120224=>'L',
16373120225=>'L',
16374120226=>'L',
16375120227=>'L',
16376120228=>'L',
16377120229=>'L',
16378120230=>'L',
16379120231=>'L',
16380120232=>'L',
16381120233=>'L',
16382120234=>'L',
16383120235=>'L',
16384120236=>'L',
16385120237=>'L',
16386120238=>'L',
16387120239=>'L',
16388120240=>'L',
16389120241=>'L',
16390120242=>'L',
16391120243=>'L',
16392120244=>'L',
16393120245=>'L',
16394120246=>'L',
16395120247=>'L',
16396120248=>'L',
16397120249=>'L',
16398120250=>'L',
16399120251=>'L',
16400120252=>'L',
16401120253=>'L',
16402120254=>'L',
16403120255=>'L',
16404120256=>'L',
16405120257=>'L',
16406120258=>'L',
16407120259=>'L',
16408120260=>'L',
16409120261=>'L',
16410120262=>'L',
16411120263=>'L',
16412120264=>'L',
16413120265=>'L',
16414120266=>'L',
16415120267=>'L',
16416120268=>'L',
16417120269=>'L',
16418120270=>'L',
16419120271=>'L',
16420120272=>'L',
16421120273=>'L',
16422120274=>'L',
16423120275=>'L',
16424120276=>'L',
16425120277=>'L',
16426120278=>'L',
16427120279=>'L',
16428120280=>'L',
16429120281=>'L',
16430120282=>'L',
16431120283=>'L',
16432120284=>'L',
16433120285=>'L',
16434120286=>'L',
16435120287=>'L',
16436120288=>'L',
16437120289=>'L',
16438120290=>'L',
16439120291=>'L',
16440120292=>'L',
16441120293=>'L',
16442120294=>'L',
16443120295=>'L',
16444120296=>'L',
16445120297=>'L',
16446120298=>'L',
16447120299=>'L',
16448120300=>'L',
16449120301=>'L',
16450120302=>'L',
16451120303=>'L',
16452120304=>'L',
16453120305=>'L',
16454120306=>'L',
16455120307=>'L',
16456120308=>'L',
16457120309=>'L',
16458120310=>'L',
16459120311=>'L',
16460120312=>'L',
16461120313=>'L',
16462120314=>'L',
16463120315=>'L',
16464120316=>'L',
16465120317=>'L',
16466120318=>'L',
16467120319=>'L',
16468120320=>'L',
16469120321=>'L',
16470120322=>'L',
16471120323=>'L',
16472120324=>'L',
16473120325=>'L',
16474120326=>'L',
16475120327=>'L',
16476120328=>'L',
16477120329=>'L',
16478120330=>'L',
16479120331=>'L',
16480120332=>'L',
16481120333=>'L',
16482120334=>'L',
16483120335=>'L',
16484120336=>'L',
16485120337=>'L',
16486120338=>'L',
16487120339=>'L',
16488120340=>'L',
16489120341=>'L',
16490120342=>'L',
16491120343=>'L',
16492120344=>'L',
16493120345=>'L',
16494120346=>'L',
16495120347=>'L',
16496120348=>'L',
16497120349=>'L',
16498120350=>'L',
16499120351=>'L',
16500120352=>'L',
16501120353=>'L',
16502120354=>'L',
16503120355=>'L',
16504120356=>'L',
16505120357=>'L',
16506120358=>'L',
16507120359=>'L',
16508120360=>'L',
16509120361=>'L',
16510120362=>'L',
16511120363=>'L',
16512120364=>'L',
16513120365=>'L',
16514120366=>'L',
16515120367=>'L',
16516120368=>'L',
16517120369=>'L',
16518120370=>'L',
16519120371=>'L',
16520120372=>'L',
16521120373=>'L',
16522120374=>'L',
16523120375=>'L',
16524120376=>'L',
16525120377=>'L',
16526120378=>'L',
16527120379=>'L',
16528120380=>'L',
16529120381=>'L',
16530120382=>'L',
16531120383=>'L',
16532120384=>'L',
16533120385=>'L',
16534120386=>'L',
16535120387=>'L',
16536120388=>'L',
16537120389=>'L',
16538120390=>'L',
16539120391=>'L',
16540120392=>'L',
16541120393=>'L',
16542120394=>'L',
16543120395=>'L',
16544120396=>'L',
16545120397=>'L',
16546120398=>'L',
16547120399=>'L',
16548120400=>'L',
16549120401=>'L',
16550120402=>'L',
16551120403=>'L',
16552120404=>'L',
16553120405=>'L',
16554120406=>'L',
16555120407=>'L',
16556120408=>'L',
16557120409=>'L',
16558120410=>'L',
16559120411=>'L',
16560120412=>'L',
16561120413=>'L',
16562120414=>'L',
16563120415=>'L',
16564120416=>'L',
16565120417=>'L',
16566120418=>'L',
16567120419=>'L',
16568120420=>'L',
16569120421=>'L',
16570120422=>'L',
16571120423=>'L',
16572120424=>'L',
16573120425=>'L',
16574120426=>'L',
16575120427=>'L',
16576120428=>'L',
16577120429=>'L',
16578120430=>'L',
16579120431=>'L',
16580120432=>'L',
16581120433=>'L',
16582120434=>'L',
16583120435=>'L',
16584120436=>'L',
16585120437=>'L',
16586120438=>'L',
16587120439=>'L',
16588120440=>'L',
16589120441=>'L',
16590120442=>'L',
16591120443=>'L',
16592120444=>'L',
16593120445=>'L',
16594120446=>'L',
16595120447=>'L',
16596120448=>'L',
16597120449=>'L',
16598120450=>'L',
16599120451=>'L',
16600120452=>'L',
16601120453=>'L',
16602120454=>'L',
16603120455=>'L',
16604120456=>'L',
16605120457=>'L',
16606120458=>'L',
16607120459=>'L',
16608120460=>'L',
16609120461=>'L',
16610120462=>'L',
16611120463=>'L',
16612120464=>'L',
16613120465=>'L',
16614120466=>'L',
16615120467=>'L',
16616120468=>'L',
16617120469=>'L',
16618120470=>'L',
16619120471=>'L',
16620120472=>'L',
16621120473=>'L',
16622120474=>'L',
16623120475=>'L',
16624120476=>'L',
16625120477=>'L',
16626120478=>'L',
16627120479=>'L',
16628120480=>'L',
16629120481=>'L',
16630120482=>'L',
16631120483=>'L',
16632120484=>'L',
16633120485=>'L',
16634120488=>'L',
16635120489=>'L',
16636120490=>'L',
16637120491=>'L',
16638120492=>'L',
16639120493=>'L',
16640120494=>'L',
16641120495=>'L',
16642120496=>'L',
16643120497=>'L',
16644120498=>'L',
16645120499=>'L',
16646120500=>'L',
16647120501=>'L',
16648120502=>'L',
16649120503=>'L',
16650120504=>'L',
16651120505=>'L',
16652120506=>'L',
16653120507=>'L',
16654120508=>'L',
16655120509=>'L',
16656120510=>'L',
16657120511=>'L',
16658120512=>'L',
16659120513=>'L',
16660120514=>'L',
16661120515=>'L',
16662120516=>'L',
16663120517=>'L',
16664120518=>'L',
16665120519=>'L',
16666120520=>'L',
16667120521=>'L',
16668120522=>'L',
16669120523=>'L',
16670120524=>'L',
16671120525=>'L',
16672120526=>'L',
16673120527=>'L',
16674120528=>'L',
16675120529=>'L',
16676120530=>'L',
16677120531=>'L',
16678120532=>'L',
16679120533=>'L',
16680120534=>'L',
16681120535=>'L',
16682120536=>'L',
16683120537=>'L',
16684120538=>'L',
16685120539=>'L',
16686120540=>'L',
16687120541=>'L',
16688120542=>'L',
16689120543=>'L',
16690120544=>'L',
16691120545=>'L',
16692120546=>'L',
16693120547=>'L',
16694120548=>'L',
16695120549=>'L',
16696120550=>'L',
16697120551=>'L',
16698120552=>'L',
16699120553=>'L',
16700120554=>'L',
16701120555=>'L',
16702120556=>'L',
16703120557=>'L',
16704120558=>'L',
16705120559=>'L',
16706120560=>'L',
16707120561=>'L',
16708120562=>'L',
16709120563=>'L',
16710120564=>'L',
16711120565=>'L',
16712120566=>'L',
16713120567=>'L',
16714120568=>'L',
16715120569=>'L',
16716120570=>'L',
16717120571=>'L',
16718120572=>'L',
16719120573=>'L',
16720120574=>'L',
16721120575=>'L',
16722120576=>'L',
16723120577=>'L',
16724120578=>'L',
16725120579=>'L',
16726120580=>'L',
16727120581=>'L',
16728120582=>'L',
16729120583=>'L',
16730120584=>'L',
16731120585=>'L',
16732120586=>'L',
16733120587=>'L',
16734120588=>'L',
16735120589=>'L',
16736120590=>'L',
16737120591=>'L',
16738120592=>'L',
16739120593=>'L',
16740120594=>'L',
16741120595=>'L',
16742120596=>'L',
16743120597=>'L',
16744120598=>'L',
16745120599=>'L',
16746120600=>'L',
16747120601=>'L',
16748120602=>'L',
16749120603=>'L',
16750120604=>'L',
16751120605=>'L',
16752120606=>'L',
16753120607=>'L',
16754120608=>'L',
16755120609=>'L',
16756120610=>'L',
16757120611=>'L',
16758120612=>'L',
16759120613=>'L',
16760120614=>'L',
16761120615=>'L',
16762120616=>'L',
16763120617=>'L',
16764120618=>'L',
16765120619=>'L',
16766120620=>'L',
16767120621=>'L',
16768120622=>'L',
16769120623=>'L',
16770120624=>'L',
16771120625=>'L',
16772120626=>'L',
16773120627=>'L',
16774120628=>'L',
16775120629=>'L',
16776120630=>'L',
16777120631=>'L',
16778120632=>'L',
16779120633=>'L',
16780120634=>'L',
16781120635=>'L',
16782120636=>'L',
16783120637=>'L',
16784120638=>'L',
16785120639=>'L',
16786120640=>'L',
16787120641=>'L',
16788120642=>'L',
16789120643=>'L',
16790120644=>'L',
16791120645=>'L',
16792120646=>'L',
16793120647=>'L',
16794120648=>'L',
16795120649=>'L',
16796120650=>'L',
16797120651=>'L',
16798120652=>'L',
16799120653=>'L',
16800120654=>'L',
16801120655=>'L',
16802120656=>'L',
16803120657=>'L',
16804120658=>'L',
16805120659=>'L',
16806120660=>'L',
16807120661=>'L',
16808120662=>'L',
16809120663=>'L',
16810120664=>'L',
16811120665=>'L',
16812120666=>'L',
16813120667=>'L',
16814120668=>'L',
16815120669=>'L',
16816120670=>'L',
16817120671=>'L',
16818120672=>'L',
16819120673=>'L',
16820120674=>'L',
16821120675=>'L',
16822120676=>'L',
16823120677=>'L',
16824120678=>'L',
16825120679=>'L',
16826120680=>'L',
16827120681=>'L',
16828120682=>'L',
16829120683=>'L',
16830120684=>'L',
16831120685=>'L',
16832120686=>'L',
16833120687=>'L',
16834120688=>'L',
16835120689=>'L',
16836120690=>'L',
16837120691=>'L',
16838120692=>'L',
16839120693=>'L',
16840120694=>'L',
16841120695=>'L',
16842120696=>'L',
16843120697=>'L',
16844120698=>'L',
16845120699=>'L',
16846120700=>'L',
16847120701=>'L',
16848120702=>'L',
16849120703=>'L',
16850120704=>'L',
16851120705=>'L',
16852120706=>'L',
16853120707=>'L',
16854120708=>'L',
16855120709=>'L',
16856120710=>'L',
16857120711=>'L',
16858120712=>'L',
16859120713=>'L',
16860120714=>'L',
16861120715=>'L',
16862120716=>'L',
16863120717=>'L',
16864120718=>'L',
16865120719=>'L',
16866120720=>'L',
16867120721=>'L',
16868120722=>'L',
16869120723=>'L',
16870120724=>'L',
16871120725=>'L',
16872120726=>'L',
16873120727=>'L',
16874120728=>'L',
16875120729=>'L',
16876120730=>'L',
16877120731=>'L',
16878120732=>'L',
16879120733=>'L',
16880120734=>'L',
16881120735=>'L',
16882120736=>'L',
16883120737=>'L',
16884120738=>'L',
16885120739=>'L',
16886120740=>'L',
16887120741=>'L',
16888120742=>'L',
16889120743=>'L',
16890120744=>'L',
16891120745=>'L',
16892120746=>'L',
16893120747=>'L',
16894120748=>'L',
16895120749=>'L',
16896120750=>'L',
16897120751=>'L',
16898120752=>'L',
16899120753=>'L',
16900120754=>'L',
16901120755=>'L',
16902120756=>'L',
16903120757=>'L',
16904120758=>'L',
16905120759=>'L',
16906120760=>'L',
16907120761=>'L',
16908120762=>'L',
16909120763=>'L',
16910120764=>'L',
16911120765=>'L',
16912120766=>'L',
16913120767=>'L',
16914120768=>'L',
16915120769=>'L',
16916120770=>'L',
16917120771=>'L',
16918120772=>'L',
16919120773=>'L',
16920120774=>'L',
16921120775=>'L',
16922120776=>'L',
16923120777=>'L',
16924120778=>'L',
16925120779=>'L',
16926120782=>'EN',
16927120783=>'EN',
16928120784=>'EN',
16929120785=>'EN',
16930120786=>'EN',
16931120787=>'EN',
16932120788=>'EN',
16933120789=>'EN',
16934120790=>'EN',
16935120791=>'EN',
16936120792=>'EN',
16937120793=>'EN',
16938120794=>'EN',
16939120795=>'EN',
16940120796=>'EN',
16941120797=>'EN',
16942120798=>'EN',
16943120799=>'EN',
16944120800=>'EN',
16945120801=>'EN',
16946120802=>'EN',
16947120803=>'EN',
16948120804=>'EN',
16949120805=>'EN',
16950120806=>'EN',
16951120807=>'EN',
16952120808=>'EN',
16953120809=>'EN',
16954120810=>'EN',
16955120811=>'EN',
16956120812=>'EN',
16957120813=>'EN',
16958120814=>'EN',
16959120815=>'EN',
16960120816=>'EN',
16961120817=>'EN',
16962120818=>'EN',
16963120819=>'EN',
16964120820=>'EN',
16965120821=>'EN',
16966120822=>'EN',
16967120823=>'EN',
16968120824=>'EN',
16969120825=>'EN',
16970120826=>'EN',
16971120827=>'EN',
16972120828=>'EN',
16973120829=>'EN',
16974120830=>'EN',
16975120831=>'EN',
16976131072=>'L',
16977173782=>'L',
16978194560=>'L',
16979194561=>'L',
16980194562=>'L',
16981194563=>'L',
16982194564=>'L',
16983194565=>'L',
16984194566=>'L',
16985194567=>'L',
16986194568=>'L',
16987194569=>'L',
16988194570=>'L',
16989194571=>'L',
16990194572=>'L',
16991194573=>'L',
16992194574=>'L',
16993194575=>'L',
16994194576=>'L',
16995194577=>'L',
16996194578=>'L',
16997194579=>'L',
16998194580=>'L',
16999194581=>'L',
17000194582=>'L',
17001194583=>'L',
17002194584=>'L',
17003194585=>'L',
17004194586=>'L',
17005194587=>'L',
17006194588=>'L',
17007194589=>'L',
17008194590=>'L',
17009194591=>'L',
17010194592=>'L',
17011194593=>'L',
17012194594=>'L',
17013194595=>'L',
17014194596=>'L',
17015194597=>'L',
17016194598=>'L',
17017194599=>'L',
17018194600=>'L',
17019194601=>'L',
17020194602=>'L',
17021194603=>'L',
17022194604=>'L',
17023194605=>'L',
17024194606=>'L',
17025194607=>'L',
17026194608=>'L',
17027194609=>'L',
17028194610=>'L',
17029194611=>'L',
17030194612=>'L',
17031194613=>'L',
17032194614=>'L',
17033194615=>'L',
17034194616=>'L',
17035194617=>'L',
17036194618=>'L',
17037194619=>'L',
17038194620=>'L',
17039194621=>'L',
17040194622=>'L',
17041194623=>'L',
17042194624=>'L',
17043194625=>'L',
17044194626=>'L',
17045194627=>'L',
17046194628=>'L',
17047194629=>'L',
17048194630=>'L',
17049194631=>'L',
17050194632=>'L',
17051194633=>'L',
17052194634=>'L',
17053194635=>'L',
17054194636=>'L',
17055194637=>'L',
17056194638=>'L',
17057194639=>'L',
17058194640=>'L',
17059194641=>'L',
17060194642=>'L',
17061194643=>'L',
17062194644=>'L',
17063194645=>'L',
17064194646=>'L',
17065194647=>'L',
17066194648=>'L',
17067194649=>'L',
17068194650=>'L',
17069194651=>'L',
17070194652=>'L',
17071194653=>'L',
17072194654=>'L',
17073194655=>'L',
17074194656=>'L',
17075194657=>'L',
17076194658=>'L',
17077194659=>'L',
17078194660=>'L',
17079194661=>'L',
17080194662=>'L',
17081194663=>'L',
17082194664=>'L',
17083194665=>'L',
17084194666=>'L',
17085194667=>'L',
17086194668=>'L',
17087194669=>'L',
17088194670=>'L',
17089194671=>'L',
17090194672=>'L',
17091194673=>'L',
17092194674=>'L',
17093194675=>'L',
17094194676=>'L',
17095194677=>'L',
17096194678=>'L',
17097194679=>'L',
17098194680=>'L',
17099194681=>'L',
17100194682=>'L',
17101194683=>'L',
17102194684=>'L',
17103194685=>'L',
17104194686=>'L',
17105194687=>'L',
17106194688=>'L',
17107194689=>'L',
17108194690=>'L',
17109194691=>'L',
17110194692=>'L',
17111194693=>'L',
17112194694=>'L',
17113194695=>'L',
17114194696=>'L',
17115194697=>'L',
17116194698=>'L',
17117194699=>'L',
17118194700=>'L',
17119194701=>'L',
17120194702=>'L',
17121194703=>'L',
17122194704=>'L',
17123194705=>'L',
17124194706=>'L',
17125194707=>'L',
17126194708=>'L',
17127194709=>'L',
17128194710=>'L',
17129194711=>'L',
17130194712=>'L',
17131194713=>'L',
17132194714=>'L',
17133194715=>'L',
17134194716=>'L',
17135194717=>'L',
17136194718=>'L',
17137194719=>'L',
17138194720=>'L',
17139194721=>'L',
17140194722=>'L',
17141194723=>'L',
17142194724=>'L',
17143194725=>'L',
17144194726=>'L',
17145194727=>'L',
17146194728=>'L',
17147194729=>'L',
17148194730=>'L',
17149194731=>'L',
17150194732=>'L',
17151194733=>'L',
17152194734=>'L',
17153194735=>'L',
17154194736=>'L',
17155194737=>'L',
17156194738=>'L',
17157194739=>'L',
17158194740=>'L',
17159194741=>'L',
17160194742=>'L',
17161194743=>'L',
17162194744=>'L',
17163194745=>'L',
17164194746=>'L',
17165194747=>'L',
17166194748=>'L',
17167194749=>'L',
17168194750=>'L',
17169194751=>'L',
17170194752=>'L',
17171194753=>'L',
17172194754=>'L',
17173194755=>'L',
17174194756=>'L',
17175194757=>'L',
17176194758=>'L',
17177194759=>'L',
17178194760=>'L',
17179194761=>'L',
17180194762=>'L',
17181194763=>'L',
17182194764=>'L',
17183194765=>'L',
17184194766=>'L',
17185194767=>'L',
17186194768=>'L',
17187194769=>'L',
17188194770=>'L',
17189194771=>'L',
17190194772=>'L',
17191194773=>'L',
17192194774=>'L',
17193194775=>'L',
17194194776=>'L',
17195194777=>'L',
17196194778=>'L',
17197194779=>'L',
17198194780=>'L',
17199194781=>'L',
17200194782=>'L',
17201194783=>'L',
17202194784=>'L',
17203194785=>'L',
17204194786=>'L',
17205194787=>'L',
17206194788=>'L',
17207194789=>'L',
17208194790=>'L',
17209194791=>'L',
17210194792=>'L',
17211194793=>'L',
17212194794=>'L',
17213194795=>'L',
17214194796=>'L',
17215194797=>'L',
17216194798=>'L',
17217194799=>'L',
17218194800=>'L',
17219194801=>'L',
17220194802=>'L',
17221194803=>'L',
17222194804=>'L',
17223194805=>'L',
17224194806=>'L',
17225194807=>'L',
17226194808=>'L',
17227194809=>'L',
17228194810=>'L',
17229194811=>'L',
17230194812=>'L',
17231194813=>'L',
17232194814=>'L',
17233194815=>'L',
17234194816=>'L',
17235194817=>'L',
17236194818=>'L',
17237194819=>'L',
17238194820=>'L',
17239194821=>'L',
17240194822=>'L',
17241194823=>'L',
17242194824=>'L',
17243194825=>'L',
17244194826=>'L',
17245194827=>'L',
17246194828=>'L',
17247194829=>'L',
17248194830=>'L',
17249194831=>'L',
17250194832=>'L',
17251194833=>'L',
17252194834=>'L',
17253194835=>'L',
17254194836=>'L',
17255194837=>'L',
17256194838=>'L',
17257194839=>'L',
17258194840=>'L',
17259194841=>'L',
17260194842=>'L',
17261194843=>'L',
17262194844=>'L',
17263194845=>'L',
17264194846=>'L',
17265194847=>'L',
17266194848=>'L',
17267194849=>'L',
17268194850=>'L',
17269194851=>'L',
17270194852=>'L',
17271194853=>'L',
17272194854=>'L',
17273194855=>'L',
17274194856=>'L',
17275194857=>'L',
17276194858=>'L',
17277194859=>'L',
17278194860=>'L',
17279194861=>'L',
17280194862=>'L',
17281194863=>'L',
17282194864=>'L',
17283194865=>'L',
17284194866=>'L',
17285194867=>'L',
17286194868=>'L',
17287194869=>'L',
17288194870=>'L',
17289194871=>'L',
17290194872=>'L',
17291194873=>'L',
17292194874=>'L',
17293194875=>'L',
17294194876=>'L',
17295194877=>'L',
17296194878=>'L',
17297194879=>'L',
17298194880=>'L',
17299194881=>'L',
17300194882=>'L',
17301194883=>'L',
17302194884=>'L',
17303194885=>'L',
17304194886=>'L',
17305194887=>'L',
17306194888=>'L',
17307194889=>'L',
17308194890=>'L',
17309194891=>'L',
17310194892=>'L',
17311194893=>'L',
17312194894=>'L',
17313194895=>'L',
17314194896=>'L',
17315194897=>'L',
17316194898=>'L',
17317194899=>'L',
17318194900=>'L',
17319194901=>'L',
17320194902=>'L',
17321194903=>'L',
17322194904=>'L',
17323194905=>'L',
17324194906=>'L',
17325194907=>'L',
17326194908=>'L',
17327194909=>'L',
17328194910=>'L',
17329194911=>'L',
17330194912=>'L',
17331194913=>'L',
17332194914=>'L',
17333194915=>'L',
17334194916=>'L',
17335194917=>'L',
17336194918=>'L',
17337194919=>'L',
17338194920=>'L',
17339194921=>'L',
17340194922=>'L',
17341194923=>'L',
17342194924=>'L',
17343194925=>'L',
17344194926=>'L',
17345194927=>'L',
17346194928=>'L',
17347194929=>'L',
17348194930=>'L',
17349194931=>'L',
17350194932=>'L',
17351194933=>'L',
17352194934=>'L',
17353194935=>'L',
17354194936=>'L',
17355194937=>'L',
17356194938=>'L',
17357194939=>'L',
17358194940=>'L',
17359194941=>'L',
17360194942=>'L',
17361194943=>'L',
17362194944=>'L',
17363194945=>'L',
17364194946=>'L',
17365194947=>'L',
17366194948=>'L',
17367194949=>'L',
17368194950=>'L',
17369194951=>'L',
17370194952=>'L',
17371194953=>'L',
17372194954=>'L',
17373194955=>'L',
17374194956=>'L',
17375194957=>'L',
17376194958=>'L',
17377194959=>'L',
17378194960=>'L',
17379194961=>'L',
17380194962=>'L',
17381194963=>'L',
17382194964=>'L',
17383194965=>'L',
17384194966=>'L',
17385194967=>'L',
17386194968=>'L',
17387194969=>'L',
17388194970=>'L',
17389194971=>'L',
17390194972=>'L',
17391194973=>'L',
17392194974=>'L',
17393194975=>'L',
17394194976=>'L',
17395194977=>'L',
17396194978=>'L',
17397194979=>'L',
17398194980=>'L',
17399194981=>'L',
17400194982=>'L',
17401194983=>'L',
17402194984=>'L',
17403194985=>'L',
17404194986=>'L',
17405194987=>'L',
17406194988=>'L',
17407194989=>'L',
17408194990=>'L',
17409194991=>'L',
17410194992=>'L',
17411194993=>'L',
17412194994=>'L',
17413194995=>'L',
17414194996=>'L',
17415194997=>'L',
17416194998=>'L',
17417194999=>'L',
17418195000=>'L',
17419195001=>'L',
17420195002=>'L',
17421195003=>'L',
17422195004=>'L',
17423195005=>'L',
17424195006=>'L',
17425195007=>'L',
17426195008=>'L',
17427195009=>'L',
17428195010=>'L',
17429195011=>'L',
17430195012=>'L',
17431195013=>'L',
17432195014=>'L',
17433195015=>'L',
17434195016=>'L',
17435195017=>'L',
17436195018=>'L',
17437195019=>'L',
17438195020=>'L',
17439195021=>'L',
17440195022=>'L',
17441195023=>'L',
17442195024=>'L',
17443195025=>'L',
17444195026=>'L',
17445195027=>'L',
17446195028=>'L',
17447195029=>'L',
17448195030=>'L',
17449195031=>'L',
17450195032=>'L',
17451195033=>'L',
17452195034=>'L',
17453195035=>'L',
17454195036=>'L',
17455195037=>'L',
17456195038=>'L',
17457195039=>'L',
17458195040=>'L',
17459195041=>'L',
17460195042=>'L',
17461195043=>'L',
17462195044=>'L',
17463195045=>'L',
17464195046=>'L',
17465195047=>'L',
17466195048=>'L',
17467195049=>'L',
17468195050=>'L',
17469195051=>'L',
17470195052=>'L',
17471195053=>'L',
17472195054=>'L',
17473195055=>'L',
17474195056=>'L',
17475195057=>'L',
17476195058=>'L',
17477195059=>'L',
17478195060=>'L',
17479195061=>'L',
17480195062=>'L',
17481195063=>'L',
17482195064=>'L',
17483195065=>'L',
17484195066=>'L',
17485195067=>'L',
17486195068=>'L',
17487195069=>'L',
17488195070=>'L',
17489195071=>'L',
17490195072=>'L',
17491195073=>'L',
17492195074=>'L',
17493195075=>'L',
17494195076=>'L',
17495195077=>'L',
17496195078=>'L',
17497195079=>'L',
17498195080=>'L',
17499195081=>'L',
17500195082=>'L',
17501195083=>'L',
17502195084=>'L',
17503195085=>'L',
17504195086=>'L',
17505195087=>'L',
17506195088=>'L',
17507195089=>'L',
17508195090=>'L',
17509195091=>'L',
17510195092=>'L',
17511195093=>'L',
17512195094=>'L',
17513195095=>'L',
17514195096=>'L',
17515195097=>'L',
17516195098=>'L',
17517195099=>'L',
17518195100=>'L',
17519195101=>'L',
17520917505=>'BN',
17521917536=>'BN',
17522917537=>'BN',
17523917538=>'BN',
17524917539=>'BN',
17525917540=>'BN',
17526917541=>'BN',
17527917542=>'BN',
17528917543=>'BN',
17529917544=>'BN',
17530917545=>'BN',
17531917546=>'BN',
17532917547=>'BN',
17533917548=>'BN',
17534917549=>'BN',
17535917550=>'BN',
17536917551=>'BN',
17537917552=>'BN',
17538917553=>'BN',
17539917554=>'BN',
17540917555=>'BN',
17541917556=>'BN',
17542917557=>'BN',
17543917558=>'BN',
17544917559=>'BN',
17545917560=>'BN',
17546917561=>'BN',
17547917562=>'BN',
17548917563=>'BN',
17549917564=>'BN',
17550917565=>'BN',
17551917566=>'BN',
17552917567=>'BN',
17553917568=>'BN',
17554917569=>'BN',
17555917570=>'BN',
17556917571=>'BN',
17557917572=>'BN',
17558917573=>'BN',
17559917574=>'BN',
17560917575=>'BN',
17561917576=>'BN',
17562917577=>'BN',
17563917578=>'BN',
17564917579=>'BN',
17565917580=>'BN',
17566917581=>'BN',
17567917582=>'BN',
17568917583=>'BN',
17569917584=>'BN',
17570917585=>'BN',
17571917586=>'BN',
17572917587=>'BN',
17573917588=>'BN',
17574917589=>'BN',
17575917590=>'BN',
17576917591=>'BN',
17577917592=>'BN',
17578917593=>'BN',
17579917594=>'BN',
17580917595=>'BN',
17581917596=>'BN',
17582917597=>'BN',
17583917598=>'BN',
17584917599=>'BN',
17585917600=>'BN',
17586917601=>'BN',
17587917602=>'BN',
17588917603=>'BN',
17589917604=>'BN',
17590917605=>'BN',
17591917606=>'BN',
17592917607=>'BN',
17593917608=>'BN',
17594917609=>'BN',
17595917610=>'BN',
17596917611=>'BN',
17597917612=>'BN',
17598917613=>'BN',
17599917614=>'BN',
17600917615=>'BN',
17601917616=>'BN',
17602917617=>'BN',
17603917618=>'BN',
17604917619=>'BN',
17605917620=>'BN',
17606917621=>'BN',
17607917622=>'BN',
17608917623=>'BN',
17609917624=>'BN',
17610917625=>'BN',
17611917626=>'BN',
17612917627=>'BN',
17613917628=>'BN',
17614917629=>'BN',
17615917630=>'BN',
17616917631=>'BN',
17617917760=>'NSM',
17618917761=>'NSM',
17619917762=>'NSM',
17620917763=>'NSM',
17621917764=>'NSM',
17622917765=>'NSM',
17623917766=>'NSM',
17624917767=>'NSM',
17625917768=>'NSM',
17626917769=>'NSM',
17627917770=>'NSM',
17628917771=>'NSM',
17629917772=>'NSM',
17630917773=>'NSM',
17631917774=>'NSM',
17632917775=>'NSM',
17633917776=>'NSM',
17634917777=>'NSM',
17635917778=>'NSM',
17636917779=>'NSM',
17637917780=>'NSM',
17638917781=>'NSM',
17639917782=>'NSM',
17640917783=>'NSM',
17641917784=>'NSM',
17642917785=>'NSM',
17643917786=>'NSM',
17644917787=>'NSM',
17645917788=>'NSM',
17646917789=>'NSM',
17647917790=>'NSM',
17648917791=>'NSM',
17649917792=>'NSM',
17650917793=>'NSM',
17651917794=>'NSM',
17652917795=>'NSM',
17653917796=>'NSM',
17654917797=>'NSM',
17655917798=>'NSM',
17656917799=>'NSM',
17657917800=>'NSM',
17658917801=>'NSM',
17659917802=>'NSM',
17660917803=>'NSM',
17661917804=>'NSM',
17662917805=>'NSM',
17663917806=>'NSM',
17664917807=>'NSM',
17665917808=>'NSM',
17666917809=>'NSM',
17667917810=>'NSM',
17668917811=>'NSM',
17669917812=>'NSM',
17670917813=>'NSM',
17671917814=>'NSM',
17672917815=>'NSM',
17673917816=>'NSM',
17674917817=>'NSM',
17675917818=>'NSM',
17676917819=>'NSM',
17677917820=>'NSM',
17678917821=>'NSM',
17679917822=>'NSM',
17680917823=>'NSM',
17681917824=>'NSM',
17682917825=>'NSM',
17683917826=>'NSM',
17684917827=>'NSM',
17685917828=>'NSM',
17686917829=>'NSM',
17687917830=>'NSM',
17688917831=>'NSM',
17689917832=>'NSM',
17690917833=>'NSM',
17691917834=>'NSM',
17692917835=>'NSM',
17693917836=>'NSM',
17694917837=>'NSM',
17695917838=>'NSM',
17696917839=>'NSM',
17697917840=>'NSM',
17698917841=>'NSM',
17699917842=>'NSM',
17700917843=>'NSM',
17701917844=>'NSM',
17702917845=>'NSM',
17703917846=>'NSM',
17704917847=>'NSM',
17705917848=>'NSM',
17706917849=>'NSM',
17707917850=>'NSM',
17708917851=>'NSM',
17709917852=>'NSM',
17710917853=>'NSM',
17711917854=>'NSM',
17712917855=>'NSM',
17713917856=>'NSM',
17714917857=>'NSM',
17715917858=>'NSM',
17716917859=>'NSM',
17717917860=>'NSM',
17718917861=>'NSM',
17719917862=>'NSM',
17720917863=>'NSM',
17721917864=>'NSM',
17722917865=>'NSM',
17723917866=>'NSM',
17724917867=>'NSM',
17725917868=>'NSM',
17726917869=>'NSM',
17727917870=>'NSM',
17728917871=>'NSM',
17729917872=>'NSM',
17730917873=>'NSM',
17731917874=>'NSM',
17732917875=>'NSM',
17733917876=>'NSM',
17734917877=>'NSM',
17735917878=>'NSM',
17736917879=>'NSM',
17737917880=>'NSM',
17738917881=>'NSM',
17739917882=>'NSM',
17740917883=>'NSM',
17741917884=>'NSM',
17742917885=>'NSM',
17743917886=>'NSM',
17744917887=>'NSM',
17745917888=>'NSM',
17746917889=>'NSM',
17747917890=>'NSM',
17748917891=>'NSM',
17749917892=>'NSM',
17750917893=>'NSM',
17751917894=>'NSM',
17752917895=>'NSM',
17753917896=>'NSM',
17754917897=>'NSM',
17755917898=>'NSM',
17756917899=>'NSM',
17757917900=>'NSM',
17758917901=>'NSM',
17759917902=>'NSM',
17760917903=>'NSM',
17761917904=>'NSM',
17762917905=>'NSM',
17763917906=>'NSM',
17764917907=>'NSM',
17765917908=>'NSM',
17766917909=>'NSM',
17767917910=>'NSM',
17768917911=>'NSM',
17769917912=>'NSM',
17770917913=>'NSM',
17771917914=>'NSM',
17772917915=>'NSM',
17773917916=>'NSM',
17774917917=>'NSM',
17775917918=>'NSM',
17776917919=>'NSM',
17777917920=>'NSM',
17778917921=>'NSM',
17779917922=>'NSM',
17780917923=>'NSM',
17781917924=>'NSM',
17782917925=>'NSM',
17783917926=>'NSM',
17784917927=>'NSM',
17785917928=>'NSM',
17786917929=>'NSM',
17787917930=>'NSM',
17788917931=>'NSM',
17789917932=>'NSM',
17790917933=>'NSM',
17791917934=>'NSM',
17792917935=>'NSM',
17793917936=>'NSM',
17794917937=>'NSM',
17795917938=>'NSM',
17796917939=>'NSM',
17797917940=>'NSM',
17798917941=>'NSM',
17799917942=>'NSM',
17800917943=>'NSM',
17801917944=>'NSM',
17802917945=>'NSM',
17803917946=>'NSM',
17804917947=>'NSM',
17805917948=>'NSM',
17806917949=>'NSM',
17807917950=>'NSM',
17808917951=>'NSM',
17809917952=>'NSM',
17810917953=>'NSM',
17811917954=>'NSM',
17812917955=>'NSM',
17813917956=>'NSM',
17814917957=>'NSM',
17815917958=>'NSM',
17816917959=>'NSM',
17817917960=>'NSM',
17818917961=>'NSM',
17819917962=>'NSM',
17820917963=>'NSM',
17821917964=>'NSM',
17822917965=>'NSM',
17823917966=>'NSM',
17824917967=>'NSM',
17825917968=>'NSM',
17826917969=>'NSM',
17827917970=>'NSM',
17828917971=>'NSM',
17829917972=>'NSM',
17830917973=>'NSM',
17831917974=>'NSM',
17832917975=>'NSM',
17833917976=>'NSM',
17834917977=>'NSM',
17835917978=>'NSM',
17836917979=>'NSM',
17837917980=>'NSM',
17838917981=>'NSM',
17839917982=>'NSM',
17840917983=>'NSM',
17841917984=>'NSM',
17842917985=>'NSM',
17843917986=>'NSM',
17844917987=>'NSM',
17845917988=>'NSM',
17846917989=>'NSM',
17847917990=>'NSM',
17848917991=>'NSM',
17849917992=>'NSM',
17850917993=>'NSM',
17851917994=>'NSM',
17852917995=>'NSM',
17853917996=>'NSM',
17854917997=>'NSM',
17855917998=>'NSM',
17856917999=>'NSM',
17857983040=>'L',
178581048573=>'L',
178591048576=>'L',
178601114109=>'L'
17861);
17862
17863/**
17864 * Mirror unicode characters. For information on bidi mirroring, see UAX #9: Bidirectional Algorithm, at http://www.unicode.org/unicode/reports/tr9/
17865 * @public
17866 */
17867public static $uni_mirror = array (
178680x0028=>0x0029,
178690x0029=>0x0028,
178700x003C=>0x003E,
178710x003E=>0x003C,
178720x005B=>0x005D,
178730x005D=>0x005B,
178740x007B=>0x007D,
178750x007D=>0x007B,
178760x00AB=>0x00BB,
178770x00BB=>0x00AB,
178780x0F3A=>0x0F3B,
178790x0F3B=>0x0F3A,
178800x0F3C=>0x0F3D,
178810x0F3D=>0x0F3C,
178820x169B=>0x169C,
178830x169C=>0x169B,
178840x2018=>0x2019,
178850x2019=>0x2018,
178860x201C=>0x201D,
178870x201D=>0x201C,
178880x2039=>0x203A,
178890x203A=>0x2039,
178900x2045=>0x2046,
178910x2046=>0x2045,
178920x207D=>0x207E,
178930x207E=>0x207D,
178940x208D=>0x208E,
178950x208E=>0x208D,
178960x2208=>0x220B,
178970x2209=>0x220C,
178980x220A=>0x220D,
178990x220B=>0x2208,
179000x220C=>0x2209,
179010x220D=>0x220A,
179020x2215=>0x29F5,
179030x223C=>0x223D,
179040x223D=>0x223C,
179050x2243=>0x22CD,
179060x2252=>0x2253,
179070x2253=>0x2252,
179080x2254=>0x2255,
179090x2255=>0x2254,
179100x2264=>0x2265,
179110x2265=>0x2264,
179120x2266=>0x2267,
179130x2267=>0x2266,
179140x2268=>0x2269,
179150x2269=>0x2268,
179160x226A=>0x226B,
179170x226B=>0x226A,
179180x226E=>0x226F,
179190x226F=>0x226E,
179200x2270=>0x2271,
179210x2271=>0x2270,
179220x2272=>0x2273,
179230x2273=>0x2272,
179240x2274=>0x2275,
179250x2275=>0x2274,
179260x2276=>0x2277,
179270x2277=>0x2276,
179280x2278=>0x2279,
179290x2279=>0x2278,
179300x227A=>0x227B,
179310x227B=>0x227A,
179320x227C=>0x227D,
179330x227D=>0x227C,
179340x227E=>0x227F,
179350x227F=>0x227E,
179360x2280=>0x2281,
179370x2281=>0x2280,
179380x2282=>0x2283,
179390x2283=>0x2282,
179400x2284=>0x2285,
179410x2285=>0x2284,
179420x2286=>0x2287,
179430x2287=>0x2286,
179440x2288=>0x2289,
179450x2289=>0x2288,
179460x228A=>0x228B,
179470x228B=>0x228A,
179480x228F=>0x2290,
179490x2290=>0x228F,
179500x2291=>0x2292,
179510x2292=>0x2291,
179520x2298=>0x29B8,
179530x22A2=>0x22A3,
179540x22A3=>0x22A2,
179550x22A6=>0x2ADE,
179560x22A8=>0x2AE4,
179570x22A9=>0x2AE3,
179580x22AB=>0x2AE5,
179590x22B0=>0x22B1,
179600x22B1=>0x22B0,
179610x22B2=>0x22B3,
179620x22B3=>0x22B2,
179630x22B4=>0x22B5,
179640x22B5=>0x22B4,
179650x22B6=>0x22B7,
179660x22B7=>0x22B6,
179670x22C9=>0x22CA,
179680x22CA=>0x22C9,
179690x22CB=>0x22CC,
179700x22CC=>0x22CB,
179710x22CD=>0x2243,
179720x22D0=>0x22D1,
179730x22D1=>0x22D0,
179740x22D6=>0x22D7,
179750x22D7=>0x22D6,
179760x22D8=>0x22D9,
179770x22D9=>0x22D8,
179780x22DA=>0x22DB,
179790x22DB=>0x22DA,
179800x22DC=>0x22DD,
179810x22DD=>0x22DC,
179820x22DE=>0x22DF,
179830x22DF=>0x22DE,
179840x22E0=>0x22E1,
179850x22E1=>0x22E0,
179860x22E2=>0x22E3,
179870x22E3=>0x22E2,
179880x22E4=>0x22E5,
179890x22E5=>0x22E4,
179900x22E6=>0x22E7,
179910x22E7=>0x22E6,
179920x22E8=>0x22E9,
179930x22E9=>0x22E8,
179940x22EA=>0x22EB,
179950x22EB=>0x22EA,
179960x22EC=>0x22ED,
179970x22ED=>0x22EC,
179980x22F0=>0x22F1,
179990x22F1=>0x22F0,
180000x22F2=>0x22FA,
180010x22F3=>0x22FB,
180020x22F4=>0x22FC,
180030x22F6=>0x22FD,
180040x22F7=>0x22FE,
180050x22FA=>0x22F2,
180060x22FB=>0x22F3,
180070x22FC=>0x22F4,
180080x22FD=>0x22F6,
180090x22FE=>0x22F7,
180100x2308=>0x2309,
180110x2309=>0x2308,
180120x230A=>0x230B,
180130x230B=>0x230A,
180140x2329=>0x232A,
180150x232A=>0x2329,
180160x2768=>0x2769,
180170x2769=>0x2768,
180180x276A=>0x276B,
180190x276B=>0x276A,
180200x276C=>0x276D,
180210x276D=>0x276C,
180220x276E=>0x276F,
180230x276F=>0x276E,
180240x2770=>0x2771,
180250x2771=>0x2770,
180260x2772=>0x2773,
180270x2773=>0x2772,
180280x2774=>0x2775,
180290x2775=>0x2774,
180300x27C3=>0x27C4,
180310x27C4=>0x27C3,
180320x27C5=>0x27C6,
180330x27C6=>0x27C5,
180340x27D5=>0x27D6,
180350x27D6=>0x27D5,
180360x27DD=>0x27DE,
180370x27DE=>0x27DD,
180380x27E2=>0x27E3,
180390x27E3=>0x27E2,
180400x27E4=>0x27E5,
180410x27E5=>0x27E4,
180420x27E6=>0x27E7,
180430x27E7=>0x27E6,
180440x27E8=>0x27E9,
180450x27E9=>0x27E8,
180460x27EA=>0x27EB,
180470x27EB=>0x27EA,
180480x2983=>0x2984,
180490x2984=>0x2983,
180500x2985=>0x2986,
180510x2986=>0x2985,
180520x2987=>0x2988,
180530x2988=>0x2987,
180540x2989=>0x298A,
180550x298A=>0x2989,
180560x298B=>0x298C,
180570x298C=>0x298B,
180580x298D=>0x2990,
180590x298E=>0x298F,
180600x298F=>0x298E,
180610x2990=>0x298D,
180620x2991=>0x2992,
180630x2992=>0x2991,
180640x2993=>0x2994,
180650x2994=>0x2993,
180660x2995=>0x2996,
180670x2996=>0x2995,
180680x2997=>0x2998,
180690x2998=>0x2997,
180700x29B8=>0x2298,
180710x29C0=>0x29C1,
180720x29C1=>0x29C0,
180730x29C4=>0x29C5,
180740x29C5=>0x29C4,
180750x29CF=>0x29D0,
180760x29D0=>0x29CF,
180770x29D1=>0x29D2,
180780x29D2=>0x29D1,
180790x29D4=>0x29D5,
180800x29D5=>0x29D4,
180810x29D8=>0x29D9,
180820x29D9=>0x29D8,
180830x29DA=>0x29DB,
180840x29DB=>0x29DA,
180850x29F5=>0x2215,
180860x29F8=>0x29F9,
180870x29F9=>0x29F8,
180880x29FC=>0x29FD,
180890x29FD=>0x29FC,
180900x2A2B=>0x2A2C,
180910x2A2C=>0x2A2B,
180920x2A2D=>0x2A2E,
180930x2A2E=>0x2A2D,
180940x2A34=>0x2A35,
180950x2A35=>0x2A34,
180960x2A3C=>0x2A3D,
180970x2A3D=>0x2A3C,
180980x2A64=>0x2A65,
180990x2A65=>0x2A64,
181000x2A79=>0x2A7A,
181010x2A7A=>0x2A79,
181020x2A7D=>0x2A7E,
181030x2A7E=>0x2A7D,
181040x2A7F=>0x2A80,
181050x2A80=>0x2A7F,
181060x2A81=>0x2A82,
181070x2A82=>0x2A81,
181080x2A83=>0x2A84,
181090x2A84=>0x2A83,
181100x2A8B=>0x2A8C,
181110x2A8C=>0x2A8B,
181120x2A91=>0x2A92,
181130x2A92=>0x2A91,
181140x2A93=>0x2A94,
181150x2A94=>0x2A93,
181160x2A95=>0x2A96,
181170x2A96=>0x2A95,
181180x2A97=>0x2A98,
181190x2A98=>0x2A97,
181200x2A99=>0x2A9A,
181210x2A9A=>0x2A99,
181220x2A9B=>0x2A9C,
181230x2A9C=>0x2A9B,
181240x2AA1=>0x2AA2,
181250x2AA2=>0x2AA1,
181260x2AA6=>0x2AA7,
181270x2AA7=>0x2AA6,
181280x2AA8=>0x2AA9,
181290x2AA9=>0x2AA8,
181300x2AAA=>0x2AAB,
181310x2AAB=>0x2AAA,
181320x2AAC=>0x2AAD,
181330x2AAD=>0x2AAC,
181340x2AAF=>0x2AB0,
181350x2AB0=>0x2AAF,
181360x2AB3=>0x2AB4,
181370x2AB4=>0x2AB3,
181380x2ABB=>0x2ABC,
181390x2ABC=>0x2ABB,
181400x2ABD=>0x2ABE,
181410x2ABE=>0x2ABD,
181420x2ABF=>0x2AC0,
181430x2AC0=>0x2ABF,
181440x2AC1=>0x2AC2,
181450x2AC2=>0x2AC1,
181460x2AC3=>0x2AC4,
181470x2AC4=>0x2AC3,
181480x2AC5=>0x2AC6,
181490x2AC6=>0x2AC5,
181500x2ACD=>0x2ACE,
181510x2ACE=>0x2ACD,
181520x2ACF=>0x2AD0,
181530x2AD0=>0x2ACF,
181540x2AD1=>0x2AD2,
181550x2AD2=>0x2AD1,
181560x2AD3=>0x2AD4,
181570x2AD4=>0x2AD3,
181580x2AD5=>0x2AD6,
181590x2AD6=>0x2AD5,
181600x2ADE=>0x22A6,
181610x2AE3=>0x22A9,
181620x2AE4=>0x22A8,
181630x2AE5=>0x22AB,
181640x2AEC=>0x2AED,
181650x2AED=>0x2AEC,
181660x2AF7=>0x2AF8,
181670x2AF8=>0x2AF7,
181680x2AF9=>0x2AFA,
181690x2AFA=>0x2AF9,
181700x2E02=>0x2E03,
181710x2E03=>0x2E02,
181720x2E04=>0x2E05,
181730x2E05=>0x2E04,
181740x2E09=>0x2E0A,
181750x2E0A=>0x2E09,
181760x2E0C=>0x2E0D,
181770x2E0D=>0x2E0C,
181780x2E1C=>0x2E1D,
181790x2E1D=>0x2E1C,
181800x3008=>0x3009,
181810x3009=>0x3008,
181820x300A=>0x300B,
181830x300B=>0x300A,
181840x300C=>0x300D,
181850x300D=>0x300C,
181860x300E=>0x300F,
181870x300F=>0x300E,
181880x3010=>0x3011,
181890x3011=>0x3010,
181900x3014=>0x3015,
181910x3015=>0x3014,
181920x3016=>0x3017,
181930x3017=>0x3016,
181940x3018=>0x3019,
181950x3019=>0x3018,
181960x301A=>0x301B,
181970x301B=>0x301A,
181980x301D=>0x301E,
181990x301E=>0x301D,
182000xFE59=>0xFE5A,
182010xFE5A=>0xFE59,
182020xFE5B=>0xFE5C,
182030xFE5C=>0xFE5B,
182040xFE5D=>0xFE5E,
182050xFE5E=>0xFE5D,
182060xFE64=>0xFE65,
182070xFE65=>0xFE64,
182080xFF08=>0xFF09,
182090xFF09=>0xFF08,
182100xFF1C=>0xFF1E,
182110xFF1E=>0xFF1C,
182120xFF3B=>0xFF3D,
182130xFF3D=>0xFF3B,
182140xFF5B=>0xFF5D,
182150xFF5D=>0xFF5B,
182160xFF5F=>0xFF60,
182170xFF60=>0xFF5F,
182180xFF62=>0xFF63,
182190xFF63=>0xFF62);
18220
18221/**
18222 * Arabic shape substitutions: char code => (isolated, final, initial, medial).
18223 * @public
18224 */
18225public static $uni_arabicsubst = array(
182261569=>array(65152),
182271570=>array(65153, 65154, 65153, 65154),
182281571=>array(65155, 65156, 65155, 65156),
182291572=>array(65157, 65158),
182301573=>array(65159, 65160, 65159, 65160),
182311574=>array(65161, 65162, 65163, 65164),
182321575=>array(65165, 65166, 65165, 65166),
182331576=>array(65167, 65168, 65169, 65170),
182341577=>array(65171, 65172),
182351578=>array(65173, 65174, 65175, 65176),
182361579=>array(65177, 65178, 65179, 65180),
182371580=>array(65181, 65182, 65183, 65184),
182381581=>array(65185, 65186, 65187, 65188),
182391582=>array(65189, 65190, 65191, 65192),
182401583=>array(65193, 65194, 65193, 65194),
182411584=>array(65195, 65196, 65195, 65196),
182421585=>array(65197, 65198, 65197, 65198),
182431586=>array(65199, 65200, 65199, 65200),
182441587=>array(65201, 65202, 65203, 65204),
182451588=>array(65205, 65206, 65207, 65208),
182461589=>array(65209, 65210, 65211, 65212),
182471590=>array(65213, 65214, 65215, 65216),
182481591=>array(65217, 65218, 65219, 65220),
182491592=>array(65221, 65222, 65223, 65224),
182501593=>array(65225, 65226, 65227, 65228),
182511594=>array(65229, 65230, 65231, 65232),
182521601=>array(65233, 65234, 65235, 65236),
182531602=>array(65237, 65238, 65239, 65240),
182541603=>array(65241, 65242, 65243, 65244),
182551604=>array(65245, 65246, 65247, 65248),
182561605=>array(65249, 65250, 65251, 65252),
182571606=>array(65253, 65254, 65255, 65256),
182581607=>array(65257, 65258, 65259, 65260),
182591608=>array(65261, 65262, 65261, 65262),
182601609=>array(65263, 65264, 64488, 64489),
182611610=>array(65265, 65266, 65267, 65268),
182621649=>array(64336, 64337),
182631655=>array(64477),
182641657=>array(64358, 64359, 64360, 64361),
182651658=>array(64350, 64351, 64352, 64353),
182661659=>array(64338, 64339, 64340, 64341),
182671662=>array(64342, 64343, 64344, 64345),
182681663=>array(64354, 64355, 64356, 64357),
182691664=>array(64346, 64347, 64348, 64349),
182701667=>array(64374, 64375, 64376, 64377),
182711668=>array(64370, 64371, 64372, 64373),
182721670=>array(64378, 64379, 64380, 64381),
182731671=>array(64382, 64383, 64384, 64385),
182741672=>array(64392, 64393),
182751676=>array(64388, 64389),
182761677=>array(64386, 64387),
182771678=>array(64390, 64391),
182781681=>array(64396, 64397),
182791688=>array(64394, 64395, 64394, 64395),
182801700=>array(64362, 64363, 64364, 64365),
182811702=>array(64366, 64367, 64368, 64369),
182821705=>array(64398, 64399, 64400, 64401),
182831709=>array(64467, 64468, 64469, 64470),
182841711=>array(64402, 64403, 64404, 64405),
182851713=>array(64410, 64411, 64412, 64413),
182861715=>array(64406, 64407, 64408, 64409),
182871722=>array(64414, 64415),
182881723=>array(64416, 64417, 64418, 64419),
182891726=>array(64426, 64427, 64428, 64429),
182901728=>array(64420, 64421),
182911729=>array(64422, 64423, 64424, 64425),
182921733=>array(64480, 64481),
182931734=>array(64473, 64474),
182941735=>array(64471, 64472),
182951736=>array(64475, 64476),
182961737=>array(64482, 64483),
182971739=>array(64478, 64479),
182981740=>array(64508, 64509, 64510, 64511),
182991744=>array(64484, 64485, 64486, 64487),
183001746=>array(64430, 64431),
183011747=>array(64432, 64433)
18302);
18303
18304/**
18305 * Arabic laa letter: (char code => isolated, final, initial, medial).
18306 * @public
18307 */
18308public static $uni_laa_array = array (
183091570 =>array(65269, 65270, 65269, 65270),
183101571 =>array(65271, 65272, 65271, 65272),
183111573 =>array(65273, 65274, 65273, 65274),
183121575 =>array(65275, 65276, 65275, 65276)
18313);
18314
18315/**
18316 * Array of character substitutions for sequences of two diacritics symbols.
18317 * Putting the combining mark and character in the same glyph allows us to avoid the two marks overlapping each other in an illegible manner.
18318 * second NSM char code => substitution char
18319 * @public
18320 */
18321public static $uni_diacritics = array (
183221612=>64606, # Shadda + Dammatan
183231613=>64607, # Shadda + Kasratan
183241614=>64608, # Shadda + Fatha
183251615=>64609, # Shadda + Damma
183261616=>64610 # Shadda + Kasra
18327);
18328
18329/**
18330 * Array of character substitutions from UTF-8 Unicode to Latin1.
18331 * @public
18332 */
18333public static $uni_utf8tolatin = array (
183348364=>128, # Euro1
18335338=>140, # OE
18336352=>138, # Scaron
18337376=>159, # Ydieresis
18338381=>142, # Zcaron2
183398226=>149, # bullet3
18340710=>136, # circumflex
183418224=>134, # dagger
183428225=>135, # daggerdbl
183438230=>133, # ellipsis
183448212=>151, # emdash
183458211=>150, # endash
18346402=>131, # florin
183478249=>139, # guilsinglleft
183488250=>155, # guilsinglright
18349339=>156, # oe
183508240=>137, # perthousand
183518222=>132, # quotedblbase
183528220=>147, # quotedblleft
183538221=>148, # quotedblright
183548216=>145, # quoteleft
183558217=>146, # quoteright
183568218=>130, # quotesinglbase
18357353=>154, # scaron
18358732=>152, # tilde
183598482=>153, # trademark
18360382=>158 # zcaron2
18361);
18362
18363/**
18364 * Array of Encoding Maps.
18365 * @public static
18366 */
18367public static $encmap = array(
18368
18369// encoding map for: cp874
18370'cp874' => array(0=>'.notdef',1=>'.notdef',2=>'.notdef',3=>'.notdef',4=>'.notdef',5=>'.notdef',6=>'.notdef',7=>'.notdef',8=>'.notdef',9=>'.notdef',10=>'.notdef',11=>'.notdef',12=>'.notdef',13=>'.notdef',14=>'.notdef',15=>'.notdef',16=>'.notdef',17=>'.notdef',18=>'.notdef',19=>'.notdef',20=>'.notdef',21=>'.notdef',22=>'.notdef',23=>'.notdef',24=>'.notdef',25=>'.notdef',26=>'.notdef',27=>'.notdef',28=>'.notdef',29=>'.notdef',30=>'.notdef',31=>'.notdef',32=>'space',33=>'exclam',34=>'quotedbl',35=>'numbersign',36=>'dollar',37=>'percent',38=>'ampersand',39=>'quotesingle',40=>'parenleft',41=>'parenright',42=>'asterisk',43=>'plus',44=>'comma',45=>'hyphen',46=>'period',47=>'slash',48=>'zero',49=>'one',50=>'two',51=>'three',52=>'four',53=>'five',54=>'six',55=>'seven',56=>'eight',57=>'nine',58=>'colon',59=>'semicolon',60=>'less',61=>'equal',62=>'greater',63=>'question',64=>'at',65=>'A',66=>'B',67=>'C',68=>'D',69=>'E',70=>'F',71=>'G',72=>'H',73=>'I',74=>'J',75=>'K',76=>'L',77=>'M',78=>'N',79=>'O',80=>'P',81=>'Q',82=>'R',83=>'S',84=>'T',85=>'U',86=>'V',87=>'W',88=>'X',89=>'Y',90=>'Z',91=>'bracketleft',92=>'backslash',93=>'bracketright',94=>'asciicircum',95=>'underscore',96=>'grave',97=>'a',98=>'b',99=>'c',100=>'d',101=>'e',102=>'f',103=>'g',104=>'h',105=>'i',106=>'j',107=>'k',108=>'l',109=>'m',110=>'n',111=>'o',112=>'p',113=>'q',114=>'r',115=>'s',116=>'t',117=>'u',118=>'v',119=>'w',120=>'x',121=>'y',122=>'z',123=>'braceleft',124=>'bar',125=>'braceright',126=>'asciitilde',127=>'.notdef',128=>'Euro',129=>'.notdef',130=>'.notdef',131=>'.notdef',132=>'.notdef',133=>'ellipsis',134=>'.notdef',135=>'.notdef',136=>'.notdef',137=>'.notdef',138=>'.notdef',139=>'.notdef',140=>'.notdef',141=>'.notdef',142=>'.notdef',143=>'.notdef',144=>'.notdef',145=>'quoteleft',146=>'quoteright',147=>'quotedblleft',148=>'quotedblright',149=>'bullet',150=>'endash',151=>'emdash',152=>'.notdef',153=>'.notdef',154=>'.notdef',155=>'.notdef',156=>'.notdef',157=>'.notdef',158=>'.notdef',159=>'.notdef',160=>'space',161=>'kokaithai',162=>'khokhaithai',163=>'khokhuatthai',164=>'khokhwaithai',165=>'khokhonthai',166=>'khorakhangthai',167=>'ngonguthai',168=>'chochanthai',169=>'chochingthai',170=>'chochangthai',171=>'sosothai',172=>'chochoethai',173=>'yoyingthai',174=>'dochadathai',175=>'topatakthai',176=>'thothanthai',177=>'thonangmonthothai',178=>'thophuthaothai',179=>'nonenthai',180=>'dodekthai',181=>'totaothai',182=>'thothungthai',183=>'thothahanthai',184=>'thothongthai',185=>'nonuthai',186=>'bobaimaithai',187=>'poplathai',188=>'phophungthai',189=>'fofathai',190=>'phophanthai',191=>'fofanthai',192=>'phosamphaothai',193=>'momathai',194=>'yoyakthai',195=>'roruathai',196=>'ruthai',197=>'lolingthai',198=>'luthai',199=>'wowaenthai',200=>'sosalathai',201=>'sorusithai',202=>'sosuathai',203=>'hohipthai',204=>'lochulathai',205=>'oangthai',206=>'honokhukthai',207=>'paiyannoithai',208=>'saraathai',209=>'maihanakatthai',210=>'saraaathai',211=>'saraamthai',212=>'saraithai',213=>'saraiithai',214=>'sarauethai',215=>'saraueethai',216=>'sarauthai',217=>'sarauuthai',218=>'phinthuthai',219=>'.notdef',220=>'.notdef',221=>'.notdef',222=>'.notdef',223=>'bahtthai',224=>'saraethai',225=>'saraaethai',226=>'saraothai',227=>'saraaimaimuanthai',228=>'saraaimaimalaithai',229=>'lakkhangyaothai',230=>'maiyamokthai',231=>'maitaikhuthai',232=>'maiekthai',233=>'maithothai',234=>'maitrithai',235=>'maichattawathai',236=>'thanthakhatthai',237=>'nikhahitthai',238=>'yamakkanthai',239=>'fongmanthai',240=>'zerothai',241=>'onethai',242=>'twothai',243=>'threethai',244=>'fourthai',245=>'fivethai',246=>'sixthai',247=>'seventhai',248=>'eightthai',249=>'ninethai',250=>'angkhankhuthai',251=>'khomutthai',252=>'.notdef',253=>'.notdef',254=>'.notdef',255=>'.notdef'),
18371
18372// encoding map for: cp1250
18373'cp1250' => array(0=>'.notdef',1=>'.notdef',2=>'.notdef',3=>'.notdef',4=>'.notdef',5=>'.notdef',6=>'.notdef',7=>'.notdef',8=>'.notdef',9=>'.notdef',10=>'.notdef',11=>'.notdef',12=>'.notdef',13=>'.notdef',14=>'.notdef',15=>'.notdef',16=>'.notdef',17=>'.notdef',18=>'.notdef',19=>'.notdef',20=>'.notdef',21=>'.notdef',22=>'.notdef',23=>'.notdef',24=>'.notdef',25=>'.notdef',26=>'.notdef',27=>'.notdef',28=>'.notdef',29=>'.notdef',30=>'.notdef',31=>'.notdef',32=>'space',33=>'exclam',34=>'quotedbl',35=>'numbersign',36=>'dollar',37=>'percent',38=>'ampersand',39=>'quotesingle',40=>'parenleft',41=>'parenright',42=>'asterisk',43=>'plus',44=>'comma',45=>'hyphen',46=>'period',47=>'slash',48=>'zero',49=>'one',50=>'two',51=>'three',52=>'four',53=>'five',54=>'six',55=>'seven',56=>'eight',57=>'nine',58=>'colon',59=>'semicolon',60=>'less',61=>'equal',62=>'greater',63=>'question',64=>'at',65=>'A',66=>'B',67=>'C',68=>'D',69=>'E',70=>'F',71=>'G',72=>'H',73=>'I',74=>'J',75=>'K',76=>'L',77=>'M',78=>'N',79=>'O',80=>'P',81=>'Q',82=>'R',83=>'S',84=>'T',85=>'U',86=>'V',87=>'W',88=>'X',89=>'Y',90=>'Z',91=>'bracketleft',92=>'backslash',93=>'bracketright',94=>'asciicircum',95=>'underscore',96=>'grave',97=>'a',98=>'b',99=>'c',100=>'d',101=>'e',102=>'f',103=>'g',104=>'h',105=>'i',106=>'j',107=>'k',108=>'l',109=>'m',110=>'n',111=>'o',112=>'p',113=>'q',114=>'r',115=>'s',116=>'t',117=>'u',118=>'v',119=>'w',120=>'x',121=>'y',122=>'z',123=>'braceleft',124=>'bar',125=>'braceright',126=>'asciitilde',127=>'.notdef',128=>'Euro',129=>'.notdef',130=>'quotesinglbase',131=>'.notdef',132=>'quotedblbase',133=>'ellipsis',134=>'dagger',135=>'daggerdbl',136=>'.notdef',137=>'perthousand',138=>'Scaron',139=>'guilsinglleft',140=>'Sacute',141=>'Tcaron',142=>'Zcaron',143=>'Zacute',144=>'.notdef',145=>'quoteleft',146=>'quoteright',147=>'quotedblleft',148=>'quotedblright',149=>'bullet',150=>'endash',151=>'emdash',152=>'.notdef',153=>'trademark',154=>'scaron',155=>'guilsinglright',156=>'sacute',157=>'tcaron',158=>'zcaron',159=>'zacute',160=>'space',161=>'caron',162=>'breve',163=>'Lslash',164=>'currency',165=>'Aogonek',166=>'brokenbar',167=>'section',168=>'dieresis',169=>'copyright',170=>'Scedilla',171=>'guillemotleft',172=>'logicalnot',173=>'hyphen',174=>'registered',175=>'Zdotaccent',176=>'degree',177=>'plusminus',178=>'ogonek',179=>'lslash',180=>'acute',181=>'mu',182=>'paragraph',183=>'periodcentered',184=>'cedilla',185=>'aogonek',186=>'scedilla',187=>'guillemotright',188=>'Lcaron',189=>'hungarumlaut',190=>'lcaron',191=>'zdotaccent',192=>'Racute',193=>'Aacute',194=>'Acircumflex',195=>'Abreve',196=>'Adieresis',197=>'Lacute',198=>'Cacute',199=>'Ccedilla',200=>'Ccaron',201=>'Eacute',202=>'Eogonek',203=>'Edieresis',204=>'Ecaron',205=>'Iacute',206=>'Icircumflex',207=>'Dcaron',208=>'Dcroat',209=>'Nacute',210=>'Ncaron',211=>'Oacute',212=>'Ocircumflex',213=>'Ohungarumlaut',214=>'Odieresis',215=>'multiply',216=>'Rcaron',217=>'Uring',218=>'Uacute',219=>'Uhungarumlaut',220=>'Udieresis',221=>'Yacute',222=>'Tcommaaccent',223=>'germandbls',224=>'racute',225=>'aacute',226=>'acircumflex',227=>'abreve',228=>'adieresis',229=>'lacute',230=>'cacute',231=>'ccedilla',232=>'ccaron',233=>'eacute',234=>'eogonek',235=>'edieresis',236=>'ecaron',237=>'iacute',238=>'icircumflex',239=>'dcaron',240=>'dcroat',241=>'nacute',242=>'ncaron',243=>'oacute',244=>'ocircumflex',245=>'ohungarumlaut',246=>'odieresis',247=>'divide',248=>'rcaron',249=>'uring',250=>'uacute',251=>'uhungarumlaut',252=>'udieresis',253=>'yacute',254=>'tcommaaccent',255=>'dotaccent'),
18374
18375// encoding map for: cp1251
18376'cp1251' => array(0=>'.notdef',1=>'.notdef',2=>'.notdef',3=>'.notdef',4=>'.notdef',5=>'.notdef',6=>'.notdef',7=>'.notdef',8=>'.notdef',9=>'.notdef',10=>'.notdef',11=>'.notdef',12=>'.notdef',13=>'.notdef',14=>'.notdef',15=>'.notdef',16=>'.notdef',17=>'.notdef',18=>'.notdef',19=>'.notdef',20=>'.notdef',21=>'.notdef',22=>'.notdef',23=>'.notdef',24=>'.notdef',25=>'.notdef',26=>'.notdef',27=>'.notdef',28=>'.notdef',29=>'.notdef',30=>'.notdef',31=>'.notdef',32=>'space',33=>'exclam',34=>'quotedbl',35=>'numbersign',36=>'dollar',37=>'percent',38=>'ampersand',39=>'quotesingle',40=>'parenleft',41=>'parenright',42=>'asterisk',43=>'plus',44=>'comma',45=>'hyphen',46=>'period',47=>'slash',48=>'zero',49=>'one',50=>'two',51=>'three',52=>'four',53=>'five',54=>'six',55=>'seven',56=>'eight',57=>'nine',58=>'colon',59=>'semicolon',60=>'less',61=>'equal',62=>'greater',63=>'question',64=>'at',65=>'A',66=>'B',67=>'C',68=>'D',69=>'E',70=>'F',71=>'G',72=>'H',73=>'I',74=>'J',75=>'K',76=>'L',77=>'M',78=>'N',79=>'O',80=>'P',81=>'Q',82=>'R',83=>'S',84=>'T',85=>'U',86=>'V',87=>'W',88=>'X',89=>'Y',90=>'Z',91=>'bracketleft',92=>'backslash',93=>'bracketright',94=>'asciicircum',95=>'underscore',96=>'grave',97=>'a',98=>'b',99=>'c',100=>'d',101=>'e',102=>'f',103=>'g',104=>'h',105=>'i',106=>'j',107=>'k',108=>'l',109=>'m',110=>'n',111=>'o',112=>'p',113=>'q',114=>'r',115=>'s',116=>'t',117=>'u',118=>'v',119=>'w',120=>'x',121=>'y',122=>'z',123=>'braceleft',124=>'bar',125=>'braceright',126=>'asciitilde',127=>'.notdef',128=>'afii10051',129=>'afii10052',130=>'quotesinglbase',131=>'afii10100',132=>'quotedblbase',133=>'ellipsis',134=>'dagger',135=>'daggerdbl',136=>'Euro',137=>'perthousand',138=>'afii10058',139=>'guilsinglleft',140=>'afii10059',141=>'afii10061',142=>'afii10060',143=>'afii10145',144=>'afii10099',145=>'quoteleft',146=>'quoteright',147=>'quotedblleft',148=>'quotedblright',149=>'bullet',150=>'endash',151=>'emdash',152=>'.notdef',153=>'trademark',154=>'afii10106',155=>'guilsinglright',156=>'afii10107',157=>'afii10109',158=>'afii10108',159=>'afii10193',160=>'space',161=>'afii10062',162=>'afii10110',163=>'afii10057',164=>'currency',165=>'afii10050',166=>'brokenbar',167=>'section',168=>'afii10023',169=>'copyright',170=>'afii10053',171=>'guillemotleft',172=>'logicalnot',173=>'hyphen',174=>'registered',175=>'afii10056',176=>'degree',177=>'plusminus',178=>'afii10055',179=>'afii10103',180=>'afii10098',181=>'mu',182=>'paragraph',183=>'periodcentered',184=>'afii10071',185=>'afii61352',186=>'afii10101',187=>'guillemotright',188=>'afii10105',189=>'afii10054',190=>'afii10102',191=>'afii10104',192=>'afii10017',193=>'afii10018',194=>'afii10019',195=>'afii10020',196=>'afii10021',197=>'afii10022',198=>'afii10024',199=>'afii10025',200=>'afii10026',201=>'afii10027',202=>'afii10028',203=>'afii10029',204=>'afii10030',205=>'afii10031',206=>'afii10032',207=>'afii10033',208=>'afii10034',209=>'afii10035',210=>'afii10036',211=>'afii10037',212=>'afii10038',213=>'afii10039',214=>'afii10040',215=>'afii10041',216=>'afii10042',217=>'afii10043',218=>'afii10044',219=>'afii10045',220=>'afii10046',221=>'afii10047',222=>'afii10048',223=>'afii10049',224=>'afii10065',225=>'afii10066',226=>'afii10067',227=>'afii10068',228=>'afii10069',229=>'afii10070',230=>'afii10072',231=>'afii10073',232=>'afii10074',233=>'afii10075',234=>'afii10076',235=>'afii10077',236=>'afii10078',237=>'afii10079',238=>'afii10080',239=>'afii10081',240=>'afii10082',241=>'afii10083',242=>'afii10084',243=>'afii10085',244=>'afii10086',245=>'afii10087',246=>'afii10088',247=>'afii10089',248=>'afii10090',249=>'afii10091',250=>'afii10092',251=>'afii10093',252=>'afii10094',253=>'afii10095',254=>'afii10096',255=>'afii10097'),
18377
18378// encoding map for: cp1252
18379'cp1252' => array(0=>'.notdef',1=>'.notdef',2=>'.notdef',3=>'.notdef',4=>'.notdef',5=>'.notdef',6=>'.notdef',7=>'.notdef',8=>'.notdef',9=>'.notdef',10=>'.notdef',11=>'.notdef',12=>'.notdef',13=>'.notdef',14=>'.notdef',15=>'.notdef',16=>'.notdef',17=>'.notdef',18=>'.notdef',19=>'.notdef',20=>'.notdef',21=>'.notdef',22=>'.notdef',23=>'.notdef',24=>'.notdef',25=>'.notdef',26=>'.notdef',27=>'.notdef',28=>'.notdef',29=>'.notdef',30=>'.notdef',31=>'.notdef',32=>'space',33=>'exclam',34=>'quotedbl',35=>'numbersign',36=>'dollar',37=>'percent',38=>'ampersand',39=>'quotesingle',40=>'parenleft',41=>'parenright',42=>'asterisk',43=>'plus',44=>'comma',45=>'hyphen',46=>'period',47=>'slash',48=>'zero',49=>'one',50=>'two',51=>'three',52=>'four',53=>'five',54=>'six',55=>'seven',56=>'eight',57=>'nine',58=>'colon',59=>'semicolon',60=>'less',61=>'equal',62=>'greater',63=>'question',64=>'at',65=>'A',66=>'B',67=>'C',68=>'D',69=>'E',70=>'F',71=>'G',72=>'H',73=>'I',74=>'J',75=>'K',76=>'L',77=>'M',78=>'N',79=>'O',80=>'P',81=>'Q',82=>'R',83=>'S',84=>'T',85=>'U',86=>'V',87=>'W',88=>'X',89=>'Y',90=>'Z',91=>'bracketleft',92=>'backslash',93=>'bracketright',94=>'asciicircum',95=>'underscore',96=>'grave',97=>'a',98=>'b',99=>'c',100=>'d',101=>'e',102=>'f',103=>'g',104=>'h',105=>'i',106=>'j',107=>'k',108=>'l',109=>'m',110=>'n',111=>'o',112=>'p',113=>'q',114=>'r',115=>'s',116=>'t',117=>'u',118=>'v',119=>'w',120=>'x',121=>'y',122=>'z',123=>'braceleft',124=>'bar',125=>'braceright',126=>'asciitilde',127=>'.notdef',128=>'Euro',129=>'.notdef',130=>'quotesinglbase',131=>'florin',132=>'quotedblbase',133=>'ellipsis',134=>'dagger',135=>'daggerdbl',136=>'circumflex',137=>'perthousand',138=>'Scaron',139=>'guilsinglleft',140=>'OE',141=>'.notdef',142=>'Zcaron',143=>'.notdef',144=>'.notdef',145=>'quoteleft',146=>'quoteright',147=>'quotedblleft',148=>'quotedblright',149=>'bullet',150=>'endash',151=>'emdash',152=>'tilde',153=>'trademark',154=>'scaron',155=>'guilsinglright',156=>'oe',157=>'.notdef',158=>'zcaron',159=>'Ydieresis',160=>'space',161=>'exclamdown',162=>'cent',163=>'sterling',164=>'currency',165=>'yen',166=>'brokenbar',167=>'section',168=>'dieresis',169=>'copyright',170=>'ordfeminine',171=>'guillemotleft',172=>'logicalnot',173=>'hyphen',174=>'registered',175=>'macron',176=>'degree',177=>'plusminus',178=>'twosuperior',179=>'threesuperior',180=>'acute',181=>'mu',182=>'paragraph',183=>'periodcentered',184=>'cedilla',185=>'onesuperior',186=>'ordmasculine',187=>'guillemotright',188=>'onequarter',189=>'onehalf',190=>'threequarters',191=>'questiondown',192=>'Agrave',193=>'Aacute',194=>'Acircumflex',195=>'Atilde',196=>'Adieresis',197=>'Aring',198=>'AE',199=>'Ccedilla',200=>'Egrave',201=>'Eacute',202=>'Ecircumflex',203=>'Edieresis',204=>'Igrave',205=>'Iacute',206=>'Icircumflex',207=>'Idieresis',208=>'Eth',209=>'Ntilde',210=>'Ograve',211=>'Oacute',212=>'Ocircumflex',213=>'Otilde',214=>'Odieresis',215=>'multiply',216=>'Oslash',217=>'Ugrave',218=>'Uacute',219=>'Ucircumflex',220=>'Udieresis',221=>'Yacute',222=>'Thorn',223=>'germandbls',224=>'agrave',225=>'aacute',226=>'acircumflex',227=>'atilde',228=>'adieresis',229=>'aring',230=>'ae',231=>'ccedilla',232=>'egrave',233=>'eacute',234=>'ecircumflex',235=>'edieresis',236=>'igrave',237=>'iacute',238=>'icircumflex',239=>'idieresis',240=>'eth',241=>'ntilde',242=>'ograve',243=>'oacute',244=>'ocircumflex',245=>'otilde',246=>'odieresis',247=>'divide',248=>'oslash',249=>'ugrave',250=>'uacute',251=>'ucircumflex',252=>'udieresis',253=>'yacute',254=>'thorn',255=>'ydieresis'),
18380
18381// encoding map for: cp1253
18382'cp1253' => array(0=>'.notdef',1=>'.notdef',2=>'.notdef',3=>'.notdef',4=>'.notdef',5=>'.notdef',6=>'.notdef',7=>'.notdef',8=>'.notdef',9=>'.notdef',10=>'.notdef',11=>'.notdef',12=>'.notdef',13=>'.notdef',14=>'.notdef',15=>'.notdef',16=>'.notdef',17=>'.notdef',18=>'.notdef',19=>'.notdef',20=>'.notdef',21=>'.notdef',22=>'.notdef',23=>'.notdef',24=>'.notdef',25=>'.notdef',26=>'.notdef',27=>'.notdef',28=>'.notdef',29=>'.notdef',30=>'.notdef',31=>'.notdef',32=>'space',33=>'exclam',34=>'quotedbl',35=>'numbersign',36=>'dollar',37=>'percent',38=>'ampersand',39=>'quotesingle',40=>'parenleft',41=>'parenright',42=>'asterisk',43=>'plus',44=>'comma',45=>'hyphen',46=>'period',47=>'slash',48=>'zero',49=>'one',50=>'two',51=>'three',52=>'four',53=>'five',54=>'six',55=>'seven',56=>'eight',57=>'nine',58=>'colon',59=>'semicolon',60=>'less',61=>'equal',62=>'greater',63=>'question',64=>'at',65=>'A',66=>'B',67=>'C',68=>'D',69=>'E',70=>'F',71=>'G',72=>'H',73=>'I',74=>'J',75=>'K',76=>'L',77=>'M',78=>'N',79=>'O',80=>'P',81=>'Q',82=>'R',83=>'S',84=>'T',85=>'U',86=>'V',87=>'W',88=>'X',89=>'Y',90=>'Z',91=>'bracketleft',92=>'backslash',93=>'bracketright',94=>'asciicircum',95=>'underscore',96=>'grave',97=>'a',98=>'b',99=>'c',100=>'d',101=>'e',102=>'f',103=>'g',104=>'h',105=>'i',106=>'j',107=>'k',108=>'l',109=>'m',110=>'n',111=>'o',112=>'p',113=>'q',114=>'r',115=>'s',116=>'t',117=>'u',118=>'v',119=>'w',120=>'x',121=>'y',122=>'z',123=>'braceleft',124=>'bar',125=>'braceright',126=>'asciitilde',127=>'.notdef',128=>'Euro',129=>'.notdef',130=>'quotesinglbase',131=>'florin',132=>'quotedblbase',133=>'ellipsis',134=>'dagger',135=>'daggerdbl',136=>'.notdef',137=>'perthousand',138=>'.notdef',139=>'guilsinglleft',140=>'.notdef',141=>'.notdef',142=>'.notdef',143=>'.notdef',144=>'.notdef',145=>'quoteleft',146=>'quoteright',147=>'quotedblleft',148=>'quotedblright',149=>'bullet',150=>'endash',151=>'emdash',152=>'.notdef',153=>'trademark',154=>'.notdef',155=>'guilsinglright',156=>'.notdef',157=>'.notdef',158=>'.notdef',159=>'.notdef',160=>'space',161=>'dieresistonos',162=>'Alphatonos',163=>'sterling',164=>'currency',165=>'yen',166=>'brokenbar',167=>'section',168=>'dieresis',169=>'copyright',170=>'.notdef',171=>'guillemotleft',172=>'logicalnot',173=>'hyphen',174=>'registered',175=>'afii00208',176=>'degree',177=>'plusminus',178=>'twosuperior',179=>'threesuperior',180=>'tonos',181=>'mu',182=>'paragraph',183=>'periodcentered',184=>'Epsilontonos',185=>'Etatonos',186=>'Iotatonos',187=>'guillemotright',188=>'Omicrontonos',189=>'onehalf',190=>'Upsilontonos',191=>'Omegatonos',192=>'iotadieresistonos',193=>'Alpha',194=>'Beta',195=>'Gamma',196=>'Delta',197=>'Epsilon',198=>'Zeta',199=>'Eta',200=>'Theta',201=>'Iota',202=>'Kappa',203=>'Lambda',204=>'Mu',205=>'Nu',206=>'Xi',207=>'Omicron',208=>'Pi',209=>'Rho',210=>'.notdef',211=>'Sigma',212=>'Tau',213=>'Upsilon',214=>'Phi',215=>'Chi',216=>'Psi',217=>'Omega',218=>'Iotadieresis',219=>'Upsilondieresis',220=>'alphatonos',221=>'epsilontonos',222=>'etatonos',223=>'iotatonos',224=>'upsilondieresistonos',225=>'alpha',226=>'beta',227=>'gamma',228=>'delta',229=>'epsilon',230=>'zeta',231=>'eta',232=>'theta',233=>'iota',234=>'kappa',235=>'lambda',236=>'mu',237=>'nu',238=>'xi',239=>'omicron',240=>'pi',241=>'rho',242=>'sigma1',243=>'sigma',244=>'tau',245=>'upsilon',246=>'phi',247=>'chi',248=>'psi',249=>'omega',250=>'iotadieresis',251=>'upsilondieresis',252=>'omicrontonos',253=>'upsilontonos',254=>'omegatonos',255=>'.notdef'),
18383
18384// encoding map for: cp1254
18385'cp1254' => array(0=>'.notdef',1=>'.notdef',2=>'.notdef',3=>'.notdef',4=>'.notdef',5=>'.notdef',6=>'.notdef',7=>'.notdef',8=>'.notdef',9=>'.notdef',10=>'.notdef',11=>'.notdef',12=>'.notdef',13=>'.notdef',14=>'.notdef',15=>'.notdef',16=>'.notdef',17=>'.notdef',18=>'.notdef',19=>'.notdef',20=>'.notdef',21=>'.notdef',22=>'.notdef',23=>'.notdef',24=>'.notdef',25=>'.notdef',26=>'.notdef',27=>'.notdef',28=>'.notdef',29=>'.notdef',30=>'.notdef',31=>'.notdef',32=>'space',33=>'exclam',34=>'quotedbl',35=>'numbersign',36=>'dollar',37=>'percent',38=>'ampersand',39=>'quotesingle',40=>'parenleft',41=>'parenright',42=>'asterisk',43=>'plus',44=>'comma',45=>'hyphen',46=>'period',47=>'slash',48=>'zero',49=>'one',50=>'two',51=>'three',52=>'four',53=>'five',54=>'six',55=>'seven',56=>'eight',57=>'nine',58=>'colon',59=>'semicolon',60=>'less',61=>'equal',62=>'greater',63=>'question',64=>'at',65=>'A',66=>'B',67=>'C',68=>'D',69=>'E',70=>'F',71=>'G',72=>'H',73=>'I',74=>'J',75=>'K',76=>'L',77=>'M',78=>'N',79=>'O',80=>'P',81=>'Q',82=>'R',83=>'S',84=>'T',85=>'U',86=>'V',87=>'W',88=>'X',89=>'Y',90=>'Z',91=>'bracketleft',92=>'backslash',93=>'bracketright',94=>'asciicircum',95=>'underscore',96=>'grave',97=>'a',98=>'b',99=>'c',100=>'d',101=>'e',102=>'f',103=>'g',104=>'h',105=>'i',106=>'j',107=>'k',108=>'l',109=>'m',110=>'n',111=>'o',112=>'p',113=>'q',114=>'r',115=>'s',116=>'t',117=>'u',118=>'v',119=>'w',120=>'x',121=>'y',122=>'z',123=>'braceleft',124=>'bar',125=>'braceright',126=>'asciitilde',127=>'.notdef',128=>'Euro',129=>'.notdef',130=>'quotesinglbase',131=>'florin',132=>'quotedblbase',133=>'ellipsis',134=>'dagger',135=>'daggerdbl',136=>'circumflex',137=>'perthousand',138=>'Scaron',139=>'guilsinglleft',140=>'OE',141=>'.notdef',142=>'.notdef',143=>'.notdef',144=>'.notdef',145=>'quoteleft',146=>'quoteright',147=>'quotedblleft',148=>'quotedblright',149=>'bullet',150=>'endash',151=>'emdash',152=>'tilde',153=>'trademark',154=>'scaron',155=>'guilsinglright',156=>'oe',157=>'.notdef',158=>'.notdef',159=>'Ydieresis',160=>'space',161=>'exclamdown',162=>'cent',163=>'sterling',164=>'currency',165=>'yen',166=>'brokenbar',167=>'section',168=>'dieresis',169=>'copyright',170=>'ordfeminine',171=>'guillemotleft',172=>'logicalnot',173=>'hyphen',174=>'registered',175=>'macron',176=>'degree',177=>'plusminus',178=>'twosuperior',179=>'threesuperior',180=>'acute',181=>'mu',182=>'paragraph',183=>'periodcentered',184=>'cedilla',185=>'onesuperior',186=>'ordmasculine',187=>'guillemotright',188=>'onequarter',189=>'onehalf',190=>'threequarters',191=>'questiondown',192=>'Agrave',193=>'Aacute',194=>'Acircumflex',195=>'Atilde',196=>'Adieresis',197=>'Aring',198=>'AE',199=>'Ccedilla',200=>'Egrave',201=>'Eacute',202=>'Ecircumflex',203=>'Edieresis',204=>'Igrave',205=>'Iacute',206=>'Icircumflex',207=>'Idieresis',208=>'Gbreve',209=>'Ntilde',210=>'Ograve',211=>'Oacute',212=>'Ocircumflex',213=>'Otilde',214=>'Odieresis',215=>'multiply',216=>'Oslash',217=>'Ugrave',218=>'Uacute',219=>'Ucircumflex',220=>'Udieresis',221=>'Idotaccent',222=>'Scedilla',223=>'germandbls',224=>'agrave',225=>'aacute',226=>'acircumflex',227=>'atilde',228=>'adieresis',229=>'aring',230=>'ae',231=>'ccedilla',232=>'egrave',233=>'eacute',234=>'ecircumflex',235=>'edieresis',236=>'igrave',237=>'iacute',238=>'icircumflex',239=>'idieresis',240=>'gbreve',241=>'ntilde',242=>'ograve',243=>'oacute',244=>'ocircumflex',245=>'otilde',246=>'odieresis',247=>'divide',248=>'oslash',249=>'ugrave',250=>'uacute',251=>'ucircumflex',252=>'udieresis',253=>'dotlessi',254=>'scedilla',255=>'ydieresis'),
18386
18387// encoding map for: cp1255
18388'cp1255' => array(0=>'.notdef',1=>'.notdef',2=>'.notdef',3=>'.notdef',4=>'.notdef',5=>'.notdef',6=>'.notdef',7=>'.notdef',8=>'.notdef',9=>'.notdef',10=>'.notdef',11=>'.notdef',12=>'.notdef',13=>'.notdef',14=>'.notdef',15=>'.notdef',16=>'.notdef',17=>'.notdef',18=>'.notdef',19=>'.notdef',20=>'.notdef',21=>'.notdef',22=>'.notdef',23=>'.notdef',24=>'.notdef',25=>'.notdef',26=>'.notdef',27=>'.notdef',28=>'.notdef',29=>'.notdef',30=>'.notdef',31=>'.notdef',32=>'space',33=>'exclam',34=>'quotedbl',35=>'numbersign',36=>'dollar',37=>'percent',38=>'ampersand',39=>'quotesingle',40=>'parenleft',41=>'parenright',42=>'asterisk',43=>'plus',44=>'comma',45=>'hyphen',46=>'period',47=>'slash',48=>'zero',49=>'one',50=>'two',51=>'three',52=>'four',53=>'five',54=>'six',55=>'seven',56=>'eight',57=>'nine',58=>'colon',59=>'semicolon',60=>'less',61=>'equal',62=>'greater',63=>'question',64=>'at',65=>'A',66=>'B',67=>'C',68=>'D',69=>'E',70=>'F',71=>'G',72=>'H',73=>'I',74=>'J',75=>'K',76=>'L',77=>'M',78=>'N',79=>'O',80=>'P',81=>'Q',82=>'R',83=>'S',84=>'T',85=>'U',86=>'V',87=>'W',88=>'X',89=>'Y',90=>'Z',91=>'bracketleft',92=>'backslash',93=>'bracketright',94=>'asciicircum',95=>'underscore',96=>'grave',97=>'a',98=>'b',99=>'c',100=>'d',101=>'e',102=>'f',103=>'g',104=>'h',105=>'i',106=>'j',107=>'k',108=>'l',109=>'m',110=>'n',111=>'o',112=>'p',113=>'q',114=>'r',115=>'s',116=>'t',117=>'u',118=>'v',119=>'w',120=>'x',121=>'y',122=>'z',123=>'braceleft',124=>'bar',125=>'braceright',126=>'asciitilde',127=>'.notdef',128=>'Euro',129=>'.notdef',130=>'quotesinglbase',131=>'florin',132=>'quotedblbase',133=>'ellipsis',134=>'dagger',135=>'daggerdbl',136=>'circumflex',137=>'perthousand',138=>'.notdef',139=>'guilsinglleft',140=>'.notdef',141=>'.notdef',142=>'.notdef',143=>'.notdef',144=>'.notdef',145=>'quoteleft',146=>'quoteright',147=>'quotedblleft',148=>'quotedblright',149=>'bullet',150=>'endash',151=>'emdash',152=>'tilde',153=>'trademark',154=>'.notdef',155=>'guilsinglright',156=>'.notdef',157=>'.notdef',158=>'.notdef',159=>'.notdef',160=>'space',161=>'exclamdown',162=>'cent',163=>'sterling',164=>'afii57636',165=>'yen',166=>'brokenbar',167=>'section',168=>'dieresis',169=>'copyright',170=>'multiply',171=>'guillemotleft',172=>'logicalnot',173=>'sfthyphen',174=>'registered',175=>'macron',176=>'degree',177=>'plusminus',178=>'twosuperior',179=>'threesuperior',180=>'acute',181=>'mu',182=>'paragraph',183=>'middot',184=>'cedilla',185=>'onesuperior',186=>'divide',187=>'guillemotright',188=>'onequarter',189=>'onehalf',190=>'threequarters',191=>'questiondown',192=>'afii57799',193=>'afii57801',194=>'afii57800',195=>'afii57802',196=>'afii57793',197=>'afii57794',198=>'afii57795',199=>'afii57798',200=>'afii57797',201=>'afii57806',202=>'.notdef',203=>'afii57796',204=>'afii57807',205=>'afii57839',206=>'afii57645',207=>'afii57841',208=>'afii57842',209=>'afii57804',210=>'afii57803',211=>'afii57658',212=>'afii57716',213=>'afii57717',214=>'afii57718',215=>'gereshhebrew',216=>'gershayimhebrew',217=>'.notdef',218=>'.notdef',219=>'.notdef',220=>'.notdef',221=>'.notdef',222=>'.notdef',223=>'.notdef',224=>'afii57664',225=>'afii57665',226=>'afii57666',227=>'afii57667',228=>'afii57668',229=>'afii57669',230=>'afii57670',231=>'afii57671',232=>'afii57672',233=>'afii57673',234=>'afii57674',235=>'afii57675',236=>'afii57676',237=>'afii57677',238=>'afii57678',239=>'afii57679',240=>'afii57680',241=>'afii57681',242=>'afii57682',243=>'afii57683',244=>'afii57684',245=>'afii57685',246=>'afii57686',247=>'afii57687',248=>'afii57688',249=>'afii57689',250=>'afii57690',251=>'.notdef',252=>'.notdef',253=>'afii299',254=>'afii300',255=>'.notdef'),
18389
18390// encoding map for: cp1256
18391'cp1256' => array(0=>'.notdef',1=>'.notdef',2=>'.notdef',3=>'.notdef',4=>'.notdef',5=>'.notdef',6=>'.notdef',7=>'.notdef',8=>'.notdef',9=>'.notdef',10=>'.notdef',11=>'.notdef',12=>'.notdef',13=>'.notdef',14=>'.notdef',15=>'.notdef',16=>'.notdef',17=>'.notdef',18=>'.notdef',19=>'.notdef',20=>'.notdef',21=>'.notdef',22=>'.notdef',23=>'.notdef',24=>'.notdef',25=>'.notdef',26=>'.notdef',27=>'.notdef',28=>'.notdef',29=>'.notdef',30=>'.notdef',31=>'.notdef',32=>'space',33=>'exclam',34=>'quotedbl',35=>'numbersign',36=>'dollar',37=>'percent',38=>'ampersand',39=>'quotesingle',40=>'parenleft',41=>'parenright',42=>'asterisk',43=>'plus',44=>'comma',45=>'hyphen',46=>'period',47=>'slash',48=>'zero',49=>'one',50=>'two',51=>'three',52=>'four',53=>'five',54=>'six',55=>'seven',56=>'eight',57=>'nine',58=>'colon',59=>'semicolon',60=>'less',61=>'equal',62=>'greater',63=>'question',64=>'at',65=>'A',66=>'B',67=>'C',68=>'D',69=>'E',70=>'F',71=>'G',72=>'H',73=>'I',74=>'J',75=>'K',76=>'L',77=>'M',78=>'N',79=>'O',80=>'P',81=>'Q',82=>'R',83=>'S',84=>'T',85=>'U',86=>'V',87=>'W',88=>'X',89=>'Y',90=>'Z',91=>'bracketleft',92=>'backslash',93=>'bracketright',94=>'asciicircum',95=>'underscore',96=>'grave',97=>'a',98=>'b',99=>'c',100=>'d',101=>'e',102=>'f',103=>'g',104=>'h',105=>'i',106=>'j',107=>'k',108=>'l',109=>'m',110=>'n',111=>'o',112=>'p',113=>'q',114=>'r',115=>'s',116=>'t',117=>'u',118=>'v',119=>'w',120=>'x',121=>'y',122=>'z',123=>'braceleft',124=>'bar',125=>'braceright',126=>'asciitilde',127=>'.notdef',128=>'Euro',129=>'afii57506',130=>'quotesinglbase',131=>'florin',132=>'quotedblbase',133=>'ellipsis',134=>'dagger',135=>'daggerdbl',136=>'circumflex',137=>'perthousand',138=>'afii57511',139=>'guilsinglleft',140=>'OE',141=>'afii57507',142=>'afii57508',143=>'afii57512',144=>'afii57509',145=>'quoteleft',146=>'quoteright',147=>'quotedblleft',148=>'quotedblright',149=>'bullet',150=>'endash',151=>'emdash',152=>'.notdef',153=>'trademark',154=>'afii57513',155=>'guilsinglright',156=>'oe',157=>'afii61664',158=>'afii301',159=>'afii57514',160=>'space',161=>'afii57388',162=>'cent',163=>'sterling',164=>'currency',165=>'yen',166=>'brokenbar',167=>'section',168=>'dieresis',169=>'copyright',170=>'.notdef',171=>'guillemotleft',172=>'logicalnot',173=>'hyphen',174=>'registered',175=>'macron',176=>'degree',177=>'plusminus',178=>'twosuperior',179=>'threesuperior',180=>'acute',181=>'mu',182=>'paragraph',183=>'periodcentered',184=>'cedilla',185=>'onesuperior',186=>'afii57403',187=>'guillemotright',188=>'onequarter',189=>'onehalf',190=>'threequarters',191=>'afii57407',192=>'.notdef',193=>'afii57409',194=>'afii57410',195=>'afii57411',196=>'afii57412',197=>'afii57413',198=>'afii57414',199=>'afii57415',200=>'afii57416',201=>'afii57417',202=>'afii57418',203=>'afii57419',204=>'afii57420',205=>'afii57421',206=>'afii57422',207=>'afii57423',208=>'afii57424',209=>'afii57425',210=>'afii57426',211=>'afii57427',212=>'afii57428',213=>'afii57429',214=>'afii57430',215=>'multiply',216=>'afii57431',217=>'afii57432',218=>'afii57433',219=>'afii57434',220=>'afii57440',221=>'afii57441',222=>'afii57442',223=>'afii57443',224=>'agrave',225=>'afii57444',226=>'acircumflex',227=>'afii57445',228=>'afii57446',229=>'afii57470',230=>'afii57448',231=>'ccedilla',232=>'egrave',233=>'eacute',234=>'ecircumflex',235=>'edieresis',236=>'afii57449',237=>'afii57450',238=>'icircumflex',239=>'idieresis',240=>'afii57451',241=>'afii57452',242=>'afii57453',243=>'afii57454',244=>'ocircumflex',245=>'afii57455',246=>'afii57456',247=>'divide',248=>'afii57457',249=>'ugrave',250=>'afii57458',251=>'ucircumflex',252=>'udieresis',253=>'afii299',254=>'afii300',255=>'afii57519'),
18392
18393// encoding map for: cp1257
18394'cp1257' => array(0=>'.notdef',1=>'.notdef',2=>'.notdef',3=>'.notdef',4=>'.notdef',5=>'.notdef',6=>'.notdef',7=>'.notdef',8=>'.notdef',9=>'.notdef',10=>'.notdef',11=>'.notdef',12=>'.notdef',13=>'.notdef',14=>'.notdef',15=>'.notdef',16=>'.notdef',17=>'.notdef',18=>'.notdef',19=>'.notdef',20=>'.notdef',21=>'.notdef',22=>'.notdef',23=>'.notdef',24=>'.notdef',25=>'.notdef',26=>'.notdef',27=>'.notdef',28=>'.notdef',29=>'.notdef',30=>'.notdef',31=>'.notdef',32=>'space',33=>'exclam',34=>'quotedbl',35=>'numbersign',36=>'dollar',37=>'percent',38=>'ampersand',39=>'quotesingle',40=>'parenleft',41=>'parenright',42=>'asterisk',43=>'plus',44=>'comma',45=>'hyphen',46=>'period',47=>'slash',48=>'zero',49=>'one',50=>'two',51=>'three',52=>'four',53=>'five',54=>'six',55=>'seven',56=>'eight',57=>'nine',58=>'colon',59=>'semicolon',60=>'less',61=>'equal',62=>'greater',63=>'question',64=>'at',65=>'A',66=>'B',67=>'C',68=>'D',69=>'E',70=>'F',71=>'G',72=>'H',73=>'I',74=>'J',75=>'K',76=>'L',77=>'M',78=>'N',79=>'O',80=>'P',81=>'Q',82=>'R',83=>'S',84=>'T',85=>'U',86=>'V',87=>'W',88=>'X',89=>'Y',90=>'Z',91=>'bracketleft',92=>'backslash',93=>'bracketright',94=>'asciicircum',95=>'underscore',96=>'grave',97=>'a',98=>'b',99=>'c',100=>'d',101=>'e',102=>'f',103=>'g',104=>'h',105=>'i',106=>'j',107=>'k',108=>'l',109=>'m',110=>'n',111=>'o',112=>'p',113=>'q',114=>'r',115=>'s',116=>'t',117=>'u',118=>'v',119=>'w',120=>'x',121=>'y',122=>'z',123=>'braceleft',124=>'bar',125=>'braceright',126=>'asciitilde',127=>'.notdef',128=>'Euro',129=>'.notdef',130=>'quotesinglbase',131=>'.notdef',132=>'quotedblbase',133=>'ellipsis',134=>'dagger',135=>'daggerdbl',136=>'.notdef',137=>'perthousand',138=>'.notdef',139=>'guilsinglleft',140=>'.notdef',141=>'dieresis',142=>'caron',143=>'cedilla',144=>'.notdef',145=>'quoteleft',146=>'quoteright',147=>'quotedblleft',148=>'quotedblright',149=>'bullet',150=>'endash',151=>'emdash',152=>'.notdef',153=>'trademark',154=>'.notdef',155=>'guilsinglright',156=>'.notdef',157=>'macron',158=>'ogonek',159=>'.notdef',160=>'space',161=>'.notdef',162=>'cent',163=>'sterling',164=>'currency',165=>'.notdef',166=>'brokenbar',167=>'section',168=>'Oslash',169=>'copyright',170=>'Rcommaaccent',171=>'guillemotleft',172=>'logicalnot',173=>'hyphen',174=>'registered',175=>'AE',176=>'degree',177=>'plusminus',178=>'twosuperior',179=>'threesuperior',180=>'acute',181=>'mu',182=>'paragraph',183=>'periodcentered',184=>'oslash',185=>'onesuperior',186=>'rcommaaccent',187=>'guillemotright',188=>'onequarter',189=>'onehalf',190=>'threequarters',191=>'ae',192=>'Aogonek',193=>'Iogonek',194=>'Amacron',195=>'Cacute',196=>'Adieresis',197=>'Aring',198=>'Eogonek',199=>'Emacron',200=>'Ccaron',201=>'Eacute',202=>'Zacute',203=>'Edotaccent',204=>'Gcommaaccent',205=>'Kcommaaccent',206=>'Imacron',207=>'Lcommaaccent',208=>'Scaron',209=>'Nacute',210=>'Ncommaaccent',211=>'Oacute',212=>'Omacron',213=>'Otilde',214=>'Odieresis',215=>'multiply',216=>'Uogonek',217=>'Lslash',218=>'Sacute',219=>'Umacron',220=>'Udieresis',221=>'Zdotaccent',222=>'Zcaron',223=>'germandbls',224=>'aogonek',225=>'iogonek',226=>'amacron',227=>'cacute',228=>'adieresis',229=>'aring',230=>'eogonek',231=>'emacron',232=>'ccaron',233=>'eacute',234=>'zacute',235=>'edotaccent',236=>'gcommaaccent',237=>'kcommaaccent',238=>'imacron',239=>'lcommaaccent',240=>'scaron',241=>'nacute',242=>'ncommaaccent',243=>'oacute',244=>'omacron',245=>'otilde',246=>'odieresis',247=>'divide',248=>'uogonek',249=>'lslash',250=>'sacute',251=>'umacron',252=>'udieresis',253=>'zdotaccent',254=>'zcaron',255=>'dotaccent'),
18395
18396// encoding map for: cp1258
18397'cp1258' => array(0=>'.notdef',1=>'.notdef',2=>'.notdef',3=>'.notdef',4=>'.notdef',5=>'.notdef',6=>'.notdef',7=>'.notdef',8=>'.notdef',9=>'.notdef',10=>'.notdef',11=>'.notdef',12=>'.notdef',13=>'.notdef',14=>'.notdef',15=>'.notdef',16=>'.notdef',17=>'.notdef',18=>'.notdef',19=>'.notdef',20=>'.notdef',21=>'.notdef',22=>'.notdef',23=>'.notdef',24=>'.notdef',25=>'.notdef',26=>'.notdef',27=>'.notdef',28=>'.notdef',29=>'.notdef',30=>'.notdef',31=>'.notdef',32=>'space',33=>'exclam',34=>'quotedbl',35=>'numbersign',36=>'dollar',37=>'percent',38=>'ampersand',39=>'quotesingle',40=>'parenleft',41=>'parenright',42=>'asterisk',43=>'plus',44=>'comma',45=>'hyphen',46=>'period',47=>'slash',48=>'zero',49=>'one',50=>'two',51=>'three',52=>'four',53=>'five',54=>'six',55=>'seven',56=>'eight',57=>'nine',58=>'colon',59=>'semicolon',60=>'less',61=>'equal',62=>'greater',63=>'question',64=>'at',65=>'A',66=>'B',67=>'C',68=>'D',69=>'E',70=>'F',71=>'G',72=>'H',73=>'I',74=>'J',75=>'K',76=>'L',77=>'M',78=>'N',79=>'O',80=>'P',81=>'Q',82=>'R',83=>'S',84=>'T',85=>'U',86=>'V',87=>'W',88=>'X',89=>'Y',90=>'Z',91=>'bracketleft',92=>'backslash',93=>'bracketright',94=>'asciicircum',95=>'underscore',96=>'grave',97=>'a',98=>'b',99=>'c',100=>'d',101=>'e',102=>'f',103=>'g',104=>'h',105=>'i',106=>'j',107=>'k',108=>'l',109=>'m',110=>'n',111=>'o',112=>'p',113=>'q',114=>'r',115=>'s',116=>'t',117=>'u',118=>'v',119=>'w',120=>'x',121=>'y',122=>'z',123=>'braceleft',124=>'bar',125=>'braceright',126=>'asciitilde',127=>'.notdef',128=>'Euro',129=>'.notdef',130=>'quotesinglbase',131=>'florin',132=>'quotedblbase',133=>'ellipsis',134=>'dagger',135=>'daggerdbl',136=>'circumflex',137=>'perthousand',138=>'.notdef',139=>'guilsinglleft',140=>'OE',141=>'.notdef',142=>'.notdef',143=>'.notdef',144=>'.notdef',145=>'quoteleft',146=>'quoteright',147=>'quotedblleft',148=>'quotedblright',149=>'bullet',150=>'endash',151=>'emdash',152=>'tilde',153=>'trademark',154=>'.notdef',155=>'guilsinglright',156=>'oe',157=>'.notdef',158=>'.notdef',159=>'Ydieresis',160=>'space',161=>'exclamdown',162=>'cent',163=>'sterling',164=>'currency',165=>'yen',166=>'brokenbar',167=>'section',168=>'dieresis',169=>'copyright',170=>'ordfeminine',171=>'guillemotleft',172=>'logicalnot',173=>'hyphen',174=>'registered',175=>'macron',176=>'degree',177=>'plusminus',178=>'twosuperior',179=>'threesuperior',180=>'acute',181=>'mu',182=>'paragraph',183=>'periodcentered',184=>'cedilla',185=>'onesuperior',186=>'ordmasculine',187=>'guillemotright',188=>'onequarter',189=>'onehalf',190=>'threequarters',191=>'questiondown',192=>'Agrave',193=>'Aacute',194=>'Acircumflex',195=>'Abreve',196=>'Adieresis',197=>'Aring',198=>'AE',199=>'Ccedilla',200=>'Egrave',201=>'Eacute',202=>'Ecircumflex',203=>'Edieresis',204=>'gravecomb',205=>'Iacute',206=>'Icircumflex',207=>'Idieresis',208=>'Dcroat',209=>'Ntilde',210=>'hookabovecomb',211=>'Oacute',212=>'Ocircumflex',213=>'Ohorn',214=>'Odieresis',215=>'multiply',216=>'Oslash',217=>'Ugrave',218=>'Uacute',219=>'Ucircumflex',220=>'Udieresis',221=>'Uhorn',222=>'tildecomb',223=>'germandbls',224=>'agrave',225=>'aacute',226=>'acircumflex',227=>'abreve',228=>'adieresis',229=>'aring',230=>'ae',231=>'ccedilla',232=>'egrave',233=>'eacute',234=>'ecircumflex',235=>'edieresis',236=>'acutecomb',237=>'iacute',238=>'icircumflex',239=>'idieresis',240=>'dcroat',241=>'ntilde',242=>'dotbelowcomb',243=>'oacute',244=>'ocircumflex',245=>'ohorn',246=>'odieresis',247=>'divide',248=>'oslash',249=>'ugrave',250=>'uacute',251=>'ucircumflex',252=>'udieresis',253=>'uhorn',254=>'dong',255=>'ydieresis'),
18398
18399// encoding map for: iso-8859-1
18400'iso-8859-1' => array(0=>'.notdef',1=>'.notdef',2=>'.notdef',3=>'.notdef',4=>'.notdef',5=>'.notdef',6=>'.notdef',7=>'.notdef',8=>'.notdef',9=>'.notdef',10=>'.notdef',11=>'.notdef',12=>'.notdef',13=>'.notdef',14=>'.notdef',15=>'.notdef',16=>'.notdef',17=>'.notdef',18=>'.notdef',19=>'.notdef',20=>'.notdef',21=>'.notdef',22=>'.notdef',23=>'.notdef',24=>'.notdef',25=>'.notdef',26=>'.notdef',27=>'.notdef',28=>'.notdef',29=>'.notdef',30=>'.notdef',31=>'.notdef',32=>'space',33=>'exclam',34=>'quotedbl',35=>'numbersign',36=>'dollar',37=>'percent',38=>'ampersand',39=>'quotesingle',40=>'parenleft',41=>'parenright',42=>'asterisk',43=>'plus',44=>'comma',45=>'hyphen',46=>'period',47=>'slash',48=>'zero',49=>'one',50=>'two',51=>'three',52=>'four',53=>'five',54=>'six',55=>'seven',56=>'eight',57=>'nine',58=>'colon',59=>'semicolon',60=>'less',61=>'equal',62=>'greater',63=>'question',64=>'at',65=>'A',66=>'B',67=>'C',68=>'D',69=>'E',70=>'F',71=>'G',72=>'H',73=>'I',74=>'J',75=>'K',76=>'L',77=>'M',78=>'N',79=>'O',80=>'P',81=>'Q',82=>'R',83=>'S',84=>'T',85=>'U',86=>'V',87=>'W',88=>'X',89=>'Y',90=>'Z',91=>'bracketleft',92=>'backslash',93=>'bracketright',94=>'asciicircum',95=>'underscore',96=>'grave',97=>'a',98=>'b',99=>'c',100=>'d',101=>'e',102=>'f',103=>'g',104=>'h',105=>'i',106=>'j',107=>'k',108=>'l',109=>'m',110=>'n',111=>'o',112=>'p',113=>'q',114=>'r',115=>'s',116=>'t',117=>'u',118=>'v',119=>'w',120=>'x',121=>'y',122=>'z',123=>'braceleft',124=>'bar',125=>'braceright',126=>'asciitilde',127=>'.notdef',128=>'.notdef',129=>'.notdef',130=>'.notdef',131=>'.notdef',132=>'.notdef',133=>'.notdef',134=>'.notdef',135=>'.notdef',136=>'.notdef',137=>'.notdef',138=>'.notdef',139=>'.notdef',140=>'.notdef',141=>'.notdef',142=>'.notdef',143=>'.notdef',144=>'.notdef',145=>'.notdef',146=>'.notdef',147=>'.notdef',148=>'.notdef',149=>'.notdef',150=>'.notdef',151=>'.notdef',152=>'.notdef',153=>'.notdef',154=>'.notdef',155=>'.notdef',156=>'.notdef',157=>'.notdef',158=>'.notdef',159=>'.notdef',160=>'space',161=>'exclamdown',162=>'cent',163=>'sterling',164=>'currency',165=>'yen',166=>'brokenbar',167=>'section',168=>'dieresis',169=>'copyright',170=>'ordfeminine',171=>'guillemotleft',172=>'logicalnot',173=>'hyphen',174=>'registered',175=>'macron',176=>'degree',177=>'plusminus',178=>'twosuperior',179=>'threesuperior',180=>'acute',181=>'mu',182=>'paragraph',183=>'periodcentered',184=>'cedilla',185=>'onesuperior',186=>'ordmasculine',187=>'guillemotright',188=>'onequarter',189=>'onehalf',190=>'threequarters',191=>'questiondown',192=>'Agrave',193=>'Aacute',194=>'Acircumflex',195=>'Atilde',196=>'Adieresis',197=>'Aring',198=>'AE',199=>'Ccedilla',200=>'Egrave',201=>'Eacute',202=>'Ecircumflex',203=>'Edieresis',204=>'Igrave',205=>'Iacute',206=>'Icircumflex',207=>'Idieresis',208=>'Eth',209=>'Ntilde',210=>'Ograve',211=>'Oacute',212=>'Ocircumflex',213=>'Otilde',214=>'Odieresis',215=>'multiply',216=>'Oslash',217=>'Ugrave',218=>'Uacute',219=>'Ucircumflex',220=>'Udieresis',221=>'Yacute',222=>'Thorn',223=>'germandbls',224=>'agrave',225=>'aacute',226=>'acircumflex',227=>'atilde',228=>'adieresis',229=>'aring',230=>'ae',231=>'ccedilla',232=>'egrave',233=>'eacute',234=>'ecircumflex',235=>'edieresis',236=>'igrave',237=>'iacute',238=>'icircumflex',239=>'idieresis',240=>'eth',241=>'ntilde',242=>'ograve',243=>'oacute',244=>'ocircumflex',245=>'otilde',246=>'odieresis',247=>'divide',248=>'oslash',249=>'ugrave',250=>'uacute',251=>'ucircumflex',252=>'udieresis',253=>'yacute',254=>'thorn',255=>'ydieresis'),
18401
18402// encoding map for: iso-8859-2
18403'iso-8859-2' => array(0=>'.notdef',1=>'.notdef',2=>'.notdef',3=>'.notdef',4=>'.notdef',5=>'.notdef',6=>'.notdef',7=>'.notdef',8=>'.notdef',9=>'.notdef',10=>'.notdef',11=>'.notdef',12=>'.notdef',13=>'.notdef',14=>'.notdef',15=>'.notdef',16=>'.notdef',17=>'.notdef',18=>'.notdef',19=>'.notdef',20=>'.notdef',21=>'.notdef',22=>'.notdef',23=>'.notdef',24=>'.notdef',25=>'.notdef',26=>'.notdef',27=>'.notdef',28=>'.notdef',29=>'.notdef',30=>'.notdef',31=>'.notdef',32=>'space',33=>'exclam',34=>'quotedbl',35=>'numbersign',36=>'dollar',37=>'percent',38=>'ampersand',39=>'quotesingle',40=>'parenleft',41=>'parenright',42=>'asterisk',43=>'plus',44=>'comma',45=>'hyphen',46=>'period',47=>'slash',48=>'zero',49=>'one',50=>'two',51=>'three',52=>'four',53=>'five',54=>'six',55=>'seven',56=>'eight',57=>'nine',58=>'colon',59=>'semicolon',60=>'less',61=>'equal',62=>'greater',63=>'question',64=>'at',65=>'A',66=>'B',67=>'C',68=>'D',69=>'E',70=>'F',71=>'G',72=>'H',73=>'I',74=>'J',75=>'K',76=>'L',77=>'M',78=>'N',79=>'O',80=>'P',81=>'Q',82=>'R',83=>'S',84=>'T',85=>'U',86=>'V',87=>'W',88=>'X',89=>'Y',90=>'Z',91=>'bracketleft',92=>'backslash',93=>'bracketright',94=>'asciicircum',95=>'underscore',96=>'grave',97=>'a',98=>'b',99=>'c',100=>'d',101=>'e',102=>'f',103=>'g',104=>'h',105=>'i',106=>'j',107=>'k',108=>'l',109=>'m',110=>'n',111=>'o',112=>'p',113=>'q',114=>'r',115=>'s',116=>'t',117=>'u',118=>'v',119=>'w',120=>'x',121=>'y',122=>'z',123=>'braceleft',124=>'bar',125=>'braceright',126=>'asciitilde',127=>'.notdef',128=>'.notdef',129=>'.notdef',130=>'.notdef',131=>'.notdef',132=>'.notdef',133=>'.notdef',134=>'.notdef',135=>'.notdef',136=>'.notdef',137=>'.notdef',138=>'.notdef',139=>'.notdef',140=>'.notdef',141=>'.notdef',142=>'.notdef',143=>'.notdef',144=>'.notdef',145=>'.notdef',146=>'.notdef',147=>'.notdef',148=>'.notdef',149=>'.notdef',150=>'.notdef',151=>'.notdef',152=>'.notdef',153=>'.notdef',154=>'.notdef',155=>'.notdef',156=>'.notdef',157=>'.notdef',158=>'.notdef',159=>'.notdef',160=>'space',161=>'Aogonek',162=>'breve',163=>'Lslash',164=>'currency',165=>'Lcaron',166=>'Sacute',167=>'section',168=>'dieresis',169=>'Scaron',170=>'Scedilla',171=>'Tcaron',172=>'Zacute',173=>'hyphen',174=>'Zcaron',175=>'Zdotaccent',176=>'degree',177=>'aogonek',178=>'ogonek',179=>'lslash',180=>'acute',181=>'lcaron',182=>'sacute',183=>'caron',184=>'cedilla',185=>'scaron',186=>'scedilla',187=>'tcaron',188=>'zacute',189=>'hungarumlaut',190=>'zcaron',191=>'zdotaccent',192=>'Racute',193=>'Aacute',194=>'Acircumflex',195=>'Abreve',196=>'Adieresis',197=>'Lacute',198=>'Cacute',199=>'Ccedilla',200=>'Ccaron',201=>'Eacute',202=>'Eogonek',203=>'Edieresis',204=>'Ecaron',205=>'Iacute',206=>'Icircumflex',207=>'Dcaron',208=>'Dcroat',209=>'Nacute',210=>'Ncaron',211=>'Oacute',212=>'Ocircumflex',213=>'Ohungarumlaut',214=>'Odieresis',215=>'multiply',216=>'Rcaron',217=>'Uring',218=>'Uacute',219=>'Uhungarumlaut',220=>'Udieresis',221=>'Yacute',222=>'Tcommaaccent',223=>'germandbls',224=>'racute',225=>'aacute',226=>'acircumflex',227=>'abreve',228=>'adieresis',229=>'lacute',230=>'cacute',231=>'ccedilla',232=>'ccaron',233=>'eacute',234=>'eogonek',235=>'edieresis',236=>'ecaron',237=>'iacute',238=>'icircumflex',239=>'dcaron',240=>'dcroat',241=>'nacute',242=>'ncaron',243=>'oacute',244=>'ocircumflex',245=>'ohungarumlaut',246=>'odieresis',247=>'divide',248=>'rcaron',249=>'uring',250=>'uacute',251=>'uhungarumlaut',252=>'udieresis',253=>'yacute',254=>'tcommaaccent',255=>'dotaccent'),
18404
18405// encoding map for: iso-8859-4
18406'iso-8859-4' => array(0=>'.notdef',1=>'.notdef',2=>'.notdef',3=>'.notdef',4=>'.notdef',5=>'.notdef',6=>'.notdef',7=>'.notdef',8=>'.notdef',9=>'.notdef',10=>'.notdef',11=>'.notdef',12=>'.notdef',13=>'.notdef',14=>'.notdef',15=>'.notdef',16=>'.notdef',17=>'.notdef',18=>'.notdef',19=>'.notdef',20=>'.notdef',21=>'.notdef',22=>'.notdef',23=>'.notdef',24=>'.notdef',25=>'.notdef',26=>'.notdef',27=>'.notdef',28=>'.notdef',29=>'.notdef',30=>'.notdef',31=>'.notdef',32=>'space',33=>'exclam',34=>'quotedbl',35=>'numbersign',36=>'dollar',37=>'percent',38=>'ampersand',39=>'quotesingle',40=>'parenleft',41=>'parenright',42=>'asterisk',43=>'plus',44=>'comma',45=>'hyphen',46=>'period',47=>'slash',48=>'zero',49=>'one',50=>'two',51=>'three',52=>'four',53=>'five',54=>'six',55=>'seven',56=>'eight',57=>'nine',58=>'colon',59=>'semicolon',60=>'less',61=>'equal',62=>'greater',63=>'question',64=>'at',65=>'A',66=>'B',67=>'C',68=>'D',69=>'E',70=>'F',71=>'G',72=>'H',73=>'I',74=>'J',75=>'K',76=>'L',77=>'M',78=>'N',79=>'O',80=>'P',81=>'Q',82=>'R',83=>'S',84=>'T',85=>'U',86=>'V',87=>'W',88=>'X',89=>'Y',90=>'Z',91=>'bracketleft',92=>'backslash',93=>'bracketright',94=>'asciicircum',95=>'underscore',96=>'grave',97=>'a',98=>'b',99=>'c',100=>'d',101=>'e',102=>'f',103=>'g',104=>'h',105=>'i',106=>'j',107=>'k',108=>'l',109=>'m',110=>'n',111=>'o',112=>'p',113=>'q',114=>'r',115=>'s',116=>'t',117=>'u',118=>'v',119=>'w',120=>'x',121=>'y',122=>'z',123=>'braceleft',124=>'bar',125=>'braceright',126=>'asciitilde',127=>'.notdef',128=>'.notdef',129=>'.notdef',130=>'.notdef',131=>'.notdef',132=>'.notdef',133=>'.notdef',134=>'.notdef',135=>'.notdef',136=>'.notdef',137=>'.notdef',138=>'.notdef',139=>'.notdef',140=>'.notdef',141=>'.notdef',142=>'.notdef',143=>'.notdef',144=>'.notdef',145=>'.notdef',146=>'.notdef',147=>'.notdef',148=>'.notdef',149=>'.notdef',150=>'.notdef',151=>'.notdef',152=>'.notdef',153=>'.notdef',154=>'.notdef',155=>'.notdef',156=>'.notdef',157=>'.notdef',158=>'.notdef',159=>'.notdef',160=>'space',161=>'Aogonek',162=>'kgreenlandic',163=>'Rcommaaccent',164=>'currency',165=>'Itilde',166=>'Lcommaaccent',167=>'section',168=>'dieresis',169=>'Scaron',170=>'Emacron',171=>'Gcommaaccent',172=>'Tbar',173=>'hyphen',174=>'Zcaron',175=>'macron',176=>'degree',177=>'aogonek',178=>'ogonek',179=>'rcommaaccent',180=>'acute',181=>'itilde',182=>'lcommaaccent',183=>'caron',184=>'cedilla',185=>'scaron',186=>'emacron',187=>'gcommaaccent',188=>'tbar',189=>'Eng',190=>'zcaron',191=>'eng',192=>'Amacron',193=>'Aacute',194=>'Acircumflex',195=>'Atilde',196=>'Adieresis',197=>'Aring',198=>'AE',199=>'Iogonek',200=>'Ccaron',201=>'Eacute',202=>'Eogonek',203=>'Edieresis',204=>'Edotaccent',205=>'Iacute',206=>'Icircumflex',207=>'Imacron',208=>'Dcroat',209=>'Ncommaaccent',210=>'Omacron',211=>'Kcommaaccent',212=>'Ocircumflex',213=>'Otilde',214=>'Odieresis',215=>'multiply',216=>'Oslash',217=>'Uogonek',218=>'Uacute',219=>'Ucircumflex',220=>'Udieresis',221=>'Utilde',222=>'Umacron',223=>'germandbls',224=>'amacron',225=>'aacute',226=>'acircumflex',227=>'atilde',228=>'adieresis',229=>'aring',230=>'ae',231=>'iogonek',232=>'ccaron',233=>'eacute',234=>'eogonek',235=>'edieresis',236=>'edotaccent',237=>'iacute',238=>'icircumflex',239=>'imacron',240=>'dcroat',241=>'ncommaaccent',242=>'omacron',243=>'kcommaaccent',244=>'ocircumflex',245=>'otilde',246=>'odieresis',247=>'divide',248=>'oslash',249=>'uogonek',250=>'uacute',251=>'ucircumflex',252=>'udieresis',253=>'utilde',254=>'umacron',255=>'dotaccent'),
18407
18408// encoding map for: iso-8859-5
18409'iso-8859-5' => array(0=>'.notdef',1=>'.notdef',2=>'.notdef',3=>'.notdef',4=>'.notdef',5=>'.notdef',6=>'.notdef',7=>'.notdef',8=>'.notdef',9=>'.notdef',10=>'.notdef',11=>'.notdef',12=>'.notdef',13=>'.notdef',14=>'.notdef',15=>'.notdef',16=>'.notdef',17=>'.notdef',18=>'.notdef',19=>'.notdef',20=>'.notdef',21=>'.notdef',22=>'.notdef',23=>'.notdef',24=>'.notdef',25=>'.notdef',26=>'.notdef',27=>'.notdef',28=>'.notdef',29=>'.notdef',30=>'.notdef',31=>'.notdef',32=>'space',33=>'exclam',34=>'quotedbl',35=>'numbersign',36=>'dollar',37=>'percent',38=>'ampersand',39=>'quotesingle',40=>'parenleft',41=>'parenright',42=>'asterisk',43=>'plus',44=>'comma',45=>'hyphen',46=>'period',47=>'slash',48=>'zero',49=>'one',50=>'two',51=>'three',52=>'four',53=>'five',54=>'six',55=>'seven',56=>'eight',57=>'nine',58=>'colon',59=>'semicolon',60=>'less',61=>'equal',62=>'greater',63=>'question',64=>'at',65=>'A',66=>'B',67=>'C',68=>'D',69=>'E',70=>'F',71=>'G',72=>'H',73=>'I',74=>'J',75=>'K',76=>'L',77=>'M',78=>'N',79=>'O',80=>'P',81=>'Q',82=>'R',83=>'S',84=>'T',85=>'U',86=>'V',87=>'W',88=>'X',89=>'Y',90=>'Z',91=>'bracketleft',92=>'backslash',93=>'bracketright',94=>'asciicircum',95=>'underscore',96=>'grave',97=>'a',98=>'b',99=>'c',100=>'d',101=>'e',102=>'f',103=>'g',104=>'h',105=>'i',106=>'j',107=>'k',108=>'l',109=>'m',110=>'n',111=>'o',112=>'p',113=>'q',114=>'r',115=>'s',116=>'t',117=>'u',118=>'v',119=>'w',120=>'x',121=>'y',122=>'z',123=>'braceleft',124=>'bar',125=>'braceright',126=>'asciitilde',127=>'.notdef',128=>'.notdef',129=>'.notdef',130=>'.notdef',131=>'.notdef',132=>'.notdef',133=>'.notdef',134=>'.notdef',135=>'.notdef',136=>'.notdef',137=>'.notdef',138=>'.notdef',139=>'.notdef',140=>'.notdef',141=>'.notdef',142=>'.notdef',143=>'.notdef',144=>'.notdef',145=>'.notdef',146=>'.notdef',147=>'.notdef',148=>'.notdef',149=>'.notdef',150=>'.notdef',151=>'.notdef',152=>'.notdef',153=>'.notdef',154=>'.notdef',155=>'.notdef',156=>'.notdef',157=>'.notdef',158=>'.notdef',159=>'.notdef',160=>'space',161=>'afii10023',162=>'afii10051',163=>'afii10052',164=>'afii10053',165=>'afii10054',166=>'afii10055',167=>'afii10056',168=>'afii10057',169=>'afii10058',170=>'afii10059',171=>'afii10060',172=>'afii10061',173=>'hyphen',174=>'afii10062',175=>'afii10145',176=>'afii10017',177=>'afii10018',178=>'afii10019',179=>'afii10020',180=>'afii10021',181=>'afii10022',182=>'afii10024',183=>'afii10025',184=>'afii10026',185=>'afii10027',186=>'afii10028',187=>'afii10029',188=>'afii10030',189=>'afii10031',190=>'afii10032',191=>'afii10033',192=>'afii10034',193=>'afii10035',194=>'afii10036',195=>'afii10037',196=>'afii10038',197=>'afii10039',198=>'afii10040',199=>'afii10041',200=>'afii10042',201=>'afii10043',202=>'afii10044',203=>'afii10045',204=>'afii10046',205=>'afii10047',206=>'afii10048',207=>'afii10049',208=>'afii10065',209=>'afii10066',210=>'afii10067',211=>'afii10068',212=>'afii10069',213=>'afii10070',214=>'afii10072',215=>'afii10073',216=>'afii10074',217=>'afii10075',218=>'afii10076',219=>'afii10077',220=>'afii10078',221=>'afii10079',222=>'afii10080',223=>'afii10081',224=>'afii10082',225=>'afii10083',226=>'afii10084',227=>'afii10085',228=>'afii10086',229=>'afii10087',230=>'afii10088',231=>'afii10089',232=>'afii10090',233=>'afii10091',234=>'afii10092',235=>'afii10093',236=>'afii10094',237=>'afii10095',238=>'afii10096',239=>'afii10097',240=>'afii61352',241=>'afii10071',242=>'afii10099',243=>'afii10100',244=>'afii10101',245=>'afii10102',246=>'afii10103',247=>'afii10104',248=>'afii10105',249=>'afii10106',250=>'afii10107',251=>'afii10108',252=>'afii10109',253=>'section',254=>'afii10110',255=>'afii10193'),
18410
18411// encoding map for: iso-8859-7
18412'iso-8859-7' => array(0=>'.notdef',1=>'.notdef',2=>'.notdef',3=>'.notdef',4=>'.notdef',5=>'.notdef',6=>'.notdef',7=>'.notdef',8=>'.notdef',9=>'.notdef',10=>'.notdef',11=>'.notdef',12=>'.notdef',13=>'.notdef',14=>'.notdef',15=>'.notdef',16=>'.notdef',17=>'.notdef',18=>'.notdef',19=>'.notdef',20=>'.notdef',21=>'.notdef',22=>'.notdef',23=>'.notdef',24=>'.notdef',25=>'.notdef',26=>'.notdef',27=>'.notdef',28=>'.notdef',29=>'.notdef',30=>'.notdef',31=>'.notdef',32=>'space',33=>'exclam',34=>'quotedbl',35=>'numbersign',36=>'dollar',37=>'percent',38=>'ampersand',39=>'quotesingle',40=>'parenleft',41=>'parenright',42=>'asterisk',43=>'plus',44=>'comma',45=>'hyphen',46=>'period',47=>'slash',48=>'zero',49=>'one',50=>'two',51=>'three',52=>'four',53=>'five',54=>'six',55=>'seven',56=>'eight',57=>'nine',58=>'colon',59=>'semicolon',60=>'less',61=>'equal',62=>'greater',63=>'question',64=>'at',65=>'A',66=>'B',67=>'C',68=>'D',69=>'E',70=>'F',71=>'G',72=>'H',73=>'I',74=>'J',75=>'K',76=>'L',77=>'M',78=>'N',79=>'O',80=>'P',81=>'Q',82=>'R',83=>'S',84=>'T',85=>'U',86=>'V',87=>'W',88=>'X',89=>'Y',90=>'Z',91=>'bracketleft',92=>'backslash',93=>'bracketright',94=>'asciicircum',95=>'underscore',96=>'grave',97=>'a',98=>'b',99=>'c',100=>'d',101=>'e',102=>'f',103=>'g',104=>'h',105=>'i',106=>'j',107=>'k',108=>'l',109=>'m',110=>'n',111=>'o',112=>'p',113=>'q',114=>'r',115=>'s',116=>'t',117=>'u',118=>'v',119=>'w',120=>'x',121=>'y',122=>'z',123=>'braceleft',124=>'bar',125=>'braceright',126=>'asciitilde',127=>'.notdef',128=>'.notdef',129=>'.notdef',130=>'.notdef',131=>'.notdef',132=>'.notdef',133=>'.notdef',134=>'.notdef',135=>'.notdef',136=>'.notdef',137=>'.notdef',138=>'.notdef',139=>'.notdef',140=>'.notdef',141=>'.notdef',142=>'.notdef',143=>'.notdef',144=>'.notdef',145=>'.notdef',146=>'.notdef',147=>'.notdef',148=>'.notdef',149=>'.notdef',150=>'.notdef',151=>'.notdef',152=>'.notdef',153=>'.notdef',154=>'.notdef',155=>'.notdef',156=>'.notdef',157=>'.notdef',158=>'.notdef',159=>'.notdef',160=>'space',161=>'quoteleft',162=>'quoteright',163=>'sterling',164=>'.notdef',165=>'.notdef',166=>'brokenbar',167=>'section',168=>'dieresis',169=>'copyright',170=>'.notdef',171=>'guillemotleft',172=>'logicalnot',173=>'hyphen',174=>'.notdef',175=>'afii00208',176=>'degree',177=>'plusminus',178=>'twosuperior',179=>'threesuperior',180=>'tonos',181=>'dieresistonos',182=>'Alphatonos',183=>'periodcentered',184=>'Epsilontonos',185=>'Etatonos',186=>'Iotatonos',187=>'guillemotright',188=>'Omicrontonos',189=>'onehalf',190=>'Upsilontonos',191=>'Omegatonos',192=>'iotadieresistonos',193=>'Alpha',194=>'Beta',195=>'Gamma',196=>'Delta',197=>'Epsilon',198=>'Zeta',199=>'Eta',200=>'Theta',201=>'Iota',202=>'Kappa',203=>'Lambda',204=>'Mu',205=>'Nu',206=>'Xi',207=>'Omicron',208=>'Pi',209=>'Rho',210=>'.notdef',211=>'Sigma',212=>'Tau',213=>'Upsilon',214=>'Phi',215=>'Chi',216=>'Psi',217=>'Omega',218=>'Iotadieresis',219=>'Upsilondieresis',220=>'alphatonos',221=>'epsilontonos',222=>'etatonos',223=>'iotatonos',224=>'upsilondieresistonos',225=>'alpha',226=>'beta',227=>'gamma',228=>'delta',229=>'epsilon',230=>'zeta',231=>'eta',232=>'theta',233=>'iota',234=>'kappa',235=>'lambda',236=>'mu',237=>'nu',238=>'xi',239=>'omicron',240=>'pi',241=>'rho',242=>'sigma1',243=>'sigma',244=>'tau',245=>'upsilon',246=>'phi',247=>'chi',248=>'psi',249=>'omega',250=>'iotadieresis',251=>'upsilondieresis',252=>'omicrontonos',253=>'upsilontonos',254=>'omegatonos',255=>'.notdef'),
18413
18414// encoding map for: iso-8859-9
18415'iso-8859-9' => array(0=>'.notdef',1=>'.notdef',2=>'.notdef',3=>'.notdef',4=>'.notdef',5=>'.notdef',6=>'.notdef',7=>'.notdef',8=>'.notdef',9=>'.notdef',10=>'.notdef',11=>'.notdef',12=>'.notdef',13=>'.notdef',14=>'.notdef',15=>'.notdef',16=>'.notdef',17=>'.notdef',18=>'.notdef',19=>'.notdef',20=>'.notdef',21=>'.notdef',22=>'.notdef',23=>'.notdef',24=>'.notdef',25=>'.notdef',26=>'.notdef',27=>'.notdef',28=>'.notdef',29=>'.notdef',30=>'.notdef',31=>'.notdef',32=>'space',33=>'exclam',34=>'quotedbl',35=>'numbersign',36=>'dollar',37=>'percent',38=>'ampersand',39=>'quotesingle',40=>'parenleft',41=>'parenright',42=>'asterisk',43=>'plus',44=>'comma',45=>'hyphen',46=>'period',47=>'slash',48=>'zero',49=>'one',50=>'two',51=>'three',52=>'four',53=>'five',54=>'six',55=>'seven',56=>'eight',57=>'nine',58=>'colon',59=>'semicolon',60=>'less',61=>'equal',62=>'greater',63=>'question',64=>'at',65=>'A',66=>'B',67=>'C',68=>'D',69=>'E',70=>'F',71=>'G',72=>'H',73=>'I',74=>'J',75=>'K',76=>'L',77=>'M',78=>'N',79=>'O',80=>'P',81=>'Q',82=>'R',83=>'S',84=>'T',85=>'U',86=>'V',87=>'W',88=>'X',89=>'Y',90=>'Z',91=>'bracketleft',92=>'backslash',93=>'bracketright',94=>'asciicircum',95=>'underscore',96=>'grave',97=>'a',98=>'b',99=>'c',100=>'d',101=>'e',102=>'f',103=>'g',104=>'h',105=>'i',106=>'j',107=>'k',108=>'l',109=>'m',110=>'n',111=>'o',112=>'p',113=>'q',114=>'r',115=>'s',116=>'t',117=>'u',118=>'v',119=>'w',120=>'x',121=>'y',122=>'z',123=>'braceleft',124=>'bar',125=>'braceright',126=>'asciitilde',127=>'.notdef',128=>'.notdef',129=>'.notdef',130=>'.notdef',131=>'.notdef',132=>'.notdef',133=>'.notdef',134=>'.notdef',135=>'.notdef',136=>'.notdef',137=>'.notdef',138=>'.notdef',139=>'.notdef',140=>'.notdef',141=>'.notdef',142=>'.notdef',143=>'.notdef',144=>'.notdef',145=>'.notdef',146=>'.notdef',147=>'.notdef',148=>'.notdef',149=>'.notdef',150=>'.notdef',151=>'.notdef',152=>'.notdef',153=>'.notdef',154=>'.notdef',155=>'.notdef',156=>'.notdef',157=>'.notdef',158=>'.notdef',159=>'.notdef',160=>'space',161=>'exclamdown',162=>'cent',163=>'sterling',164=>'currency',165=>'yen',166=>'brokenbar',167=>'section',168=>'dieresis',169=>'copyright',170=>'ordfeminine',171=>'guillemotleft',172=>'logicalnot',173=>'hyphen',174=>'registered',175=>'macron',176=>'degree',177=>'plusminus',178=>'twosuperior',179=>'threesuperior',180=>'acute',181=>'mu',182=>'paragraph',183=>'periodcentered',184=>'cedilla',185=>'onesuperior',186=>'ordmasculine',187=>'guillemotright',188=>'onequarter',189=>'onehalf',190=>'threequarters',191=>'questiondown',192=>'Agrave',193=>'Aacute',194=>'Acircumflex',195=>'Atilde',196=>'Adieresis',197=>'Aring',198=>'AE',199=>'Ccedilla',200=>'Egrave',201=>'Eacute',202=>'Ecircumflex',203=>'Edieresis',204=>'Igrave',205=>'Iacute',206=>'Icircumflex',207=>'Idieresis',208=>'Gbreve',209=>'Ntilde',210=>'Ograve',211=>'Oacute',212=>'Ocircumflex',213=>'Otilde',214=>'Odieresis',215=>'multiply',216=>'Oslash',217=>'Ugrave',218=>'Uacute',219=>'Ucircumflex',220=>'Udieresis',221=>'Idotaccent',222=>'Scedilla',223=>'germandbls',224=>'agrave',225=>'aacute',226=>'acircumflex',227=>'atilde',228=>'adieresis',229=>'aring',230=>'ae',231=>'ccedilla',232=>'egrave',233=>'eacute',234=>'ecircumflex',235=>'edieresis',236=>'igrave',237=>'iacute',238=>'icircumflex',239=>'idieresis',240=>'gbreve',241=>'ntilde',242=>'ograve',243=>'oacute',244=>'ocircumflex',245=>'otilde',246=>'odieresis',247=>'divide',248=>'oslash',249=>'ugrave',250=>'uacute',251=>'ucircumflex',252=>'udieresis',253=>'dotlessi',254=>'scedilla',255=>'ydieresis'),
18416
18417// encoding map for: iso-8859-11
18418'iso-8859-11' => array(0=>'.notdef',1=>'.notdef',2=>'.notdef',3=>'.notdef',4=>'.notdef',5=>'.notdef',6=>'.notdef',7=>'.notdef',8=>'.notdef',9=>'.notdef',10=>'.notdef',11=>'.notdef',12=>'.notdef',13=>'.notdef',14=>'.notdef',15=>'.notdef',16=>'.notdef',17=>'.notdef',18=>'.notdef',19=>'.notdef',20=>'.notdef',21=>'.notdef',22=>'.notdef',23=>'.notdef',24=>'.notdef',25=>'.notdef',26=>'.notdef',27=>'.notdef',28=>'.notdef',29=>'.notdef',30=>'.notdef',31=>'.notdef',32=>'space',33=>'exclam',34=>'quotedbl',35=>'numbersign',36=>'dollar',37=>'percent',38=>'ampersand',39=>'quotesingle',40=>'parenleft',41=>'parenright',42=>'asterisk',43=>'plus',44=>'comma',45=>'hyphen',46=>'period',47=>'slash',48=>'zero',49=>'one',50=>'two',51=>'three',52=>'four',53=>'five',54=>'six',55=>'seven',56=>'eight',57=>'nine',58=>'colon',59=>'semicolon',60=>'less',61=>'equal',62=>'greater',63=>'question',64=>'at',65=>'A',66=>'B',67=>'C',68=>'D',69=>'E',70=>'F',71=>'G',72=>'H',73=>'I',74=>'J',75=>'K',76=>'L',77=>'M',78=>'N',79=>'O',80=>'P',81=>'Q',82=>'R',83=>'S',84=>'T',85=>'U',86=>'V',87=>'W',88=>'X',89=>'Y',90=>'Z',91=>'bracketleft',92=>'backslash',93=>'bracketright',94=>'asciicircum',95=>'underscore',96=>'grave',97=>'a',98=>'b',99=>'c',100=>'d',101=>'e',102=>'f',103=>'g',104=>'h',105=>'i',106=>'j',107=>'k',108=>'l',109=>'m',110=>'n',111=>'o',112=>'p',113=>'q',114=>'r',115=>'s',116=>'t',117=>'u',118=>'v',119=>'w',120=>'x',121=>'y',122=>'z',123=>'braceleft',124=>'bar',125=>'braceright',126=>'asciitilde',127=>'.notdef',128=>'.notdef',129=>'.notdef',130=>'.notdef',131=>'.notdef',132=>'.notdef',133=>'.notdef',134=>'.notdef',135=>'.notdef',136=>'.notdef',137=>'.notdef',138=>'.notdef',139=>'.notdef',140=>'.notdef',141=>'.notdef',142=>'.notdef',143=>'.notdef',144=>'.notdef',145=>'.notdef',146=>'.notdef',147=>'.notdef',148=>'.notdef',149=>'.notdef',150=>'.notdef',151=>'.notdef',152=>'.notdef',153=>'.notdef',154=>'.notdef',155=>'.notdef',156=>'.notdef',157=>'.notdef',158=>'.notdef',159=>'.notdef',160=>'space',161=>'kokaithai',162=>'khokhaithai',163=>'khokhuatthai',164=>'khokhwaithai',165=>'khokhonthai',166=>'khorakhangthai',167=>'ngonguthai',168=>'chochanthai',169=>'chochingthai',170=>'chochangthai',171=>'sosothai',172=>'chochoethai',173=>'yoyingthai',174=>'dochadathai',175=>'topatakthai',176=>'thothanthai',177=>'thonangmonthothai',178=>'thophuthaothai',179=>'nonenthai',180=>'dodekthai',181=>'totaothai',182=>'thothungthai',183=>'thothahanthai',184=>'thothongthai',185=>'nonuthai',186=>'bobaimaithai',187=>'poplathai',188=>'phophungthai',189=>'fofathai',190=>'phophanthai',191=>'fofanthai',192=>'phosamphaothai',193=>'momathai',194=>'yoyakthai',195=>'roruathai',196=>'ruthai',197=>'lolingthai',198=>'luthai',199=>'wowaenthai',200=>'sosalathai',201=>'sorusithai',202=>'sosuathai',203=>'hohipthai',204=>'lochulathai',205=>'oangthai',206=>'honokhukthai',207=>'paiyannoithai',208=>'saraathai',209=>'maihanakatthai',210=>'saraaathai',211=>'saraamthai',212=>'saraithai',213=>'saraiithai',214=>'sarauethai',215=>'saraueethai',216=>'sarauthai',217=>'sarauuthai',218=>'phinthuthai',219=>'.notdef',220=>'.notdef',221=>'.notdef',222=>'.notdef',223=>'bahtthai',224=>'saraethai',225=>'saraaethai',226=>'saraothai',227=>'saraaimaimuanthai',228=>'saraaimaimalaithai',229=>'lakkhangyaothai',230=>'maiyamokthai',231=>'maitaikhuthai',232=>'maiekthai',233=>'maithothai',234=>'maitrithai',235=>'maichattawathai',236=>'thanthakhatthai',237=>'nikhahitthai',238=>'yamakkanthai',239=>'fongmanthai',240=>'zerothai',241=>'onethai',242=>'twothai',243=>'threethai',244=>'fourthai',245=>'fivethai',246=>'sixthai',247=>'seventhai',248=>'eightthai',249=>'ninethai',250=>'angkhankhuthai',251=>'khomutthai',252=>'.notdef',253=>'.notdef',254=>'.notdef',255=>'.notdef'),
18419
18420// encoding map for: iso-8859-15
18421'iso-8859-15' => array(0=>'.notdef',1=>'.notdef',2=>'.notdef',3=>'.notdef',4=>'.notdef',5=>'.notdef',6=>'.notdef',7=>'.notdef',8=>'.notdef',9=>'.notdef',10=>'.notdef',11=>'.notdef',12=>'.notdef',13=>'.notdef',14=>'.notdef',15=>'.notdef',16=>'.notdef',17=>'.notdef',18=>'.notdef',19=>'.notdef',20=>'.notdef',21=>'.notdef',22=>'.notdef',23=>'.notdef',24=>'.notdef',25=>'.notdef',26=>'.notdef',27=>'.notdef',28=>'.notdef',29=>'.notdef',30=>'.notdef',31=>'.notdef',32=>'space',33=>'exclam',34=>'quotedbl',35=>'numbersign',36=>'dollar',37=>'percent',38=>'ampersand',39=>'quotesingle',40=>'parenleft',41=>'parenright',42=>'asterisk',43=>'plus',44=>'comma',45=>'hyphen',46=>'period',47=>'slash',48=>'zero',49=>'one',50=>'two',51=>'three',52=>'four',53=>'five',54=>'six',55=>'seven',56=>'eight',57=>'nine',58=>'colon',59=>'semicolon',60=>'less',61=>'equal',62=>'greater',63=>'question',64=>'at',65=>'A',66=>'B',67=>'C',68=>'D',69=>'E',70=>'F',71=>'G',72=>'H',73=>'I',74=>'J',75=>'K',76=>'L',77=>'M',78=>'N',79=>'O',80=>'P',81=>'Q',82=>'R',83=>'S',84=>'T',85=>'U',86=>'V',87=>'W',88=>'X',89=>'Y',90=>'Z',91=>'bracketleft',92=>'backslash',93=>'bracketright',94=>'asciicircum',95=>'underscore',96=>'grave',97=>'a',98=>'b',99=>'c',100=>'d',101=>'e',102=>'f',103=>'g',104=>'h',105=>'i',106=>'j',107=>'k',108=>'l',109=>'m',110=>'n',111=>'o',112=>'p',113=>'q',114=>'r',115=>'s',116=>'t',117=>'u',118=>'v',119=>'w',120=>'x',121=>'y',122=>'z',123=>'braceleft',124=>'bar',125=>'braceright',126=>'asciitilde',127=>'.notdef',128=>'.notdef',129=>'.notdef',130=>'.notdef',131=>'.notdef',132=>'.notdef',133=>'.notdef',134=>'.notdef',135=>'.notdef',136=>'.notdef',137=>'.notdef',138=>'.notdef',139=>'.notdef',140=>'.notdef',141=>'.notdef',142=>'.notdef',143=>'.notdef',144=>'.notdef',145=>'.notdef',146=>'.notdef',147=>'.notdef',148=>'.notdef',149=>'.notdef',150=>'.notdef',151=>'.notdef',152=>'.notdef',153=>'.notdef',154=>'.notdef',155=>'.notdef',156=>'.notdef',157=>'.notdef',158=>'.notdef',159=>'.notdef',160=>'space',161=>'exclamdown',162=>'cent',163=>'sterling',164=>'Euro',165=>'yen',166=>'Scaron',167=>'section',168=>'scaron',169=>'copyright',170=>'ordfeminine',171=>'guillemotleft',172=>'logicalnot',173=>'hyphen',174=>'registered',175=>'macron',176=>'degree',177=>'plusminus',178=>'twosuperior',179=>'threesuperior',180=>'Zcaron',181=>'mu',182=>'paragraph',183=>'periodcentered',184=>'zcaron',185=>'onesuperior',186=>'ordmasculine',187=>'guillemotright',188=>'OE',189=>'oe',190=>'Ydieresis',191=>'questiondown',192=>'Agrave',193=>'Aacute',194=>'Acircumflex',195=>'Atilde',196=>'Adieresis',197=>'Aring',198=>'AE',199=>'Ccedilla',200=>'Egrave',201=>'Eacute',202=>'Ecircumflex',203=>'Edieresis',204=>'Igrave',205=>'Iacute',206=>'Icircumflex',207=>'Idieresis',208=>'Eth',209=>'Ntilde',210=>'Ograve',211=>'Oacute',212=>'Ocircumflex',213=>'Otilde',214=>'Odieresis',215=>'multiply',216=>'Oslash',217=>'Ugrave',218=>'Uacute',219=>'Ucircumflex',220=>'Udieresis',221=>'Yacute',222=>'Thorn',223=>'germandbls',224=>'agrave',225=>'aacute',226=>'acircumflex',227=>'atilde',228=>'adieresis',229=>'aring',230=>'ae',231=>'ccedilla',232=>'egrave',233=>'eacute',234=>'ecircumflex',235=>'edieresis',236=>'igrave',237=>'iacute',238=>'icircumflex',239=>'idieresis',240=>'eth',241=>'ntilde',242=>'ograve',243=>'oacute',244=>'ocircumflex',245=>'otilde',246=>'odieresis',247=>'divide',248=>'oslash',249=>'ugrave',250=>'uacute',251=>'ucircumflex',252=>'udieresis',253=>'yacute',254=>'thorn',255=>'ydieresis'),
18422
18423// encoding map for: iso-8859-16
18424'iso-8859-16' => array(0=>'.notdef',1=>'.notdef',2=>'.notdef',3=>'.notdef',4=>'.notdef',5=>'.notdef',6=>'.notdef',7=>'.notdef',8=>'.notdef',9=>'.notdef',10=>'.notdef',11=>'.notdef',12=>'.notdef',13=>'.notdef',14=>'.notdef',15=>'.notdef',16=>'.notdef',17=>'.notdef',18=>'.notdef',19=>'.notdef',20=>'.notdef',21=>'.notdef',22=>'.notdef',23=>'.notdef',24=>'.notdef',25=>'.notdef',26=>'.notdef',27=>'.notdef',28=>'.notdef',29=>'.notdef',30=>'.notdef',31=>'.notdef',32=>'space',33=>'exclam',34=>'quotedbl',35=>'numbersign',36=>'dollar',37=>'percent',38=>'ampersand',39=>'quotesingle',40=>'parenleft',41=>'parenright',42=>'asterisk',43=>'plus',44=>'comma',45=>'hyphen',46=>'period',47=>'slash',48=>'zero',49=>'one',50=>'two',51=>'three',52=>'four',53=>'five',54=>'six',55=>'seven',56=>'eight',57=>'nine',58=>'colon',59=>'semicolon',60=>'less',61=>'equal',62=>'greater',63=>'question',64=>'at',65=>'A',66=>'B',67=>'C',68=>'D',69=>'E',70=>'F',71=>'G',72=>'H',73=>'I',74=>'J',75=>'K',76=>'L',77=>'M',78=>'N',79=>'O',80=>'P',81=>'Q',82=>'R',83=>'S',84=>'T',85=>'U',86=>'V',87=>'W',88=>'X',89=>'Y',90=>'Z',91=>'bracketleft',92=>'backslash',93=>'bracketright',94=>'asciicircum',95=>'underscore',96=>'grave',97=>'a',98=>'b',99=>'c',100=>'d',101=>'e',102=>'f',103=>'g',104=>'h',105=>'i',106=>'j',107=>'k',108=>'l',109=>'m',110=>'n',111=>'o',112=>'p',113=>'q',114=>'r',115=>'s',116=>'t',117=>'u',118=>'v',119=>'w',120=>'x',121=>'y',122=>'z',123=>'braceleft',124=>'bar',125=>'braceright',126=>'asciitilde',127=>'.notdef',128=>'.notdef',129=>'.notdef',130=>'.notdef',131=>'.notdef',132=>'.notdef',133=>'.notdef',134=>'.notdef',135=>'.notdef',136=>'.notdef',137=>'.notdef',138=>'.notdef',139=>'.notdef',140=>'.notdef',141=>'.notdef',142=>'.notdef',143=>'.notdef',144=>'.notdef',145=>'.notdef',146=>'.notdef',147=>'.notdef',148=>'.notdef',149=>'.notdef',150=>'.notdef',151=>'.notdef',152=>'.notdef',153=>'.notdef',154=>'.notdef',155=>'.notdef',156=>'.notdef',157=>'.notdef',158=>'.notdef',159=>'.notdef',160=>'space',161=>'Aogonek',162=>'aogonek',163=>'Lslash',164=>'Euro',165=>'quotedblbase',166=>'Scaron',167=>'section',168=>'scaron',169=>'copyright',170=>'Scommaaccent',171=>'guillemotleft',172=>'Zacute',173=>'hyphen',174=>'zacute',175=>'Zdotaccent',176=>'degree',177=>'plusminus',178=>'Ccaron',179=>'lslash',180=>'Zcaron',181=>'quotedblright',182=>'paragraph',183=>'periodcentered',184=>'zcaron',185=>'ccaron',186=>'scommaaccent',187=>'guillemotright',188=>'OE',189=>'oe',190=>'Ydieresis',191=>'zdotaccent',192=>'Agrave',193=>'Aacute',194=>'Acircumflex',195=>'Abreve',196=>'Adieresis',197=>'Cacute',198=>'AE',199=>'Ccedilla',200=>'Egrave',201=>'Eacute',202=>'Ecircumflex',203=>'Edieresis',204=>'Igrave',205=>'Iacute',206=>'Icircumflex',207=>'Idieresis',208=>'Dcroat',209=>'Nacute',210=>'Ograve',211=>'Oacute',212=>'Ocircumflex',213=>'Ohungarumlaut',214=>'Odieresis',215=>'Sacute',216=>'Uhungarumlaut',217=>'Ugrave',218=>'Uacute',219=>'Ucircumflex',220=>'Udieresis',221=>'Eogonek',222=>'Tcommaaccent',223=>'germandbls',224=>'agrave',225=>'aacute',226=>'acircumflex',227=>'abreve',228=>'adieresis',229=>'cacute',230=>'ae',231=>'ccedilla',232=>'egrave',233=>'eacute',234=>'ecircumflex',235=>'edieresis',236=>'igrave',237=>'iacute',238=>'icircumflex',239=>'idieresis',240=>'dcroat',241=>'nacute',242=>'ograve',243=>'oacute',244=>'ocircumflex',245=>'ohungarumlaut',246=>'odieresis',247=>'sacute',248=>'uhungarumlaut',249=>'ugrave',250=>'uacute',251=>'ucircumflex',252=>'udieresis',253=>'eogonek',254=>'tcommaaccent',255=>'ydieresis'),
18425
18426// encoding map for: koi8-r
18427'koi8-r' => array(0=>'.notdef',1=>'.notdef',2=>'.notdef',3=>'.notdef',4=>'.notdef',5=>'.notdef',6=>'.notdef',7=>'.notdef',8=>'.notdef',9=>'.notdef',10=>'.notdef',11=>'.notdef',12=>'.notdef',13=>'.notdef',14=>'.notdef',15=>'.notdef',16=>'.notdef',17=>'.notdef',18=>'.notdef',19=>'.notdef',20=>'.notdef',21=>'.notdef',22=>'.notdef',23=>'.notdef',24=>'.notdef',25=>'.notdef',26=>'.notdef',27=>'.notdef',28=>'.notdef',29=>'.notdef',30=>'.notdef',31=>'.notdef',32=>'space',33=>'exclam',34=>'quotedbl',35=>'numbersign',36=>'dollar',37=>'percent',38=>'ampersand',39=>'quotesingle',40=>'parenleft',41=>'parenright',42=>'asterisk',43=>'plus',44=>'comma',45=>'hyphen',46=>'period',47=>'slash',48=>'zero',49=>'one',50=>'two',51=>'three',52=>'four',53=>'five',54=>'six',55=>'seven',56=>'eight',57=>'nine',58=>'colon',59=>'semicolon',60=>'less',61=>'equal',62=>'greater',63=>'question',64=>'at',65=>'A',66=>'B',67=>'C',68=>'D',69=>'E',70=>'F',71=>'G',72=>'H',73=>'I',74=>'J',75=>'K',76=>'L',77=>'M',78=>'N',79=>'O',80=>'P',81=>'Q',82=>'R',83=>'S',84=>'T',85=>'U',86=>'V',87=>'W',88=>'X',89=>'Y',90=>'Z',91=>'bracketleft',92=>'backslash',93=>'bracketright',94=>'asciicircum',95=>'underscore',96=>'grave',97=>'a',98=>'b',99=>'c',100=>'d',101=>'e',102=>'f',103=>'g',104=>'h',105=>'i',106=>'j',107=>'k',108=>'l',109=>'m',110=>'n',111=>'o',112=>'p',113=>'q',114=>'r',115=>'s',116=>'t',117=>'u',118=>'v',119=>'w',120=>'x',121=>'y',122=>'z',123=>'braceleft',124=>'bar',125=>'braceright',126=>'asciitilde',127=>'.notdef',128=>'SF100000',129=>'SF110000',130=>'SF010000',131=>'SF030000',132=>'SF020000',133=>'SF040000',134=>'SF080000',135=>'SF090000',136=>'SF060000',137=>'SF070000',138=>'SF050000',139=>'upblock',140=>'dnblock',141=>'block',142=>'lfblock',143=>'rtblock',144=>'ltshade',145=>'shade',146=>'dkshade',147=>'integraltp',148=>'filledbox',149=>'periodcentered',150=>'radical',151=>'approxequal',152=>'lessequal',153=>'greaterequal',154=>'space',155=>'integralbt',156=>'degree',157=>'twosuperior',158=>'periodcentered',159=>'divide',160=>'SF430000',161=>'SF240000',162=>'SF510000',163=>'afii10071',164=>'SF520000',165=>'SF390000',166=>'SF220000',167=>'SF210000',168=>'SF250000',169=>'SF500000',170=>'SF490000',171=>'SF380000',172=>'SF280000',173=>'SF270000',174=>'SF260000',175=>'SF360000',176=>'SF370000',177=>'SF420000',178=>'SF190000',179=>'afii10023',180=>'SF200000',181=>'SF230000',182=>'SF470000',183=>'SF480000',184=>'SF410000',185=>'SF450000',186=>'SF460000',187=>'SF400000',188=>'SF540000',189=>'SF530000',190=>'SF440000',191=>'copyright',192=>'afii10096',193=>'afii10065',194=>'afii10066',195=>'afii10088',196=>'afii10069',197=>'afii10070',198=>'afii10086',199=>'afii10068',200=>'afii10087',201=>'afii10074',202=>'afii10075',203=>'afii10076',204=>'afii10077',205=>'afii10078',206=>'afii10079',207=>'afii10080',208=>'afii10081',209=>'afii10097',210=>'afii10082',211=>'afii10083',212=>'afii10084',213=>'afii10085',214=>'afii10072',215=>'afii10067',216=>'afii10094',217=>'afii10093',218=>'afii10073',219=>'afii10090',220=>'afii10095',221=>'afii10091',222=>'afii10089',223=>'afii10092',224=>'afii10048',225=>'afii10017',226=>'afii10018',227=>'afii10040',228=>'afii10021',229=>'afii10022',230=>'afii10038',231=>'afii10020',232=>'afii10039',233=>'afii10026',234=>'afii10027',235=>'afii10028',236=>'afii10029',237=>'afii10030',238=>'afii10031',239=>'afii10032',240=>'afii10033',241=>'afii10049',242=>'afii10034',243=>'afii10035',244=>'afii10036',245=>'afii10037',246=>'afii10024',247=>'afii10019',248=>'afii10046',249=>'afii10045',250=>'afii10025',251=>'afii10042',252=>'afii10047',253=>'afii10043',254=>'afii10041',255=>'afii10044'),
18428
18429// encoding map for: koi8-u
18430'koi8-u' => array(0=>'.notdef',1=>'.notdef',2=>'.notdef',3=>'.notdef',4=>'.notdef',5=>'.notdef',6=>'.notdef',7=>'.notdef',8=>'.notdef',9=>'.notdef',10=>'.notdef',11=>'.notdef',12=>'.notdef',13=>'.notdef',14=>'.notdef',15=>'.notdef',16=>'.notdef',17=>'.notdef',18=>'.notdef',19=>'.notdef',20=>'.notdef',21=>'.notdef',22=>'.notdef',23=>'.notdef',24=>'.notdef',25=>'.notdef',26=>'.notdef',27=>'.notdef',28=>'.notdef',29=>'.notdef',30=>'.notdef',31=>'.notdef',32=>'space',33=>'exclam',34=>'quotedbl',35=>'numbersign',36=>'dollar',37=>'percent',38=>'ampersand',39=>'quotesingle',40=>'parenleft',41=>'parenright',42=>'asterisk',43=>'plus',44=>'comma',45=>'hyphen',46=>'period',47=>'slash',48=>'zero',49=>'one',50=>'two',51=>'three',52=>'four',53=>'five',54=>'six',55=>'seven',56=>'eight',57=>'nine',58=>'colon',59=>'semicolon',60=>'less',61=>'equal',62=>'greater',63=>'question',64=>'at',65=>'A',66=>'B',67=>'C',68=>'D',69=>'E',70=>'F',71=>'G',72=>'H',73=>'I',74=>'J',75=>'K',76=>'L',77=>'M',78=>'N',79=>'O',80=>'P',81=>'Q',82=>'R',83=>'S',84=>'T',85=>'U',86=>'V',87=>'W',88=>'X',89=>'Y',90=>'Z',91=>'bracketleft',92=>'backslash',93=>'bracketright',94=>'asciicircum',95=>'underscore',96=>'grave',97=>'a',98=>'b',99=>'c',100=>'d',101=>'e',102=>'f',103=>'g',104=>'h',105=>'i',106=>'j',107=>'k',108=>'l',109=>'m',110=>'n',111=>'o',112=>'p',113=>'q',114=>'r',115=>'s',116=>'t',117=>'u',118=>'v',119=>'w',120=>'x',121=>'y',122=>'z',123=>'braceleft',124=>'bar',125=>'braceright',126=>'asciitilde',127=>'.notdef',128=>'SF100000',129=>'SF110000',130=>'SF010000',131=>'SF030000',132=>'SF020000',133=>'SF040000',134=>'SF080000',135=>'SF090000',136=>'SF060000',137=>'SF070000',138=>'SF050000',139=>'upblock',140=>'dnblock',141=>'block',142=>'lfblock',143=>'rtblock',144=>'ltshade',145=>'shade',146=>'dkshade',147=>'integraltp',148=>'filledbox',149=>'bullet',150=>'radical',151=>'approxequal',152=>'lessequal',153=>'greaterequal',154=>'space',155=>'integralbt',156=>'degree',157=>'twosuperior',158=>'periodcentered',159=>'divide',160=>'SF430000',161=>'SF240000',162=>'SF510000',163=>'afii10071',164=>'afii10101',165=>'SF390000',166=>'afii10103',167=>'afii10104',168=>'SF250000',169=>'SF500000',170=>'SF490000',171=>'SF380000',172=>'SF280000',173=>'afii10098',174=>'SF260000',175=>'SF360000',176=>'SF370000',177=>'SF420000',178=>'SF190000',179=>'afii10023',180=>'afii10053',181=>'SF230000',182=>'afii10055',183=>'afii10056',184=>'SF410000',185=>'SF450000',186=>'SF460000',187=>'SF400000',188=>'SF540000',189=>'afii10050',190=>'SF440000',191=>'copyright',192=>'afii10096',193=>'afii10065',194=>'afii10066',195=>'afii10088',196=>'afii10069',197=>'afii10070',198=>'afii10086',199=>'afii10068',200=>'afii10087',201=>'afii10074',202=>'afii10075',203=>'afii10076',204=>'afii10077',205=>'afii10078',206=>'afii10079',207=>'afii10080',208=>'afii10081',209=>'afii10097',210=>'afii10082',211=>'afii10083',212=>'afii10084',213=>'afii10085',214=>'afii10072',215=>'afii10067',216=>'afii10094',217=>'afii10093',218=>'afii10073',219=>'afii10090',220=>'afii10095',221=>'afii10091',222=>'afii10089',223=>'afii10092',224=>'afii10048',225=>'afii10017',226=>'afii10018',227=>'afii10040',228=>'afii10021',229=>'afii10022',230=>'afii10038',231=>'afii10020',232=>'afii10039',233=>'afii10026',234=>'afii10027',235=>'afii10028',236=>'afii10029',237=>'afii10030',238=>'afii10031',239=>'afii10032',240=>'afii10033',241=>'afii10049',242=>'afii10034',243=>'afii10035',244=>'afii10036',245=>'afii10037',246=>'afii10024',247=>'afii10019',248=>'afii10046',249=>'afii10045',250=>'afii10025',251=>'afii10042',252=>'afii10047',253=>'afii10043',254=>'afii10041',255=>'afii10044'),
18431
18432// encoding map for: symbol
18433'symbol' => array(0=>'.notdef',1=>'.notdef',2=>'.notdef',3=>'.notdef',4=>'.notdef',5=>'.notdef',6=>'.notdef',7=>'.notdef',8=>'.notdef',9=>'.notdef',10=>'.notdef',11=>'.notdef',12=>'.notdef',13=>'.notdef',14=>'.notdef',15=>'.notdef',16=>'.notdef',17=>'.notdef',18=>'.notdef',19=>'.notdef',20=>'.notdef',21=>'.notdef',22=>'.notdef',23=>'.notdef',24=>'.notdef',25=>'.notdef',26=>'.notdef',27=>'.notdef',28=>'.notdef',29=>'.notdef',30=>'.notdef',31=>'.notdef',32=>'space',33=>'exclam',34=>'universal',35=>'numbersign',36=>'existential',37=>'percent',38=>'ampersand',39=>'suchthat',40=>'parenleft',41=>'parenright',42=>'asteriskmath',43=>'plus',44=>'comma',45=>'minus',46=>'period',47=>'slash',48=>'zero',49=>'one',50=>'two',51=>'three',52=>'four',53=>'five',54=>'six',55=>'seven',56=>'eight',57=>'nine',58=>'colon',59=>'semicolon',60=>'less',61=>'equal',62=>'greater',63=>'question',64=>'congruent',65=>'Alpha',66=>'Beta',67=>'Chi',68=>'Delta',69=>'Epsilon',70=>'Phi',71=>'Gamma',72=>'Eta',73=>'Iota',74=>'theta1',75=>'Kappa',76=>'Lambda',77=>'Mu',78=>'Nu',79=>'Omicron',80=>'Pi',81=>'Theta',82=>'Rho',83=>'Sigma',84=>'Tau',85=>'Upsilon',86=>'sigma1',87=>'Omega',88=>'Xi',89=>'Psi',90=>'Zeta',91=>'bracketleft',92=>'therefore',93=>'bracketright',94=>'perpendicular',95=>'underscore',96=>'radicalex',97=>'alpha',98=>'beta',99=>'chi',100=>'delta',101=>'epsilon',102=>'phi',103=>'gamma',104=>'eta',105=>'iota',106=>'phi1',107=>'kappa',108=>'lambda',109=>'mu',110=>'nu',111=>'omicron',112=>'pi',113=>'theta',114=>'rho',115=>'sigma',116=>'tau',117=>'upsilon',118=>'omega1',119=>'omega',120=>'xi',121=>'psi',122=>'zeta',123=>'braceleft',124=>'bar',125=>'braceright',126=>'similar',127=>'.notdef',128=>'.notdef',129=>'.notdef',130=>'.notdef',131=>'.notdef',132=>'.notdef',133=>'.notdef',134=>'.notdef',135=>'.notdef',136=>'.notdef',137=>'.notdef',138=>'.notdef',139=>'.notdef',140=>'.notdef',141=>'.notdef',142=>'.notdef',143=>'.notdef',144=>'.notdef',145=>'.notdef',146=>'.notdef',147=>'.notdef',148=>'.notdef',149=>'.notdef',150=>'.notdef',151=>'.notdef',152=>'.notdef',153=>'.notdef',154=>'.notdef',155=>'.notdef',156=>'.notdef',157=>'.notdef',158=>'.notdef',159=>'.notdef',160=>'Euro',161=>'Upsilon1',162=>'minute',163=>'lessequal',164=>'fraction',165=>'infinity',166=>'florin',167=>'club',168=>'diamond',169=>'heart',170=>'spade',171=>'arrowboth',172=>'arrowleft',173=>'arrowup',174=>'arrowright',175=>'arrowdown',176=>'degree',177=>'plusminus',178=>'second',179=>'greaterequal',180=>'multiply',181=>'proportional',182=>'partialdiff',183=>'bullet',184=>'divide',185=>'notequal',186=>'equivalence',187=>'approxequal',188=>'ellipsis',189=>'arrowvertex',190=>'arrowhorizex',191=>'carriagereturn',192=>'aleph',193=>'Ifraktur',194=>'Rfraktur',195=>'weierstrass',196=>'circlemultiply',197=>'circleplus',198=>'emptyset',199=>'intersection',200=>'union',201=>'propersuperset',202=>'reflexsuperset',203=>'notsubset',204=>'propersubset',205=>'reflexsubset',206=>'element',207=>'notelement',208=>'angle',209=>'gradient',210=>'registerserif',211=>'copyrightserif',212=>'trademarkserif',213=>'product',214=>'radical',215=>'dotmath',216=>'logicalnot',217=>'logicaland',218=>'logicalor',219=>'arrowdblboth',220=>'arrowdblleft',221=>'arrowdblup',222=>'arrowdblright',223=>'arrowdbldown',224=>'lozenge',225=>'angleleft',226=>'registersans',227=>'copyrightsans',228=>'trademarksans',229=>'summation',230=>'parenlefttp',231=>'parenleftex',232=>'parenleftbt',233=>'bracketlefttp',234=>'bracketleftex',235=>'bracketleftbt',236=>'bracelefttp',237=>'braceleftmid',238=>'braceleftbt',239=>'braceex',240=>'.notdef',241=>'angleright',242=>'integral',243=>'integraltp',244=>'integralex',245=>'integralbt',246=>'parenrighttp',247=>'parenrightex',248=>'parenrightbt',249=>'bracketrighttp',250=>'bracketrightex',251=>'bracketrightbt',252=>'bracerighttp',253=>'bracerightmid',254=>'bracerightbt',255=>'.notdef',1226=>'registered',1227=>'copyright',1228=>'trademark')
18434
18435); // end of encoding maps
18436
18437/**
18438 * ToUnicode map for Identity-H stream
18439 * @public static
18440 */
18441public static $uni_identity_h = "/CIDInit /ProcSet findresource begin\n12 dict begin\nbegincmap\n/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def\n/CMapName /Adobe-Identity-UCS def\n/CMapType 2 def\n/WMode 0 def\n1 begincodespacerange\n<0000> <FFFF>\nendcodespacerange\n100 beginbfrange\n<0000> <00ff> <0000>\n<0100> <01ff> <0100>\n<0200> <02ff> <0200>\n<0300> <03ff> <0300>\n<0400> <04ff> <0400>\n<0500> <05ff> <0500>\n<0600> <06ff> <0600>\n<0700> <07ff> <0700>\n<0800> <08ff> <0800>\n<0900> <09ff> <0900>\n<0a00> <0aff> <0a00>\n<0b00> <0bff> <0b00>\n<0c00> <0cff> <0c00>\n<0d00> <0dff> <0d00>\n<0e00> <0eff> <0e00>\n<0f00> <0fff> <0f00>\n<1000> <10ff> <1000>\n<1100> <11ff> <1100>\n<1200> <12ff> <1200>\n<1300> <13ff> <1300>\n<1400> <14ff> <1400>\n<1500> <15ff> <1500>\n<1600> <16ff> <1600>\n<1700> <17ff> <1700>\n<1800> <18ff> <1800>\n<1900> <19ff> <1900>\n<1a00> <1aff> <1a00>\n<1b00> <1bff> <1b00>\n<1c00> <1cff> <1c00>\n<1d00> <1dff> <1d00>\n<1e00> <1eff> <1e00>\n<1f00> <1fff> <1f00>\n<2000> <20ff> <2000>\n<2100> <21ff> <2100>\n<2200> <22ff> <2200>\n<2300> <23ff> <2300>\n<2400> <24ff> <2400>\n<2500> <25ff> <2500>\n<2600> <26ff> <2600>\n<2700> <27ff> <2700>\n<2800> <28ff> <2800>\n<2900> <29ff> <2900>\n<2a00> <2aff> <2a00>\n<2b00> <2bff> <2b00>\n<2c00> <2cff> <2c00>\n<2d00> <2dff> <2d00>\n<2e00> <2eff> <2e00>\n<2f00> <2fff> <2f00>\n<3000> <30ff> <3000>\n<3100> <31ff> <3100>\n<3200> <32ff> <3200>\n<3300> <33ff> <3300>\n<3400> <34ff> <3400>\n<3500> <35ff> <3500>\n<3600> <36ff> <3600>\n<3700> <37ff> <3700>\n<3800> <38ff> <3800>\n<3900> <39ff> <3900>\n<3a00> <3aff> <3a00>\n<3b00> <3bff> <3b00>\n<3c00> <3cff> <3c00>\n<3d00> <3dff> <3d00>\n<3e00> <3eff> <3e00>\n<3f00> <3fff> <3f00>\n<4000> <40ff> <4000>\n<4100> <41ff> <4100>\n<4200> <42ff> <4200>\n<4300> <43ff> <4300>\n<4400> <44ff> <4400>\n<4500> <45ff> <4500>\n<4600> <46ff> <4600>\n<4700> <47ff> <4700>\n<4800> <48ff> <4800>\n<4900> <49ff> <4900>\n<4a00> <4aff> <4a00>\n<4b00> <4bff> <4b00>\n<4c00> <4cff> <4c00>\n<4d00> <4dff> <4d00>\n<4e00> <4eff> <4e00>\n<4f00> <4fff> <4f00>\n<5000> <50ff> <5000>\n<5100> <51ff> <5100>\n<5200> <52ff> <5200>\n<5300> <53ff> <5300>\n<5400> <54ff> <5400>\n<5500> <55ff> <5500>\n<5600> <56ff> <5600>\n<5700> <57ff> <5700>\n<5800> <58ff> <5800>\n<5900> <59ff> <5900>\n<5a00> <5aff> <5a00>\n<5b00> <5bff> <5b00>\n<5c00> <5cff> <5c00>\n<5d00> <5dff> <5d00>\n<5e00> <5eff> <5e00>\n<5f00> <5fff> <5f00>\n<6000> <60ff> <6000>\n<6100> <61ff> <6100>\n<6200> <62ff> <6200>\n<6300> <63ff> <6300>\nendbfrange\n100 beginbfrange\n<6400> <64ff> <6400>\n<6500> <65ff> <6500>\n<6600> <66ff> <6600>\n<6700> <67ff> <6700>\n<6800> <68ff> <6800>\n<6900> <69ff> <6900>\n<6a00> <6aff> <6a00>\n<6b00> <6bff> <6b00>\n<6c00> <6cff> <6c00>\n<6d00> <6dff> <6d00>\n<6e00> <6eff> <6e00>\n<6f00> <6fff> <6f00>\n<7000> <70ff> <7000>\n<7100> <71ff> <7100>\n<7200> <72ff> <7200>\n<7300> <73ff> <7300>\n<7400> <74ff> <7400>\n<7500> <75ff> <7500>\n<7600> <76ff> <7600>\n<7700> <77ff> <7700>\n<7800> <78ff> <7800>\n<7900> <79ff> <7900>\n<7a00> <7aff> <7a00>\n<7b00> <7bff> <7b00>\n<7c00> <7cff> <7c00>\n<7d00> <7dff> <7d00>\n<7e00> <7eff> <7e00>\n<7f00> <7fff> <7f00>\n<8000> <80ff> <8000>\n<8100> <81ff> <8100>\n<8200> <82ff> <8200>\n<8300> <83ff> <8300>\n<8400> <84ff> <8400>\n<8500> <85ff> <8500>\n<8600> <86ff> <8600>\n<8700> <87ff> <8700>\n<8800> <88ff> <8800>\n<8900> <89ff> <8900>\n<8a00> <8aff> <8a00>\n<8b00> <8bff> <8b00>\n<8c00> <8cff> <8c00>\n<8d00> <8dff> <8d00>\n<8e00> <8eff> <8e00>\n<8f00> <8fff> <8f00>\n<9000> <90ff> <9000>\n<9100> <91ff> <9100>\n<9200> <92ff> <9200>\n<9300> <93ff> <9300>\n<9400> <94ff> <9400>\n<9500> <95ff> <9500>\n<9600> <96ff> <9600>\n<9700> <97ff> <9700>\n<9800> <98ff> <9800>\n<9900> <99ff> <9900>\n<9a00> <9aff> <9a00>\n<9b00> <9bff> <9b00>\n<9c00> <9cff> <9c00>\n<9d00> <9dff> <9d00>\n<9e00> <9eff> <9e00>\n<9f00> <9fff> <9f00>\n<a000> <a0ff> <a000>\n<a100> <a1ff> <a100>\n<a200> <a2ff> <a200>\n<a300> <a3ff> <a300>\n<a400> <a4ff> <a400>\n<a500> <a5ff> <a500>\n<a600> <a6ff> <a600>\n<a700> <a7ff> <a700>\n<a800> <a8ff> <a800>\n<a900> <a9ff> <a900>\n<aa00> <aaff> <aa00>\n<ab00> <abff> <ab00>\n<ac00> <acff> <ac00>\n<ad00> <adff> <ad00>\n<ae00> <aeff> <ae00>\n<af00> <afff> <af00>\n<b000> <b0ff> <b000>\n<b100> <b1ff> <b100>\n<b200> <b2ff> <b200>\n<b300> <b3ff> <b300>\n<b400> <b4ff> <b400>\n<b500> <b5ff> <b500>\n<b600> <b6ff> <b600>\n<b700> <b7ff> <b700>\n<b800> <b8ff> <b800>\n<b900> <b9ff> <b900>\n<ba00> <baff> <ba00>\n<bb00> <bbff> <bb00>\n<bc00> <bcff> <bc00>\n<bd00> <bdff> <bd00>\n<be00> <beff> <be00>\n<bf00> <bfff> <bf00>\n<c000> <c0ff> <c000>\n<c100> <c1ff> <c100>\n<c200> <c2ff> <c200>\n<c300> <c3ff> <c300>\n<c400> <c4ff> <c400>\n<c500> <c5ff> <c500>\n<c600> <c6ff> <c600>\n<c700> <c7ff> <c700>\nendbfrange\n56 beginbfrange\n<c800> <c8ff> <c800>\n<c900> <c9ff> <c900>\n<ca00> <caff> <ca00>\n<cb00> <cbff> <cb00>\n<cc00> <ccff> <cc00>\n<cd00> <cdff> <cd00>\n<ce00> <ceff> <ce00>\n<cf00> <cfff> <cf00>\n<d000> <d0ff> <d000>\n<d100> <d1ff> <d100>\n<d200> <d2ff> <d200>\n<d300> <d3ff> <d300>\n<d400> <d4ff> <d400>\n<d500> <d5ff> <d500>\n<d600> <d6ff> <d600>\n<d700> <d7ff> <d700>\n<d800> <d8ff> <d800>\n<d900> <d9ff> <d900>\n<da00> <daff> <da00>\n<db00> <dbff> <db00>\n<dc00> <dcff> <dc00>\n<dd00> <ddff> <dd00>\n<de00> <deff> <de00>\n<df00> <dfff> <df00>\n<e000> <e0ff> <e000>\n<e100> <e1ff> <e100>\n<e200> <e2ff> <e200>\n<e300> <e3ff> <e300>\n<e400> <e4ff> <e400>\n<e500> <e5ff> <e500>\n<e600> <e6ff> <e600>\n<e700> <e7ff> <e700>\n<e800> <e8ff> <e800>\n<e900> <e9ff> <e900>\n<ea00> <eaff> <ea00>\n<eb00> <ebff> <eb00>\n<ec00> <ecff> <ec00>\n<ed00> <edff> <ed00>\n<ee00> <eeff> <ee00>\n<ef00> <efff> <ef00>\n<f000> <f0ff> <f000>\n<f100> <f1ff> <f100>\n<f200> <f2ff> <f200>\n<f300> <f3ff> <f300>\n<f400> <f4ff> <f400>\n<f500> <f5ff> <f500>\n<f600> <f6ff> <f600>\n<f700> <f7ff> <f700>\n<f800> <f8ff> <f800>\n<f900> <f9ff> <f900>\n<fa00> <faff> <fa00>\n<fb00> <fbff> <fb00>\n<fc00> <fcff> <fc00>\n<fd00> <fdff> <fd00>\n<fe00> <feff> <fe00>\n<ff00> <ffff> <ff00>\nendbfrange\nendcmap\nCMapName currentdict /CMap defineresource pop\nend\nend";
18442
18443} // END OF TCPDF_FONT_DATA CLASS
18444
18445//============================================================+
18446// END OF FILE
18447//============================================================+
diff --git a/inc/3rdparty/libraries/tcpdf/include/tcpdf_fonts.php b/inc/3rdparty/libraries/tcpdf/include/tcpdf_fonts.php
new file mode 100644
index 00000000..a7f0486a
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/include/tcpdf_fonts.php
@@ -0,0 +1,2583 @@
1<?php
2//============================================================+
3// File name : tcpdf_fonts.php
4// Version : 1.0.013
5// Begin : 2008-01-01
6// Last Update : 2014-05-23
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) 2008-2014 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 GNU Lesser General Public License
25// along with TCPDF. If not, see <http://www.gnu.org/licenses/>.
26//
27// See LICENSE.TXT file for more information.
28// -------------------------------------------------------------------
29//
30// Description :Font methods for TCPDF library.
31//
32//============================================================+
33
34/**
35 * @file
36 * Unicode data and font methods for TCPDF library.
37 * @author Nicola Asuni
38 * @package com.tecnick.tcpdf
39 */
40
41/**
42 * @class TCPDF_FONTS
43 * Font methods for TCPDF library.
44 * @package com.tecnick.tcpdf
45 * @version 1.0.013
46 * @author Nicola Asuni - info@tecnick.com
47 */
48class TCPDF_FONTS {
49
50 /**
51 * Static cache used for speed up uniord performances
52 * @protected
53 */
54 protected static $cache_uniord = array();
55
56 /**
57 * Convert and add the selected TrueType or Type1 font to the fonts folder (that must be writeable).
58 * @param $fontfile (string) Font file (full path).
59 * @param $fonttype (string) Font type. Leave empty for autodetect mode. Valid values are: TrueTypeUnicode, TrueType, Type1, CID0JP = CID-0 Japanese, CID0KR = CID-0 Korean, CID0CS = CID-0 Chinese Simplified, CID0CT = CID-0 Chinese Traditional.
60 * @param $enc (string) Name of the encoding table to use. Leave empty for default mode. Omit this parameter for TrueType Unicode and symbolic fonts like Symbol or ZapfDingBats.
61 * @param $flags (int) Unsigned 32-bit integer containing flags specifying various characteristics of the font (PDF32000:2008 - 9.8.2 Font Descriptor Flags): +1 for fixed font; +4 for symbol or +32 for non-symbol; +64 for italic. Fixed and Italic mode are generally autodetected so you have to set it to 32 = non-symbolic font (default) or 4 = symbolic font.
62 * @param $outpath (string) Output path for generated font files (must be writeable by the web server). Leave empty for default font folder.
63 * @param $platid (int) Platform ID for CMAP table to extract (when building a Unicode font for Windows this value should be 3, for Macintosh should be 1).
64 * @param $encid (int) Encoding ID for CMAP table to extract (when building a Unicode font for Windows this value should be 1, for Macintosh should be 0). When Platform ID is 3, legal values for Encoding ID are: 0=Symbol, 1=Unicode, 2=ShiftJIS, 3=PRC, 4=Big5, 5=Wansung, 6=Johab, 7=Reserved, 8=Reserved, 9=Reserved, 10=UCS-4.
65 * @param $addcbbox (boolean) If true includes the character bounding box information on the php font file.
66 * @param $link (boolean) If true link to system font instead of copying the font data (not transportable) - Note: do not work with Type1 fonts.
67 * @return (string) TCPDF font name or boolean false in case of error.
68 * @author Nicola Asuni
69 * @since 5.9.123 (2010-09-30)
70 * @public static
71 */
72 public static function addTTFfont($fontfile, $fonttype='', $enc='', $flags=32, $outpath='', $platid=3, $encid=1, $addcbbox=false, $link=false) {
73 if (!file_exists($fontfile)) {
74 // Could not find file
75 return false;
76 }
77 // font metrics
78 $fmetric = array();
79 // build new font name for TCPDF compatibility
80 $font_path_parts = pathinfo($fontfile);
81 if (!isset($font_path_parts['filename'])) {
82 $font_path_parts['filename'] = substr($font_path_parts['basename'], 0, -(strlen($font_path_parts['extension']) + 1));
83 }
84 $font_name = strtolower($font_path_parts['filename']);
85 $font_name = preg_replace('/[^a-z0-9_]/', '', $font_name);
86 $search = array('bold', 'oblique', 'italic', 'regular');
87 $replace = array('b', 'i', 'i', '');
88 $font_name = str_replace($search, $replace, $font_name);
89 if (empty($font_name)) {
90 // set generic name
91 $font_name = 'tcpdffont';
92 }
93 // set output path
94 if (empty($outpath)) {
95 $outpath = self::_getfontpath();
96 }
97 // check if this font already exist
98 if (@file_exists($outpath.$font_name.'.php')) {
99 // this font already exist (delete it from fonts folder to rebuild it)
100 return $font_name;
101 }
102 $fmetric['file'] = $font_name;
103 $fmetric['ctg'] = $font_name.'.ctg.z';
104 // get font data
105 $font = file_get_contents($fontfile);
106 $fmetric['originalsize'] = strlen($font);
107 // autodetect font type
108 if (empty($fonttype)) {
109 if (TCPDF_STATIC::_getULONG($font, 0) == 0x10000) {
110 // True Type (Unicode or not)
111 $fonttype = 'TrueTypeUnicode';
112 } elseif (substr($font, 0, 4) == 'OTTO') {
113 // Open Type (Unicode or not)
114 //Unsupported font format: OpenType with CFF data
115 return false;
116 } else {
117 // Type 1
118 $fonttype = 'Type1';
119 }
120 }
121 // set font type
122 switch ($fonttype) {
123 case 'CID0CT':
124 case 'CID0CS':
125 case 'CID0KR':
126 case 'CID0JP': {
127 $fmetric['type'] = 'cidfont0';
128 break;
129 }
130 case 'Type1': {
131 $fmetric['type'] = 'Type1';
132 if (empty($enc) AND (($flags & 4) == 0)) {
133 $enc = 'cp1252';
134 }
135 break;
136 }
137 case 'TrueType': {
138 $fmetric['type'] = 'TrueType';
139 break;
140 }
141 case 'TrueTypeUnicode':
142 default: {
143 $fmetric['type'] = 'TrueTypeUnicode';
144 break;
145 }
146 }
147 // set encoding maps (if any)
148 $fmetric['enc'] = preg_replace('/[^A-Za-z0-9_\-]/', '', $enc);
149 $fmetric['diff'] = '';
150 if (($fmetric['type'] == 'TrueType') OR ($fmetric['type'] == 'Type1')) {
151 if (!empty($enc) AND ($enc != 'cp1252') AND isset(TCPDF_FONT_DATA::$encmap[$enc])) {
152 // build differences from reference encoding
153 $enc_ref = TCPDF_FONT_DATA::$encmap['cp1252'];
154 $enc_target = TCPDF_FONT_DATA::$encmap[$enc];
155 $last = 0;
156 for ($i = 32; $i <= 255; ++$i) {
157 if ($enc_target != $enc_ref[$i]) {
158 if ($i != ($last + 1)) {
159 $fmetric['diff'] .= $i.' ';
160 }
161 $last = $i;
162 $fmetric['diff'] .= '/'.$enc_target[$i].' ';
163 }
164 }
165 }
166 }
167 // parse the font by type
168 if ($fmetric['type'] == 'Type1') {
169 // ---------- TYPE 1 ----------
170 // read first segment
171 $a = unpack('Cmarker/Ctype/Vsize', substr($font, 0, 6));
172 if ($a['marker'] != 128) {
173 // Font file is not a valid binary Type1
174 return false;
175 }
176 $fmetric['size1'] = $a['size'];
177 $data = substr($font, 6, $fmetric['size1']);
178 // read second segment
179 $a = unpack('Cmarker/Ctype/Vsize', substr($font, (6 + $fmetric['size1']), 6));
180 if ($a['marker'] != 128) {
181 // Font file is not a valid binary Type1
182 return false;
183 }
184 $fmetric['size2'] = $a['size'];
185 $encrypted = substr($font, (12 + $fmetric['size1']), $fmetric['size2']);
186 $data .= $encrypted;
187 // store compressed font
188 $fmetric['file'] .= '.z';
189 $fp = fopen($outpath.$fmetric['file'], 'wb');
190 fwrite($fp, gzcompress($data));
191 fclose($fp);
192 // get font info
193 $fmetric['Flags'] = $flags;
194 preg_match ('#/FullName[\s]*\(([^\)]*)#', $font, $matches);
195 $fmetric['name'] = preg_replace('/[^a-zA-Z0-9_\-]/', '', $matches[1]);
196 preg_match('#/FontBBox[\s]*{([^}]*)#', $font, $matches);
197 $fmetric['bbox'] = trim($matches[1]);
198 $bv = explode(' ', $fmetric['bbox']);
199 $fmetric['Ascent'] = intval($bv[3]);
200 $fmetric['Descent'] = intval($bv[1]);
201 preg_match('#/ItalicAngle[\s]*([0-9\+\-]*)#', $font, $matches);
202 $fmetric['italicAngle'] = intval($matches[1]);
203 if ($fmetric['italicAngle'] != 0) {
204 $fmetric['Flags'] |= 64;
205 }
206 preg_match('#/UnderlinePosition[\s]*([0-9\+\-]*)#', $font, $matches);
207 $fmetric['underlinePosition'] = intval($matches[1]);
208 preg_match('#/UnderlineThickness[\s]*([0-9\+\-]*)#', $font, $matches);
209 $fmetric['underlineThickness'] = intval($matches[1]);
210 preg_match('#/isFixedPitch[\s]*([^\s]*)#', $font, $matches);
211 if ($matches[1] == 'true') {
212 $fmetric['Flags'] |= 1;
213 }
214 // get internal map
215 $imap = array();
216 if (preg_match_all('#dup[\s]([0-9]+)[\s]*/([^\s]*)[\s]put#sU', $font, $fmap, PREG_SET_ORDER) > 0) {
217 foreach ($fmap as $v) {
218 $imap[$v[2]] = $v[1];
219 }
220 }
221 // decrypt eexec encrypted part
222 $r = 55665; // eexec encryption constant
223 $c1 = 52845;
224 $c2 = 22719;
225 $elen = strlen($encrypted);
226 $eplain = '';
227 for ($i = 0; $i < $elen; ++$i) {
228 $chr = ord($encrypted[$i]);
229 $eplain .= chr($chr ^ ($r >> 8));
230 $r = ((($chr + $r) * $c1 + $c2) % 65536);
231 }
232 if (preg_match('#/ForceBold[\s]*([^\s]*)#', $eplain, $matches) > 0) {
233 if ($matches[1] == 'true') {
234 $fmetric['Flags'] |= 0x40000;
235 }
236 }
237 if (preg_match('#/StdVW[\s]*\[([^\]]*)#', $eplain, $matches) > 0) {
238 $fmetric['StemV'] = intval($matches[1]);
239 } else {
240 $fmetric['StemV'] = 70;
241 }
242 if (preg_match('#/StdHW[\s]*\[([^\]]*)#', $eplain, $matches) > 0) {
243 $fmetric['StemH'] = intval($matches[1]);
244 } else {
245 $fmetric['StemH'] = 30;
246 }
247 if (preg_match('#/BlueValues[\s]*\[([^\]]*)#', $eplain, $matches) > 0) {
248 $bv = explode(' ', $matches[1]);
249 if (count($bv) >= 6) {
250 $v1 = intval($bv[2]);
251 $v2 = intval($bv[4]);
252 if ($v1 <= $v2) {
253 $fmetric['XHeight'] = $v1;
254 $fmetric['CapHeight'] = $v2;
255 } else {
256 $fmetric['XHeight'] = $v2;
257 $fmetric['CapHeight'] = $v1;
258 }
259 } else {
260 $fmetric['XHeight'] = 450;
261 $fmetric['CapHeight'] = 700;
262 }
263 } else {
264 $fmetric['XHeight'] = 450;
265 $fmetric['CapHeight'] = 700;
266 }
267 // get the number of random bytes at the beginning of charstrings
268 if (preg_match('#/lenIV[\s]*([0-9]*)#', $eplain, $matches) > 0) {
269 $lenIV = intval($matches[1]);
270 } else {
271 $lenIV = 4;
272 }
273 $fmetric['Leading'] = 0;
274 // get charstring data
275 $eplain = substr($eplain, (strpos($eplain, '/CharStrings') + 1));
276 preg_match_all('#/([A-Za-z0-9\.]*)[\s][0-9]+[\s]RD[\s](.*)[\s]ND#sU', $eplain, $matches, PREG_SET_ORDER);
277 if (!empty($enc) AND isset(TCPDF_FONT_DATA::$encmap[$enc])) {
278 $enc_map = TCPDF_FONT_DATA::$encmap[$enc];
279 } else {
280 $enc_map = false;
281 }
282 $fmetric['cw'] = '';
283 $fmetric['MaxWidth'] = 0;
284 $cwidths = array();
285 foreach ($matches as $k => $v) {
286 $cid = 0;
287 if (isset($imap[$v[1]])) {
288 $cid = $imap[$v[1]];
289 } elseif ($enc_map !== false) {
290 $cid = array_search($v[1], $enc_map);
291 if ($cid === false) {
292 $cid = 0;
293 } elseif ($cid > 1000) {
294 $cid -= 1000;
295 }
296 }
297 // decrypt charstring encrypted part
298 $r = 4330; // charstring encryption constant
299 $c1 = 52845;
300 $c2 = 22719;
301 $cd = $v[2];
302 $clen = strlen($cd);
303 $ccom = array();
304 for ($i = 0; $i < $clen; ++$i) {
305 $chr = ord($cd[$i]);
306 $ccom[] = ($chr ^ ($r >> 8));
307 $r = ((($chr + $r) * $c1 + $c2) % 65536);
308 }
309 // decode numbers
310 $cdec = array();
311 $ck = 0;
312 $i = $lenIV;
313 while ($i < $clen) {
314 if ($ccom[$i] < 32) {
315 $cdec[$ck] = $ccom[$i];
316 if (($ck > 0) AND ($cdec[$ck] == 13)) {
317 // hsbw command: update width
318 $cwidths[$cid] = $cdec[($ck - 1)];
319 }
320 ++$i;
321 } elseif (($ccom[$i] >= 32) AND ($ccom[$i] <= 246)) {
322 $cdec[$ck] = ($ccom[$i] - 139);
323 ++$i;
324 } elseif (($ccom[$i] >= 247) AND ($ccom[$i] <= 250)) {
325 $cdec[$ck] = ((($ccom[$i] - 247) * 256) + $ccom[($i + 1)] + 108);
326 $i += 2;
327 } elseif (($ccom[$i] >= 251) AND ($ccom[$i] <= 254)) {
328 $cdec[$ck] = ((-($ccom[$i] - 251) * 256) - $ccom[($i + 1)] - 108);
329 $i += 2;
330 } elseif ($ccom[$i] == 255) {
331 $sval = chr($ccom[($i + 1)]).chr($ccom[($i + 2)]).chr($ccom[($i + 3)]).chr($ccom[($i + 4)]);
332 $vsval = unpack('li', $sval);
333 $cdec[$ck] = $vsval['i'];
334 $i += 5;
335 }
336 ++$ck;
337 }
338 } // end for each matches
339 $fmetric['MissingWidth'] = $cwidths[0];
340 $fmetric['MaxWidth'] = $fmetric['MissingWidth'];
341 $fmetric['AvgWidth'] = 0;
342 // set chars widths
343 for ($cid = 0; $cid <= 255; ++$cid) {
344 if (isset($cwidths[$cid])) {
345 if ($cwidths[$cid] > $fmetric['MaxWidth']) {
346 $fmetric['MaxWidth'] = $cwidths[$cid];
347 }
348 $fmetric['AvgWidth'] += $cwidths[$cid];
349 $fmetric['cw'] .= ','.$cid.'=>'.$cwidths[$cid];
350 } else {
351 $fmetric['cw'] .= ','.$cid.'=>'.$fmetric['MissingWidth'];
352 }
353 }
354 $fmetric['AvgWidth'] = round($fmetric['AvgWidth'] / count($cwidths));
355 } else {
356 // ---------- TRUE TYPE ----------
357 if ($fmetric['type'] != 'cidfont0') {
358 if ($link) {
359 // creates a symbolic link to the existing font
360 symlink($fontfile, $outpath.$fmetric['file']);
361 } else {
362 // store compressed font
363 $fmetric['file'] .= '.z';
364 $fp = fopen($outpath.$fmetric['file'], 'wb');
365 fwrite($fp, gzcompress($font));
366 fclose($fp);
367 }
368 }
369 $offset = 0; // offset position of the font data
370 if (TCPDF_STATIC::_getULONG($font, $offset) != 0x10000) {
371 // sfnt version must be 0x00010000 for TrueType version 1.0.
372 return false;
373 }
374 $offset += 4;
375 // get number of tables
376 $numTables = TCPDF_STATIC::_getUSHORT($font, $offset);
377 $offset += 2;
378 // skip searchRange, entrySelector and rangeShift
379 $offset += 6;
380 // tables array
381 $table = array();
382 // ---------- get tables ----------
383 for ($i = 0; $i < $numTables; ++$i) {
384 // get table info
385 $tag = substr($font, $offset, 4);
386 $offset += 4;
387 $table[$tag] = array();
388 $table[$tag]['checkSum'] = TCPDF_STATIC::_getULONG($font, $offset);
389 $offset += 4;
390 $table[$tag]['offset'] = TCPDF_STATIC::_getULONG($font, $offset);
391 $offset += 4;
392 $table[$tag]['length'] = TCPDF_STATIC::_getULONG($font, $offset);
393 $offset += 4;
394 }
395 // check magicNumber
396 $offset = $table['head']['offset'] + 12;
397 if (TCPDF_STATIC::_getULONG($font, $offset) != 0x5F0F3CF5) {
398 // magicNumber must be 0x5F0F3CF5
399 return false;
400 }
401 $offset += 4;
402 $offset += 2; // skip flags
403 // get FUnits
404 $fmetric['unitsPerEm'] = TCPDF_STATIC::_getUSHORT($font, $offset);
405 $offset += 2;
406 // units ratio constant
407 $urk = (1000 / $fmetric['unitsPerEm']);
408 $offset += 16; // skip created, modified
409 $xMin = round(TCPDF_STATIC::_getFWORD($font, $offset) * $urk);
410 $offset += 2;
411 $yMin = round(TCPDF_STATIC::_getFWORD($font, $offset) * $urk);
412 $offset += 2;
413 $xMax = round(TCPDF_STATIC::_getFWORD($font, $offset) * $urk);
414 $offset += 2;
415 $yMax = round(TCPDF_STATIC::_getFWORD($font, $offset) * $urk);
416 $offset += 2;
417 $fmetric['bbox'] = ''.$xMin.' '.$yMin.' '.$xMax.' '.$yMax.'';
418 $macStyle = TCPDF_STATIC::_getUSHORT($font, $offset);
419 $offset += 2;
420 // PDF font flags
421 $fmetric['Flags'] = $flags;
422 if (($macStyle & 2) == 2) {
423 // italic flag
424 $fmetric['Flags'] |= 64;
425 }
426 // get offset mode (indexToLocFormat : 0 = short, 1 = long)
427 $offset = $table['head']['offset'] + 50;
428 $short_offset = (TCPDF_STATIC::_getSHORT($font, $offset) == 0);
429 $offset += 2;
430 // get the offsets to the locations of the glyphs in the font, relative to the beginning of the glyphData table
431 $indexToLoc = array();
432 $offset = $table['loca']['offset'];
433 if ($short_offset) {
434 // short version
435 $tot_num_glyphs = floor($table['loca']['length'] / 2); // numGlyphs + 1
436 for ($i = 0; $i < $tot_num_glyphs; ++$i) {
437 $indexToLoc[$i] = TCPDF_STATIC::_getUSHORT($font, $offset) * 2;
438 $offset += 2;
439 }
440 } else {
441 // long version
442 $tot_num_glyphs = floor($table['loca']['length'] / 4); // numGlyphs + 1
443 for ($i = 0; $i < $tot_num_glyphs; ++$i) {
444 $indexToLoc[$i] = TCPDF_STATIC::_getULONG($font, $offset);
445 $offset += 4;
446 }
447 }
448 // get glyphs indexes of chars from cmap table
449 $offset = $table['cmap']['offset'] + 2;
450 $numEncodingTables = TCPDF_STATIC::_getUSHORT($font, $offset);
451 $offset += 2;
452 $encodingTables = array();
453 for ($i = 0; $i < $numEncodingTables; ++$i) {
454 $encodingTables[$i]['platformID'] = TCPDF_STATIC::_getUSHORT($font, $offset);
455 $offset += 2;
456 $encodingTables[$i]['encodingID'] = TCPDF_STATIC::_getUSHORT($font, $offset);
457 $offset += 2;
458 $encodingTables[$i]['offset'] = TCPDF_STATIC::_getULONG($font, $offset);
459 $offset += 4;
460 }
461 // ---------- get os/2 metrics ----------
462 $offset = $table['OS/2']['offset'];
463 $offset += 2; // skip version
464 // xAvgCharWidth
465 $fmetric['AvgWidth'] = round(TCPDF_STATIC::_getFWORD($font, $offset) * $urk);
466 $offset += 2;
467 // usWeightClass
468 $usWeightClass = round(TCPDF_STATIC::_getUFWORD($font, $offset) * $urk);
469 // estimate StemV and StemH (400 = usWeightClass for Normal - Regular font)
470 $fmetric['StemV'] = round((70 * $usWeightClass) / 400);
471 $fmetric['StemH'] = round((30 * $usWeightClass) / 400);
472 $offset += 2;
473 $offset += 2; // usWidthClass
474 $fsType = TCPDF_STATIC::_getSHORT($font, $offset);
475 $offset += 2;
476 if ($fsType == 2) {
477 // This Font cannot be modified, embedded or exchanged in any manner without first obtaining permission of the legal owner.
478 return false;
479 }
480 // ---------- get font name ----------
481 $fmetric['name'] = '';
482 $offset = $table['name']['offset'];
483 $offset += 2; // skip Format selector (=0).
484 // Number of NameRecords that follow n.
485 $numNameRecords = TCPDF_STATIC::_getUSHORT($font, $offset);
486 $offset += 2;
487 // Offset to start of string storage (from start of table).
488 $stringStorageOffset = TCPDF_STATIC::_getUSHORT($font, $offset);
489 $offset += 2;
490 for ($i = 0; $i < $numNameRecords; ++$i) {
491 $offset += 6; // skip Platform ID, Platform-specific encoding ID, Language ID.
492 // Name ID.
493 $nameID = TCPDF_STATIC::_getUSHORT($font, $offset);
494 $offset += 2;
495 if ($nameID == 6) {
496 // String length (in bytes).
497 $stringLength = TCPDF_STATIC::_getUSHORT($font, $offset);
498 $offset += 2;
499 // String offset from start of storage area (in bytes).
500 $stringOffset = TCPDF_STATIC::_getUSHORT($font, $offset);
501 $offset += 2;
502 $offset = ($table['name']['offset'] + $stringStorageOffset + $stringOffset);
503 $fmetric['name'] = substr($font, $offset, $stringLength);
504 $fmetric['name'] = preg_replace('/[^a-zA-Z0-9_\-]/', '', $fmetric['name']);
505 break;
506 } else {
507 $offset += 4; // skip String length, String offset
508 }
509 }
510 if (empty($fmetric['name'])) {
511 $fmetric['name'] = $font_name;
512 }
513 // ---------- get post data ----------
514 $offset = $table['post']['offset'];
515 $offset += 4; // skip Format Type
516 $fmetric['italicAngle'] = TCPDF_STATIC::_getFIXED($font, $offset);
517 $offset += 4;
518 $fmetric['underlinePosition'] = round(TCPDF_STATIC::_getFWORD($font, $offset) * $urk);
519 $offset += 2;
520 $fmetric['underlineThickness'] = round(TCPDF_STATIC::_getFWORD($font, $offset) * $urk);
521 $offset += 2;
522 $isFixedPitch = (TCPDF_STATIC::_getULONG($font, $offset) == 0) ? false : true;
523 $offset += 2;
524 if ($isFixedPitch) {
525 $fmetric['Flags'] |= 1;
526 }
527 // ---------- get hhea data ----------
528 $offset = $table['hhea']['offset'];
529 $offset += 4; // skip Table version number
530 // Ascender
531 $fmetric['Ascent'] = round(TCPDF_STATIC::_getFWORD($font, $offset) * $urk);
532 $offset += 2;
533 // Descender
534 $fmetric['Descent'] = round(TCPDF_STATIC::_getFWORD($font, $offset) * $urk);
535 $offset += 2;
536 // LineGap
537 $fmetric['Leading'] = round(TCPDF_STATIC::_getFWORD($font, $offset) * $urk);
538 $offset += 2;
539 // advanceWidthMax
540 $fmetric['MaxWidth'] = round(TCPDF_STATIC::_getUFWORD($font, $offset) * $urk);
541 $offset += 2;
542 $offset += 22; // skip some values
543 // get the number of hMetric entries in hmtx table
544 $numberOfHMetrics = TCPDF_STATIC::_getUSHORT($font, $offset);
545 // ---------- get maxp data ----------
546 $offset = $table['maxp']['offset'];
547 $offset += 4; // skip Table version number
548 // get the the number of glyphs in the font.
549 $numGlyphs = TCPDF_STATIC::_getUSHORT($font, $offset);
550 // ---------- get CIDToGIDMap ----------
551 $ctg = array();
552 foreach ($encodingTables as $enctable) {
553 // get only specified Platform ID and Encoding ID
554 if (($enctable['platformID'] == $platid) AND ($enctable['encodingID'] == $encid)) {
555 $offset = $table['cmap']['offset'] + $enctable['offset'];
556 $format = TCPDF_STATIC::_getUSHORT($font, $offset);
557 $offset += 2;
558 switch ($format) {
559 case 0: { // Format 0: Byte encoding table
560 $offset += 4; // skip length and version/language
561 for ($c = 0; $c < 256; ++$c) {
562 $g = TCPDF_STATIC::_getBYTE($font, $offset);
563 $ctg[$c] = $g;
564 ++$offset;
565 }
566 break;
567 }
568 case 2: { // Format 2: High-byte mapping through table
569 $offset += 4; // skip length and version/language
570 $numSubHeaders = 0;
571 for ($i = 0; $i < 256; ++$i) {
572 // Array that maps high bytes to subHeaders: value is subHeader index * 8.
573 $subHeaderKeys[$i] = (TCPDF_STATIC::_getUSHORT($font, $offset) / 8);
574 $offset += 2;
575 if ($numSubHeaders < $subHeaderKeys[$i]) {
576 $numSubHeaders = $subHeaderKeys[$i];
577 }
578 }
579 // the number of subHeaders is equal to the max of subHeaderKeys + 1
580 ++$numSubHeaders;
581 // read subHeader structures
582 $subHeaders = array();
583 $numGlyphIndexArray = 0;
584 for ($k = 0; $k < $numSubHeaders; ++$k) {
585 $subHeaders[$k]['firstCode'] = TCPDF_STATIC::_getUSHORT($font, $offset);
586 $offset += 2;
587 $subHeaders[$k]['entryCount'] = TCPDF_STATIC::_getUSHORT($font, $offset);
588 $offset += 2;
589 $subHeaders[$k]['idDelta'] = TCPDF_STATIC::_getUSHORT($font, $offset);
590 $offset += 2;
591 $subHeaders[$k]['idRangeOffset'] = TCPDF_STATIC::_getUSHORT($font, $offset);
592 $offset += 2;
593 $subHeaders[$k]['idRangeOffset'] -= (2 + (($numSubHeaders - $k - 1) * 8));
594 $subHeaders[$k]['idRangeOffset'] /= 2;
595 $numGlyphIndexArray += $subHeaders[$k]['entryCount'];
596 }
597 for ($k = 0; $k < $numGlyphIndexArray; ++$k) {
598 $glyphIndexArray[$k] = TCPDF_STATIC::_getUSHORT($font, $offset);
599 $offset += 2;
600 }
601 for ($i = 0; $i < 256; ++$i) {
602 $k = $subHeaderKeys[$i];
603 if ($k == 0) {
604 // one byte code
605 $c = $i;
606 $g = $glyphIndexArray[0];
607 $ctg[$c] = $g;
608 } else {
609 // two bytes code
610 $start_byte = $subHeaders[$k]['firstCode'];
611 $end_byte = $start_byte + $subHeaders[$k]['entryCount'];
612 for ($j = $start_byte; $j < $end_byte; ++$j) {
613 // combine high and low bytes
614 $c = (($i << 8) + $j);
615 $idRangeOffset = ($subHeaders[$k]['idRangeOffset'] + $j - $subHeaders[$k]['firstCode']);
616 $g = ($glyphIndexArray[$idRangeOffset] + $subHeaders[$k]['idDelta']) % 65536;
617 if ($g < 0) {
618 $g = 0;
619 }
620 $ctg[$c] = $g;
621 }
622 }
623 }
624 break;
625 }
626 case 4: { // Format 4: Segment mapping to delta values
627 $length = TCPDF_STATIC::_getUSHORT($font, $offset);
628 $offset += 2;
629 $offset += 2; // skip version/language
630 $segCount = floor(TCPDF_STATIC::_getUSHORT($font, $offset) / 2);
631 $offset += 2;
632 $offset += 6; // skip searchRange, entrySelector, rangeShift
633 $endCount = array(); // array of end character codes for each segment
634 for ($k = 0; $k < $segCount; ++$k) {
635 $endCount[$k] = TCPDF_STATIC::_getUSHORT($font, $offset);
636 $offset += 2;
637 }
638 $offset += 2; // skip reservedPad
639 $startCount = array(); // array of start character codes for each segment
640 for ($k = 0; $k < $segCount; ++$k) {
641 $startCount[$k] = TCPDF_STATIC::_getUSHORT($font, $offset);
642 $offset += 2;
643 }
644 $idDelta = array(); // delta for all character codes in segment
645 for ($k = 0; $k < $segCount; ++$k) {
646 $idDelta[$k] = TCPDF_STATIC::_getUSHORT($font, $offset);
647 $offset += 2;
648 }
649 $idRangeOffset = array(); // Offsets into glyphIdArray or 0
650 for ($k = 0; $k < $segCount; ++$k) {
651 $idRangeOffset[$k] = TCPDF_STATIC::_getUSHORT($font, $offset);
652 $offset += 2;
653 }
654 $gidlen = (floor($length / 2) - 8 - (4 * $segCount));
655 $glyphIdArray = array(); // glyph index array
656 for ($k = 0; $k < $gidlen; ++$k) {
657 $glyphIdArray[$k] = TCPDF_STATIC::_getUSHORT($font, $offset);
658 $offset += 2;
659 }
660 for ($k = 0; $k < $segCount; ++$k) {
661 for ($c = $startCount[$k]; $c <= $endCount[$k]; ++$c) {
662 if ($idRangeOffset[$k] == 0) {
663 $g = ($idDelta[$k] + $c) % 65536;
664 } else {
665 $gid = (floor($idRangeOffset[$k] / 2) + ($c - $startCount[$k]) - ($segCount - $k));
666 $g = ($glyphIdArray[$gid] + $idDelta[$k]) % 65536;
667 }
668 if ($g < 0) {
669 $g = 0;
670 }
671 $ctg[$c] = $g;
672 }
673 }
674 break;
675 }
676 case 6: { // Format 6: Trimmed table mapping
677 $offset += 4; // skip length and version/language
678 $firstCode = TCPDF_STATIC::_getUSHORT($font, $offset);
679 $offset += 2;
680 $entryCount = TCPDF_STATIC::_getUSHORT($font, $offset);
681 $offset += 2;
682 for ($k = 0; $k < $entryCount; ++$k) {
683 $c = ($k + $firstCode);
684 $g = TCPDF_STATIC::_getUSHORT($font, $offset);
685 $offset += 2;
686 $ctg[$c] = $g;
687 }
688 break;
689 }
690 case 8: { // Format 8: Mixed 16-bit and 32-bit coverage
691 $offset += 10; // skip reserved, length and version/language
692 for ($k = 0; $k < 8192; ++$k) {
693 $is32[$k] = TCPDF_STATIC::_getBYTE($font, $offset);
694 ++$offset;
695 }
696 $nGroups = TCPDF_STATIC::_getULONG($font, $offset);
697 $offset += 4;
698 for ($i = 0; $i < $nGroups; ++$i) {
699 $startCharCode = TCPDF_STATIC::_getULONG($font, $offset);
700 $offset += 4;
701 $endCharCode = TCPDF_STATIC::_getULONG($font, $offset);
702 $offset += 4;
703 $startGlyphID = TCPDF_STATIC::_getULONG($font, $offset);
704 $offset += 4;
705 for ($k = $startCharCode; $k <= $endCharCode; ++$k) {
706 $is32idx = floor($c / 8);
707 if ((isset($is32[$is32idx])) AND (($is32[$is32idx] & (1 << (7 - ($c % 8)))) == 0)) {
708 $c = $k;
709 } else {
710 // 32 bit format
711 // convert to decimal (http://www.unicode.org/faq//utf_bom.html#utf16-4)
712 //LEAD_OFFSET = (0xD800 - (0x10000 >> 10)) = 55232
713 //SURROGATE_OFFSET = (0x10000 - (0xD800 << 10) - 0xDC00) = -56613888
714 $c = ((55232 + ($k >> 10)) << 10) + (0xDC00 + ($k & 0x3FF)) -56613888;
715 }
716 $ctg[$c] = 0;
717 ++$startGlyphID;
718 }
719 }
720 break;
721 }
722 case 10: { // Format 10: Trimmed array
723 $offset += 10; // skip reserved, length and version/language
724 $startCharCode = TCPDF_STATIC::_getULONG($font, $offset);
725 $offset += 4;
726 $numChars = TCPDF_STATIC::_getULONG($font, $offset);
727 $offset += 4;
728 for ($k = 0; $k < $numChars; ++$k) {
729 $c = ($k + $startCharCode);
730 $g = TCPDF_STATIC::_getUSHORT($font, $offset);
731 $ctg[$c] = $g;
732 $offset += 2;
733 }
734 break;
735 }
736 case 12: { // Format 12: Segmented coverage
737 $offset += 10; // skip length and version/language
738 $nGroups = TCPDF_STATIC::_getULONG($font, $offset);
739 $offset += 4;
740 for ($k = 0; $k < $nGroups; ++$k) {
741 $startCharCode = TCPDF_STATIC::_getULONG($font, $offset);
742 $offset += 4;
743 $endCharCode = TCPDF_STATIC::_getULONG($font, $offset);
744 $offset += 4;
745 $startGlyphCode = TCPDF_STATIC::_getULONG($font, $offset);
746 $offset += 4;
747 for ($c = $startCharCode; $c <= $endCharCode; ++$c) {
748 $ctg[$c] = $startGlyphCode;
749 ++$startGlyphCode;
750 }
751 }
752 break;
753 }
754 case 13: { // Format 13: Many-to-one range mappings
755 // to be implemented ...
756 break;
757 }
758 case 14: { // Format 14: Unicode Variation Sequences
759 // to be implemented ...
760 break;
761 }
762 }
763 }
764 }
765 if (!isset($ctg[0])) {
766 $ctg[0] = 0;
767 }
768 // get xHeight (height of x)
769 $offset = ($table['glyf']['offset'] + $indexToLoc[$ctg[120]] + 4);
770 $yMin = TCPDF_STATIC::_getFWORD($font, $offset);
771 $offset += 4;
772 $yMax = TCPDF_STATIC::_getFWORD($font, $offset);
773 $offset += 2;
774 $fmetric['XHeight'] = round(($yMax - $yMin) * $urk);
775 // get CapHeight (height of H)
776 $offset = ($table['glyf']['offset'] + $indexToLoc[$ctg[72]] + 4);
777 $yMin = TCPDF_STATIC::_getFWORD($font, $offset);
778 $offset += 4;
779 $yMax = TCPDF_STATIC::_getFWORD($font, $offset);
780 $offset += 2;
781 $fmetric['CapHeight'] = round(($yMax - $yMin) * $urk);
782 // ceate widths array
783 $cw = array();
784 $offset = $table['hmtx']['offset'];
785 for ($i = 0 ; $i < $numberOfHMetrics; ++$i) {
786 $cw[$i] = round(TCPDF_STATIC::_getUFWORD($font, $offset) * $urk);
787 $offset += 4; // skip lsb
788 }
789 if ($numberOfHMetrics < $numGlyphs) {
790 // fill missing widths with the last value
791 $cw = array_pad($cw, $numGlyphs, $cw[($numberOfHMetrics - 1)]);
792 }
793 $fmetric['MissingWidth'] = $cw[0];
794 $fmetric['cw'] = '';
795 $fmetric['cbbox'] = '';
796 for ($cid = 0; $cid <= 65535; ++$cid) {
797 if (isset($ctg[$cid])) {
798 if (isset($cw[$ctg[$cid]])) {
799 $fmetric['cw'] .= ','.$cid.'=>'.$cw[$ctg[$cid]];
800 }
801 if ($addcbbox AND isset($indexToLoc[$ctg[$cid]])) {
802 $offset = ($table['glyf']['offset'] + $indexToLoc[$ctg[$cid]]);
803 $xMin = round(TCPDF_STATIC::_getFWORD($font, $offset + 2) * $urk);
804 $yMin = round(TCPDF_STATIC::_getFWORD($font, $offset + 4) * $urk);
805 $xMax = round(TCPDF_STATIC::_getFWORD($font, $offset + 6) * $urk);
806 $yMax = round(TCPDF_STATIC::_getFWORD($font, $offset + 8) * $urk);
807 $fmetric['cbbox'] .= ','.$cid.'=>array('.$xMin.','.$yMin.','.$xMax.','.$yMax.')';
808 }
809 }
810 }
811 } // end of true type
812 if (($fmetric['type'] == 'TrueTypeUnicode') AND (count($ctg) == 256)) {
813 $fmetric['type'] = 'TrueType';
814 }
815 // ---------- create php font file ----------
816 $pfile = '<'.'?'.'php'."\n";
817 $pfile .= '// TCPDF FONT FILE DESCRIPTION'."\n";
818 $pfile .= '$type=\''.$fmetric['type'].'\';'."\n";
819 $pfile .= '$name=\''.$fmetric['name'].'\';'."\n";
820 $pfile .= '$up='.$fmetric['underlinePosition'].';'."\n";
821 $pfile .= '$ut='.$fmetric['underlineThickness'].';'."\n";
822 if ($fmetric['MissingWidth'] > 0) {
823 $pfile .= '$dw='.$fmetric['MissingWidth'].';'."\n";
824 } else {
825 $pfile .= '$dw='.$fmetric['AvgWidth'].';'."\n";
826 }
827 $pfile .= '$diff=\''.$fmetric['diff'].'\';'."\n";
828 if ($fmetric['type'] == 'Type1') {
829 // Type 1
830 $pfile .= '$enc=\''.$fmetric['enc'].'\';'."\n";
831 $pfile .= '$file=\''.$fmetric['file'].'\';'."\n";
832 $pfile .= '$size1='.$fmetric['size1'].';'."\n";
833 $pfile .= '$size2='.$fmetric['size2'].';'."\n";
834 } else {
835 $pfile .= '$originalsize='.$fmetric['originalsize'].';'."\n";
836 if ($fmetric['type'] == 'cidfont0') {
837 // CID-0
838 switch ($fonttype) {
839 case 'CID0JP': {
840 $pfile .= '// Japanese'."\n";
841 $pfile .= '$enc=\'UniJIS-UTF16-H\';'."\n";
842 $pfile .= '$cidinfo=array(\'Registry\'=>\'Adobe\', \'Ordering\'=>\'Japan1\',\'Supplement\'=>5);'."\n";
843 $pfile .= 'include(dirname(__FILE__).\'/uni2cid_aj16.php\');'."\n";
844 break;
845 }
846 case 'CID0KR': {
847 $pfile .= '// Korean'."\n";
848 $pfile .= '$enc=\'UniKS-UTF16-H\';'."\n";
849 $pfile .= '$cidinfo=array(\'Registry\'=>\'Adobe\', \'Ordering\'=>\'Korea1\',\'Supplement\'=>0);'."\n";
850 $pfile .= 'include(dirname(__FILE__).\'/uni2cid_ak12.php\');'."\n";
851 break;
852 }
853 case 'CID0CS': {
854 $pfile .= '// Chinese Simplified'."\n";
855 $pfile .= '$enc=\'UniGB-UTF16-H\';'."\n";
856 $pfile .= '$cidinfo=array(\'Registry\'=>\'Adobe\', \'Ordering\'=>\'GB1\',\'Supplement\'=>2);'."\n";
857 $pfile .= 'include(dirname(__FILE__).\'/uni2cid_ag15.php\');'."\n";
858 break;
859 }
860 case 'CID0CT':
861 default: {
862 $pfile .= '// Chinese Traditional'."\n";
863 $pfile .= '$enc=\'UniCNS-UTF16-H\';'."\n";
864 $pfile .= '$cidinfo=array(\'Registry\'=>\'Adobe\', \'Ordering\'=>\'CNS1\',\'Supplement\'=>0);'."\n";
865 $pfile .= 'include(dirname(__FILE__).\'/uni2cid_aj16.php\');'."\n";
866 break;
867 }
868 }
869 } else {
870 // TrueType
871 $pfile .= '$enc=\''.$fmetric['enc'].'\';'."\n";
872 $pfile .= '$file=\''.$fmetric['file'].'\';'."\n";
873 $pfile .= '$ctg=\''.$fmetric['ctg'].'\';'."\n";
874 // create CIDToGIDMap
875 $cidtogidmap = str_pad('', 131072, "\x00"); // (256 * 256 * 2) = 131072
876 foreach ($ctg as $cid => $gid) {
877 $cidtogidmap = self::updateCIDtoGIDmap($cidtogidmap, $cid, $ctg[$cid]);
878 }
879 // store compressed CIDToGIDMap
880 $fp = fopen($outpath.$fmetric['ctg'], 'wb');
881 fwrite($fp, gzcompress($cidtogidmap));
882 fclose($fp);
883 }
884 }
885 $pfile .= '$desc=array(';
886 $pfile .= '\'Flags\'=>'.$fmetric['Flags'].',';
887 $pfile .= '\'FontBBox\'=>\'['.$fmetric['bbox'].']\',';
888 $pfile .= '\'ItalicAngle\'=>'.$fmetric['italicAngle'].',';
889 $pfile .= '\'Ascent\'=>'.$fmetric['Ascent'].',';
890 $pfile .= '\'Descent\'=>'.$fmetric['Descent'].',';
891 $pfile .= '\'Leading\'=>'.$fmetric['Leading'].',';
892 $pfile .= '\'CapHeight\'=>'.$fmetric['CapHeight'].',';
893 $pfile .= '\'XHeight\'=>'.$fmetric['XHeight'].',';
894 $pfile .= '\'StemV\'=>'.$fmetric['StemV'].',';
895 $pfile .= '\'StemH\'=>'.$fmetric['StemH'].',';
896 $pfile .= '\'AvgWidth\'=>'.$fmetric['AvgWidth'].',';
897 $pfile .= '\'MaxWidth\'=>'.$fmetric['MaxWidth'].',';
898 $pfile .= '\'MissingWidth\'=>'.$fmetric['MissingWidth'].'';
899 $pfile .= ');'."\n";
900 if (!empty($fmetric['cbbox'])) {
901 $pfile .= '$cbbox=array('.substr($fmetric['cbbox'], 1).');'."\n";
902 }
903 $pfile .= '$cw=array('.substr($fmetric['cw'], 1).');'."\n";
904 $pfile .= '// --- EOF ---'."\n";
905 // store file
906 $fp = fopen($outpath.$font_name.'.php', 'w');
907 fwrite($fp, $pfile);
908 fclose($fp);
909 // return TCPDF font name
910 return $font_name;
911 }
912
913 /**
914 * Returs the checksum of a TTF table.
915 * @param $table (string) table to check
916 * @param $length (int) length of table in bytes
917 * @return int checksum
918 * @author Nicola Asuni
919 * @since 5.2.000 (2010-06-02)
920 * @public static
921 */
922 public static function _getTTFtableChecksum($table, $length) {
923 $sum = 0;
924 $tlen = ($length / 4);
925 $offset = 0;
926 for ($i = 0; $i < $tlen; ++$i) {
927 $v = unpack('Ni', substr($table, $offset, 4));
928 $sum += $v['i'];
929 $offset += 4;
930 }
931 $sum = unpack('Ni', pack('N', $sum));
932 return $sum['i'];
933 }
934
935 /**
936 * Returns a subset of the TrueType font data without the unused glyphs.
937 * @param $font (string) TrueType font data.
938 * @param $subsetchars (array) Array of used characters (the glyphs to keep).
939 * @return (string) A subset of TrueType font data without the unused glyphs.
940 * @author Nicola Asuni
941 * @since 5.2.000 (2010-06-02)
942 * @public static
943 */
944 public static function _getTrueTypeFontSubset($font, $subsetchars) {
945 ksort($subsetchars);
946 $offset = 0; // offset position of the font data
947 if (TCPDF_STATIC::_getULONG($font, $offset) != 0x10000) {
948 // sfnt version must be 0x00010000 for TrueType version 1.0.
949 return $font;
950 }
951 $offset += 4;
952 // get number of tables
953 $numTables = TCPDF_STATIC::_getUSHORT($font, $offset);
954 $offset += 2;
955 // skip searchRange, entrySelector and rangeShift
956 $offset += 6;
957 // tables array
958 $table = array();
959 // for each table
960 for ($i = 0; $i < $numTables; ++$i) {
961 // get table info
962 $tag = substr($font, $offset, 4);
963 $offset += 4;
964 $table[$tag] = array();
965 $table[$tag]['checkSum'] = TCPDF_STATIC::_getULONG($font, $offset);
966 $offset += 4;
967 $table[$tag]['offset'] = TCPDF_STATIC::_getULONG($font, $offset);
968 $offset += 4;
969 $table[$tag]['length'] = TCPDF_STATIC::_getULONG($font, $offset);
970 $offset += 4;
971 }
972 // check magicNumber
973 $offset = $table['head']['offset'] + 12;
974 if (TCPDF_STATIC::_getULONG($font, $offset) != 0x5F0F3CF5) {
975 // magicNumber must be 0x5F0F3CF5
976 return $font;
977 }
978 $offset += 4;
979 // get offset mode (indexToLocFormat : 0 = short, 1 = long)
980 $offset = $table['head']['offset'] + 50;
981 $short_offset = (TCPDF_STATIC::_getSHORT($font, $offset) == 0);
982 $offset += 2;
983 // get the offsets to the locations of the glyphs in the font, relative to the beginning of the glyphData table
984 $indexToLoc = array();
985 $offset = $table['loca']['offset'];
986 if ($short_offset) {
987 // short version
988 $tot_num_glyphs = floor($table['loca']['length'] / 2); // numGlyphs + 1
989 for ($i = 0; $i < $tot_num_glyphs; ++$i) {
990 $indexToLoc[$i] = TCPDF_STATIC::_getUSHORT($font, $offset) * 2;
991 $offset += 2;
992 }
993 } else {
994 // long version
995 $tot_num_glyphs = ($table['loca']['length'] / 4); // numGlyphs + 1
996 for ($i = 0; $i < $tot_num_glyphs; ++$i) {
997 $indexToLoc[$i] = TCPDF_STATIC::_getULONG($font, $offset);
998 $offset += 4;
999 }
1000 }
1001 // get glyphs indexes of chars from cmap table
1002 $subsetglyphs = array(); // glyph IDs on key
1003 $subsetglyphs[0] = true; // character codes that do not correspond to any glyph in the font should be mapped to glyph index 0
1004 $offset = $table['cmap']['offset'] + 2;
1005 $numEncodingTables = TCPDF_STATIC::_getUSHORT($font, $offset);
1006 $offset += 2;
1007 $encodingTables = array();
1008 for ($i = 0; $i < $numEncodingTables; ++$i) {
1009 $encodingTables[$i]['platformID'] = TCPDF_STATIC::_getUSHORT($font, $offset);
1010 $offset += 2;
1011 $encodingTables[$i]['encodingID'] = TCPDF_STATIC::_getUSHORT($font, $offset);
1012 $offset += 2;
1013 $encodingTables[$i]['offset'] = TCPDF_STATIC::_getULONG($font, $offset);
1014 $offset += 4;
1015 }
1016 foreach ($encodingTables as $enctable) {
1017 // get all platforms and encodings
1018 $offset = $table['cmap']['offset'] + $enctable['offset'];
1019 $format = TCPDF_STATIC::_getUSHORT($font, $offset);
1020 $offset += 2;
1021 switch ($format) {
1022 case 0: { // Format 0: Byte encoding table
1023 $offset += 4; // skip length and version/language
1024 for ($c = 0; $c < 256; ++$c) {
1025 if (isset($subsetchars[$c])) {
1026 $g = TCPDF_STATIC::_getBYTE($font, $offset);
1027 $subsetglyphs[$g] = true;
1028 }
1029 ++$offset;
1030 }
1031 break;
1032 }
1033 case 2: { // Format 2: High-byte mapping through table
1034 $offset += 4; // skip length and version/language
1035 $numSubHeaders = 0;
1036 for ($i = 0; $i < 256; ++$i) {
1037 // Array that maps high bytes to subHeaders: value is subHeader index * 8.
1038 $subHeaderKeys[$i] = (TCPDF_STATIC::_getUSHORT($font, $offset) / 8);
1039 $offset += 2;
1040 if ($numSubHeaders < $subHeaderKeys[$i]) {
1041 $numSubHeaders = $subHeaderKeys[$i];
1042 }
1043 }
1044 // the number of subHeaders is equal to the max of subHeaderKeys + 1
1045 ++$numSubHeaders;
1046 // read subHeader structures
1047 $subHeaders = array();
1048 $numGlyphIndexArray = 0;
1049 for ($k = 0; $k < $numSubHeaders; ++$k) {
1050 $subHeaders[$k]['firstCode'] = TCPDF_STATIC::_getUSHORT($font, $offset);
1051 $offset += 2;
1052 $subHeaders[$k]['entryCount'] = TCPDF_STATIC::_getUSHORT($font, $offset);
1053 $offset += 2;
1054 $subHeaders[$k]['idDelta'] = TCPDF_STATIC::_getUSHORT($font, $offset);
1055 $offset += 2;
1056 $subHeaders[$k]['idRangeOffset'] = TCPDF_STATIC::_getUSHORT($font, $offset);
1057 $offset += 2;
1058 $subHeaders[$k]['idRangeOffset'] -= (2 + (($numSubHeaders - $k - 1) * 8));
1059 $subHeaders[$k]['idRangeOffset'] /= 2;
1060 $numGlyphIndexArray += $subHeaders[$k]['entryCount'];
1061 }
1062 for ($k = 0; $k < $numGlyphIndexArray; ++$k) {
1063 $glyphIndexArray[$k] = TCPDF_STATIC::_getUSHORT($font, $offset);
1064 $offset += 2;
1065 }
1066 for ($i = 0; $i < 256; ++$i) {
1067 $k = $subHeaderKeys[$i];
1068 if ($k == 0) {
1069 // one byte code
1070 $c = $i;
1071 if (isset($subsetchars[$c])) {
1072 $g = $glyphIndexArray[0];
1073 $subsetglyphs[$g] = true;
1074 }
1075 } else {
1076 // two bytes code
1077 $start_byte = $subHeaders[$k]['firstCode'];
1078 $end_byte = $start_byte + $subHeaders[$k]['entryCount'];
1079 for ($j = $start_byte; $j < $end_byte; ++$j) {
1080 // combine high and low bytes
1081 $c = (($i << 8) + $j);
1082 if (isset($subsetchars[$c])) {
1083 $idRangeOffset = ($subHeaders[$k]['idRangeOffset'] + $j - $subHeaders[$k]['firstCode']);
1084 $g = ($glyphIndexArray[$idRangeOffset] + $subHeaders[$k]['idDelta']) % 65536;
1085 if ($g < 0) {
1086 $g = 0;
1087 }
1088 $subsetglyphs[$g] = true;
1089 }
1090 }
1091 }
1092 }
1093 break;
1094 }
1095 case 4: { // Format 4: Segment mapping to delta values
1096 $length = TCPDF_STATIC::_getUSHORT($font, $offset);
1097 $offset += 2;
1098 $offset += 2; // skip version/language
1099 $segCount = floor(TCPDF_STATIC::_getUSHORT($font, $offset) / 2);
1100 $offset += 2;
1101 $offset += 6; // skip searchRange, entrySelector, rangeShift
1102 $endCount = array(); // array of end character codes for each segment
1103 for ($k = 0; $k < $segCount; ++$k) {
1104 $endCount[$k] = TCPDF_STATIC::_getUSHORT($font, $offset);
1105 $offset += 2;
1106 }
1107 $offset += 2; // skip reservedPad
1108 $startCount = array(); // array of start character codes for each segment
1109 for ($k = 0; $k < $segCount; ++$k) {
1110 $startCount[$k] = TCPDF_STATIC::_getUSHORT($font, $offset);
1111 $offset += 2;
1112 }
1113 $idDelta = array(); // delta for all character codes in segment
1114 for ($k = 0; $k < $segCount; ++$k) {
1115 $idDelta[$k] = TCPDF_STATIC::_getUSHORT($font, $offset);
1116 $offset += 2;
1117 }
1118 $idRangeOffset = array(); // Offsets into glyphIdArray or 0
1119 for ($k = 0; $k < $segCount; ++$k) {
1120 $idRangeOffset[$k] = TCPDF_STATIC::_getUSHORT($font, $offset);
1121 $offset += 2;
1122 }
1123 $gidlen = (floor($length / 2) - 8 - (4 * $segCount));
1124 $glyphIdArray = array(); // glyph index array
1125 for ($k = 0; $k < $gidlen; ++$k) {
1126 $glyphIdArray[$k] = TCPDF_STATIC::_getUSHORT($font, $offset);
1127 $offset += 2;
1128 }
1129 for ($k = 0; $k < $segCount; ++$k) {
1130 for ($c = $startCount[$k]; $c <= $endCount[$k]; ++$c) {
1131 if (isset($subsetchars[$c])) {
1132 if ($idRangeOffset[$k] == 0) {
1133 $g = ($idDelta[$k] + $c) % 65536;
1134 } else {
1135 $gid = (floor($idRangeOffset[$k] / 2) + ($c - $startCount[$k]) - ($segCount - $k));
1136 $g = ($glyphIdArray[$gid] + $idDelta[$k]) % 65536;
1137 }
1138 if ($g < 0) {
1139 $g = 0;
1140 }
1141 $subsetglyphs[$g] = true;
1142 }
1143 }
1144 }
1145 break;
1146 }
1147 case 6: { // Format 6: Trimmed table mapping
1148 $offset += 4; // skip length and version/language
1149 $firstCode = TCPDF_STATIC::_getUSHORT($font, $offset);
1150 $offset += 2;
1151 $entryCount = TCPDF_STATIC::_getUSHORT($font, $offset);
1152 $offset += 2;
1153 for ($k = 0; $k < $entryCount; ++$k) {
1154 $c = ($k + $firstCode);
1155 if (isset($subsetchars[$c])) {
1156 $g = TCPDF_STATIC::_getUSHORT($font, $offset);
1157 $subsetglyphs[$g] = true;
1158 }
1159 $offset += 2;
1160 }
1161 break;
1162 }
1163 case 8: { // Format 8: Mixed 16-bit and 32-bit coverage
1164 $offset += 10; // skip reserved, length and version/language
1165 for ($k = 0; $k < 8192; ++$k) {
1166 $is32[$k] = TCPDF_STATIC::_getBYTE($font, $offset);
1167 ++$offset;
1168 }
1169 $nGroups = TCPDF_STATIC::_getULONG($font, $offset);
1170 $offset += 4;
1171 for ($i = 0; $i < $nGroups; ++$i) {
1172 $startCharCode = TCPDF_STATIC::_getULONG($font, $offset);
1173 $offset += 4;
1174 $endCharCode = TCPDF_STATIC::_getULONG($font, $offset);
1175 $offset += 4;
1176 $startGlyphID = TCPDF_STATIC::_getULONG($font, $offset);
1177 $offset += 4;
1178 for ($k = $startCharCode; $k <= $endCharCode; ++$k) {
1179 $is32idx = floor($c / 8);
1180 if ((isset($is32[$is32idx])) AND (($is32[$is32idx] & (1 << (7 - ($c % 8)))) == 0)) {
1181 $c = $k;
1182 } else {
1183 // 32 bit format
1184 // convert to decimal (http://www.unicode.org/faq//utf_bom.html#utf16-4)
1185 //LEAD_OFFSET = (0xD800 - (0x10000 >> 10)) = 55232
1186 //SURROGATE_OFFSET = (0x10000 - (0xD800 << 10) - 0xDC00) = -56613888
1187 $c = ((55232 + ($k >> 10)) << 10) + (0xDC00 + ($k & 0x3FF)) -56613888;
1188 }
1189 if (isset($subsetchars[$c])) {
1190 $subsetglyphs[$startGlyphID] = true;
1191 }
1192 ++$startGlyphID;
1193 }
1194 }
1195 break;
1196 }
1197 case 10: { // Format 10: Trimmed array
1198 $offset += 10; // skip reserved, length and version/language
1199 $startCharCode = TCPDF_STATIC::_getULONG($font, $offset);
1200 $offset += 4;
1201 $numChars = TCPDF_STATIC::_getULONG($font, $offset);
1202 $offset += 4;
1203 for ($k = 0; $k < $numChars; ++$k) {
1204 $c = ($k + $startCharCode);
1205 if (isset($subsetchars[$c])) {
1206 $g = TCPDF_STATIC::_getUSHORT($font, $offset);
1207 $subsetglyphs[$g] = true;
1208 }
1209 $offset += 2;
1210 }
1211 break;
1212 }
1213 case 12: { // Format 12: Segmented coverage
1214 $offset += 10; // skip length and version/language
1215 $nGroups = TCPDF_STATIC::_getULONG($font, $offset);
1216 $offset += 4;
1217 for ($k = 0; $k < $nGroups; ++$k) {
1218 $startCharCode = TCPDF_STATIC::_getULONG($font, $offset);
1219 $offset += 4;
1220 $endCharCode = TCPDF_STATIC::_getULONG($font, $offset);
1221 $offset += 4;
1222 $startGlyphCode = TCPDF_STATIC::_getULONG($font, $offset);
1223 $offset += 4;
1224 for ($c = $startCharCode; $c <= $endCharCode; ++$c) {
1225 if (isset($subsetchars[$c])) {
1226 $subsetglyphs[$startGlyphCode] = true;
1227 }
1228 ++$startGlyphCode;
1229 }
1230 }
1231 break;
1232 }
1233 case 13: { // Format 13: Many-to-one range mappings
1234 // to be implemented ...
1235 break;
1236 }
1237 case 14: { // Format 14: Unicode Variation Sequences
1238 // to be implemented ...
1239 break;
1240 }
1241 }
1242 }
1243 // include all parts of composite glyphs
1244 $new_sga = $subsetglyphs;
1245 while (!empty($new_sga)) {
1246 $sga = $new_sga;
1247 $new_sga = array();
1248 foreach ($sga as $key => $val) {
1249 if (isset($indexToLoc[$key])) {
1250 $offset = ($table['glyf']['offset'] + $indexToLoc[$key]);
1251 $numberOfContours = TCPDF_STATIC::_getSHORT($font, $offset);
1252 $offset += 2;
1253 if ($numberOfContours < 0) { // composite glyph
1254 $offset += 8; // skip xMin, yMin, xMax, yMax
1255 do {
1256 $flags = TCPDF_STATIC::_getUSHORT($font, $offset);
1257 $offset += 2;
1258 $glyphIndex = TCPDF_STATIC::_getUSHORT($font, $offset);
1259 $offset += 2;
1260 if (!isset($subsetglyphs[$glyphIndex])) {
1261 // add missing glyphs
1262 $new_sga[$glyphIndex] = true;
1263 }
1264 // skip some bytes by case
1265 if ($flags & 1) {
1266 $offset += 4;
1267 } else {
1268 $offset += 2;
1269 }
1270 if ($flags & 8) {
1271 $offset += 2;
1272 } elseif ($flags & 64) {
1273 $offset += 4;
1274 } elseif ($flags & 128) {
1275 $offset += 8;
1276 }
1277 } while ($flags & 32);
1278 }
1279 }
1280 }
1281 $subsetglyphs += $new_sga;
1282 }
1283 // sort glyphs by key (and remove duplicates)
1284 ksort($subsetglyphs);
1285 // build new glyf and loca tables
1286 $glyf = '';
1287 $loca = '';
1288 $offset = 0;
1289 $glyf_offset = $table['glyf']['offset'];
1290 for ($i = 0; $i < $tot_num_glyphs; ++$i) {
1291 if (isset($subsetglyphs[$i])) {
1292 $length = ($indexToLoc[($i + 1)] - $indexToLoc[$i]);
1293 $glyf .= substr($font, ($glyf_offset + $indexToLoc[$i]), $length);
1294 } else {
1295 $length = 0;
1296 }
1297 if ($short_offset) {
1298 $loca .= pack('n', floor($offset / 2));
1299 } else {
1300 $loca .= pack('N', $offset);
1301 }
1302 $offset += $length;
1303 }
1304 // array of table names to preserve (loca and glyf tables will be added later)
1305 // the cmap table is not needed and shall not be present, since the mapping from character codes to glyph descriptions is provided separately
1306 $table_names = array ('head', 'hhea', 'hmtx', 'maxp', 'cvt ', 'fpgm', 'prep'); // minimum required table names
1307 // get the tables to preserve
1308 $offset = 12;
1309 foreach ($table as $tag => $val) {
1310 if (in_array($tag, $table_names)) {
1311 $table[$tag]['data'] = substr($font, $table[$tag]['offset'], $table[$tag]['length']);
1312 if ($tag == 'head') {
1313 // set the checkSumAdjustment to 0
1314 $table[$tag]['data'] = substr($table[$tag]['data'], 0, 8)."\x0\x0\x0\x0".substr($table[$tag]['data'], 12);
1315 }
1316 $pad = 4 - ($table[$tag]['length'] % 4);
1317 if ($pad != 4) {
1318 // the length of a table must be a multiple of four bytes
1319 $table[$tag]['length'] += $pad;
1320 $table[$tag]['data'] .= str_repeat("\x0", $pad);
1321 }
1322 $table[$tag]['offset'] = $offset;
1323 $offset += $table[$tag]['length'];
1324 // check sum is not changed (so keep the following line commented)
1325 //$table[$tag]['checkSum'] = self::_getTTFtableChecksum($table[$tag]['data'], $table[$tag]['length']);
1326 } else {
1327 unset($table[$tag]);
1328 }
1329 }
1330 // add loca
1331 $table['loca']['data'] = $loca;
1332 $table['loca']['length'] = strlen($loca);
1333 $pad = 4 - ($table['loca']['length'] % 4);
1334 if ($pad != 4) {
1335 // the length of a table must be a multiple of four bytes
1336 $table['loca']['length'] += $pad;
1337 $table['loca']['data'] .= str_repeat("\x0", $pad);
1338 }
1339 $table['loca']['offset'] = $offset;
1340 $table['loca']['checkSum'] = self::_getTTFtableChecksum($table['loca']['data'], $table['loca']['length']);
1341 $offset += $table['loca']['length'];
1342 // add glyf
1343 $table['glyf']['data'] = $glyf;
1344 $table['glyf']['length'] = strlen($glyf);
1345 $pad = 4 - ($table['glyf']['length'] % 4);
1346 if ($pad != 4) {
1347 // the length of a table must be a multiple of four bytes
1348 $table['glyf']['length'] += $pad;
1349 $table['glyf']['data'] .= str_repeat("\x0", $pad);
1350 }
1351 $table['glyf']['offset'] = $offset;
1352 $table['glyf']['checkSum'] = self::_getTTFtableChecksum($table['glyf']['data'], $table['glyf']['length']);
1353 // rebuild font
1354 $font = '';
1355 $font .= pack('N', 0x10000); // sfnt version
1356 $numTables = count($table);
1357 $font .= pack('n', $numTables); // numTables
1358 $entrySelector = floor(log($numTables, 2));
1359 $searchRange = pow(2, $entrySelector) * 16;
1360 $rangeShift = ($numTables * 16) - $searchRange;
1361 $font .= pack('n', $searchRange); // searchRange
1362 $font .= pack('n', $entrySelector); // entrySelector
1363 $font .= pack('n', $rangeShift); // rangeShift
1364 $offset = ($numTables * 16);
1365 foreach ($table as $tag => $data) {
1366 $font .= $tag; // tag
1367 $font .= pack('N', $data['checkSum']); // checkSum
1368 $font .= pack('N', ($data['offset'] + $offset)); // offset
1369 $font .= pack('N', $data['length']); // length
1370 }
1371 foreach ($table as $data) {
1372 $font .= $data['data'];
1373 }
1374 // set checkSumAdjustment on head table
1375 $checkSumAdjustment = 0xB1B0AFBA - self::_getTTFtableChecksum($font, strlen($font));
1376 $font = substr($font, 0, $table['head']['offset'] + 8).pack('N', $checkSumAdjustment).substr($font, $table['head']['offset'] + 12);
1377 return $font;
1378 }
1379
1380 /**
1381 * Outputs font widths
1382 * @param $font (array) font data
1383 * @param $cidoffset (int) offset for CID values
1384 * @return PDF command string for font widths
1385 * @author Nicola Asuni
1386 * @since 4.4.000 (2008-12-07)
1387 * @public static
1388 */
1389 public static function _putfontwidths($font, $cidoffset=0) {
1390 ksort($font['cw']);
1391 $rangeid = 0;
1392 $range = array();
1393 $prevcid = -2;
1394 $prevwidth = -1;
1395 $interval = false;
1396 // for each character
1397 foreach ($font['cw'] as $cid => $width) {
1398 $cid -= $cidoffset;
1399 if ($font['subset'] AND (!isset($font['subsetchars'][$cid]))) {
1400 // ignore the unused characters (font subsetting)
1401 continue;
1402 }
1403 if ($width != $font['dw']) {
1404 if ($cid == ($prevcid + 1)) {
1405 // consecutive CID
1406 if ($width == $prevwidth) {
1407 if ($width == $range[$rangeid][0]) {
1408 $range[$rangeid][] = $width;
1409 } else {
1410 array_pop($range[$rangeid]);
1411 // new range
1412 $rangeid = $prevcid;
1413 $range[$rangeid] = array();
1414 $range[$rangeid][] = $prevwidth;
1415 $range[$rangeid][] = $width;
1416 }
1417 $interval = true;
1418 $range[$rangeid]['interval'] = true;
1419 } else {
1420 if ($interval) {
1421 // new range
1422 $rangeid = $cid;
1423 $range[$rangeid] = array();
1424 $range[$rangeid][] = $width;
1425 } else {
1426 $range[$rangeid][] = $width;
1427 }
1428 $interval = false;
1429 }
1430 } else {
1431 // new range
1432 $rangeid = $cid;
1433 $range[$rangeid] = array();
1434 $range[$rangeid][] = $width;
1435 $interval = false;
1436 }
1437 $prevcid = $cid;
1438 $prevwidth = $width;
1439 }
1440 }
1441 // optimize ranges
1442 $prevk = -1;
1443 $nextk = -1;
1444 $prevint = false;
1445 foreach ($range as $k => $ws) {
1446 $cws = count($ws);
1447 if (($k == $nextk) AND (!$prevint) AND ((!isset($ws['interval'])) OR ($cws < 4))) {
1448 if (isset($range[$k]['interval'])) {
1449 unset($range[$k]['interval']);
1450 }
1451 $range[$prevk] = array_merge($range[$prevk], $range[$k]);
1452 unset($range[$k]);
1453 } else {
1454 $prevk = $k;
1455 }
1456 $nextk = $k + $cws;
1457 if (isset($ws['interval'])) {
1458 if ($cws > 3) {
1459 $prevint = true;
1460 } else {
1461 $prevint = false;
1462 }
1463 if (isset($range[$k]['interval'])) {
1464 unset($range[$k]['interval']);
1465 }
1466 --$nextk;
1467 } else {
1468 $prevint = false;
1469 }
1470 }
1471 // output data
1472 $w = '';
1473 foreach ($range as $k => $ws) {
1474 if (count(array_count_values($ws)) == 1) {
1475 // interval mode is more compact
1476 $w .= ' '.$k.' '.($k + count($ws) - 1).' '.$ws[0];
1477 } else {
1478 // range mode
1479 $w .= ' '.$k.' [ '.implode(' ', $ws).' ]';
1480 }
1481 }
1482 return '/W ['.$w.' ]';
1483 }
1484
1485 /**
1486 * Returns the unicode caracter specified by the value
1487 * @param $c (int) UTF-8 value
1488 * @param $unicode (boolean) True if we are in unicode mode, false otherwise.
1489 * @return Returns the specified character.
1490 * @since 2.3.000 (2008-03-05)
1491 * @public static
1492 */
1493 public static function unichr($c, $unicode=true) {
1494 if (!$unicode) {
1495 return chr($c);
1496 } elseif ($c <= 0x7F) {
1497 // one byte
1498 return chr($c);
1499 } elseif ($c <= 0x7FF) {
1500 // two bytes
1501 return chr(0xC0 | $c >> 6).chr(0x80 | $c & 0x3F);
1502 } elseif ($c <= 0xFFFF) {
1503 // three bytes
1504 return chr(0xE0 | $c >> 12).chr(0x80 | $c >> 6 & 0x3F).chr(0x80 | $c & 0x3F);
1505 } elseif ($c <= 0x10FFFF) {
1506 // four bytes
1507 return chr(0xF0 | $c >> 18).chr(0x80 | $c >> 12 & 0x3F).chr(0x80 | $c >> 6 & 0x3F).chr(0x80 | $c & 0x3F);
1508 } else {
1509 return '';
1510 }
1511 }
1512
1513 /**
1514 * Returns the unicode caracter specified by UTF-8 value
1515 * @param $c (int) UTF-8 value
1516 * @return Returns the specified character.
1517 * @public static
1518 */
1519 public static function unichrUnicode($c) {
1520 return self::unichr($c, true);
1521 }
1522
1523 /**
1524 * Returns the unicode caracter specified by ASCII value
1525 * @param $c (int) UTF-8 value
1526 * @return Returns the specified character.
1527 * @public static
1528 */
1529 public static function unichrASCII($c) {
1530 return self::unichr($c, false);
1531 }
1532
1533 /**
1534 * Converts array of UTF-8 characters to UTF16-BE string.<br>
1535 * Based on: http://www.faqs.org/rfcs/rfc2781.html
1536 * <pre>
1537 * Encoding UTF-16:
1538 *
1539 * Encoding of a single character from an ISO 10646 character value to
1540 * UTF-16 proceeds as follows. Let U be the character number, no greater
1541 * than 0x10FFFF.
1542 *
1543 * 1) If U < 0x10000, encode U as a 16-bit unsigned integer and
1544 * terminate.
1545 *
1546 * 2) Let U' = U - 0x10000. Because U is less than or equal to 0x10FFFF,
1547 * U' must be less than or equal to 0xFFFFF. That is, U' can be
1548 * represented in 20 bits.
1549 *
1550 * 3) Initialize two 16-bit unsigned integers, W1 and W2, to 0xD800 and
1551 * 0xDC00, respectively. These integers each have 10 bits free to
1552 * encode the character value, for a total of 20 bits.
1553 *
1554 * 4) Assign the 10 high-order bits of the 20-bit U' to the 10 low-order
1555 * bits of W1 and the 10 low-order bits of U' to the 10 low-order
1556 * bits of W2. Terminate.
1557 *
1558 * Graphically, steps 2 through 4 look like:
1559 * U' = yyyyyyyyyyxxxxxxxxxx
1560 * W1 = 110110yyyyyyyyyy
1561 * W2 = 110111xxxxxxxxxx
1562 * </pre>
1563 * @param $unicode (array) array containing UTF-8 unicode values
1564 * @param $setbom (boolean) if true set the Byte Order Mark (BOM = 0xFEFF)
1565 * @return string
1566 * @protected
1567 * @author Nicola Asuni
1568 * @since 2.1.000 (2008-01-08)
1569 * @public static
1570 */
1571 public static function arrUTF8ToUTF16BE($unicode, $setbom=false) {
1572 $outstr = ''; // string to be returned
1573 if ($setbom) {
1574 $outstr .= "\xFE\xFF"; // Byte Order Mark (BOM)
1575 }
1576 foreach ($unicode as $char) {
1577 if ($char == 0x200b) {
1578 // skip Unicode Character 'ZERO WIDTH SPACE' (DEC:8203, U+200B)
1579 } elseif ($char == 0xFFFD) {
1580 $outstr .= "\xFF\xFD"; // replacement character
1581 } elseif ($char < 0x10000) {
1582 $outstr .= chr($char >> 0x08);
1583 $outstr .= chr($char & 0xFF);
1584 } else {
1585 $char -= 0x10000;
1586 $w1 = 0xD800 | ($char >> 0x0a);
1587 $w2 = 0xDC00 | ($char & 0x3FF);
1588 $outstr .= chr($w1 >> 0x08);
1589 $outstr .= chr($w1 & 0xFF);
1590 $outstr .= chr($w2 >> 0x08);
1591 $outstr .= chr($w2 & 0xFF);
1592 }
1593 }
1594 return $outstr;
1595 }
1596
1597 /**
1598 * Convert an array of UTF8 values to array of unicode characters
1599 * @param $ta (array) The input array of UTF8 values.
1600 * @param $isunicode (boolean) True for Unicode mode, false otherwise.
1601 * @return Return array of unicode characters
1602 * @since 4.5.037 (2009-04-07)
1603 * @public static
1604 */
1605 public static function UTF8ArrayToUniArray($ta, $isunicode=true) {
1606 if ($isunicode) {
1607 return array_map(array('TCPDF_FONTS', 'unichrUnicode'), $ta);
1608 }
1609 return array_map(array('TCPDF_FONTS', 'unichrASCII'), $ta);
1610 }
1611
1612 /**
1613 * Extract a slice of the $strarr array and return it as string.
1614 * @param $strarr (string) The input array of characters.
1615 * @param $start (int) the starting element of $strarr.
1616 * @param $end (int) first element that will not be returned.
1617 * @param $unicode (boolean) True if we are in unicode mode, false otherwise.
1618 * @return Return part of a string
1619 * @public static
1620 */
1621 public static function UTF8ArrSubString($strarr, $start='', $end='', $unicode=true) {
1622 if (strlen($start) == 0) {
1623 $start = 0;
1624 }
1625 if (strlen($end) == 0) {
1626 $end = count($strarr);
1627 }
1628 $string = '';
1629 for ($i = $start; $i < $end; ++$i) {
1630 $string .= self::unichr($strarr[$i], $unicode);
1631 }
1632 return $string;
1633 }
1634
1635 /**
1636 * Extract a slice of the $uniarr array and return it as string.
1637 * @param $uniarr (string) The input array of characters.
1638 * @param $start (int) the starting element of $strarr.
1639 * @param $end (int) first element that will not be returned.
1640 * @return Return part of a string
1641 * @since 4.5.037 (2009-04-07)
1642 * @public static
1643 */
1644 public static function UniArrSubString($uniarr, $start='', $end='') {
1645 if (strlen($start) == 0) {
1646 $start = 0;
1647 }
1648 if (strlen($end) == 0) {
1649 $end = count($uniarr);
1650 }
1651 $string = '';
1652 for ($i=$start; $i < $end; ++$i) {
1653 $string .= $uniarr[$i];
1654 }
1655 return $string;
1656 }
1657
1658 /**
1659 * Update the CIDToGIDMap string with a new value.
1660 * @param $map (string) CIDToGIDMap.
1661 * @param $cid (int) CID value.
1662 * @param $gid (int) GID value.
1663 * @return (string) CIDToGIDMap.
1664 * @author Nicola Asuni
1665 * @since 5.9.123 (2011-09-29)
1666 * @public static
1667 */
1668 public static function updateCIDtoGIDmap($map, $cid, $gid) {
1669 if (($cid >= 0) AND ($cid <= 0xFFFF) AND ($gid >= 0)) {
1670 if ($gid > 0xFFFF) {
1671 $gid -= 0x10000;
1672 }
1673 $map[($cid * 2)] = chr($gid >> 8);
1674 $map[(($cid * 2) + 1)] = chr($gid & 0xFF);
1675 }
1676 return $map;
1677 }
1678
1679 /**
1680 * Return fonts path
1681 * @return string
1682 * @public static
1683 */
1684 public static function _getfontpath() {
1685 if (!defined('K_PATH_FONTS') AND is_dir($fdir = realpath(dirname(__FILE__).'/../fonts'))) {
1686 if (substr($fdir, -1) != '/') {
1687 $fdir .= '/';
1688 }
1689 define('K_PATH_FONTS', $fdir);
1690 }
1691 return defined('K_PATH_FONTS') ? K_PATH_FONTS : '';
1692 }
1693
1694 /**
1695 * Return font full path
1696 * @param $file (string) Font file name.
1697 * @param $fontdir (string) Font directory (set to false fto search on default directories)
1698 * @return string Font full path or empty string
1699 * @author Nicola Asuni
1700 * @since 6.0.025
1701 * @public static
1702 */
1703 public static function getFontFullPath($file, $fontdir=false) {
1704 $fontfile = '';
1705 // search files on various directories
1706 if (($fontdir !== false) AND @file_exists($fontdir.$file)) {
1707 $fontfile = $fontdir.$file;
1708 } elseif (@file_exists(self::_getfontpath().$file)) {
1709 $fontfile = self::_getfontpath().$file;
1710 } elseif (@file_exists($file)) {
1711 $fontfile = $file;
1712 }
1713 return $fontfile;
1714 }
1715
1716 /**
1717 * Converts UTF-8 characters array to array of Latin1 characters array<br>
1718 * @param $unicode (array) array containing UTF-8 unicode values
1719 * @return array
1720 * @author Nicola Asuni
1721 * @since 4.8.023 (2010-01-15)
1722 * @public static
1723 */
1724 public static function UTF8ArrToLatin1Arr($unicode) {
1725 $outarr = array(); // array to be returned
1726 foreach ($unicode as $char) {
1727 if ($char < 256) {
1728 $outarr[] = $char;
1729 } elseif (array_key_exists($char, TCPDF_FONT_DATA::$uni_utf8tolatin)) {
1730 // map from UTF-8
1731 $outarr[] = TCPDF_FONT_DATA::$uni_utf8tolatin[$char];
1732 } elseif ($char == 0xFFFD) {
1733 // skip
1734 } else {
1735 $outarr[] = 63; // '?' character
1736 }
1737 }
1738 return $outarr;
1739 }
1740
1741 /**
1742 * Converts UTF-8 characters array to array of Latin1 string<br>
1743 * @param $unicode (array) array containing UTF-8 unicode values
1744 * @return array
1745 * @author Nicola Asuni
1746 * @since 4.8.023 (2010-01-15)
1747 * @public static
1748 */
1749 public static function UTF8ArrToLatin1($unicode) {
1750 $outstr = ''; // string to be returned
1751 foreach ($unicode as $char) {
1752 if ($char < 256) {
1753 $outstr .= chr($char);
1754 } elseif (array_key_exists($char, TCPDF_FONT_DATA::$uni_utf8tolatin)) {
1755 // map from UTF-8
1756 $outstr .= chr(TCPDF_FONT_DATA::$uni_utf8tolatin[$char]);
1757 } elseif ($char == 0xFFFD) {
1758 // skip
1759 } else {
1760 $outstr .= '?';
1761 }
1762 }
1763 return $outstr;
1764 }
1765
1766 /**
1767 * Converts UTF-8 character to integer value.<br>
1768 * Uses the getUniord() method if the value is not cached.
1769 * @param $uch (string) character string to process.
1770 * @return integer Unicode value
1771 * @public static
1772 */
1773 public static function uniord($uch) {
1774 if (!isset(self::$cache_uniord[$uch])) {
1775 self::$cache_uniord[$uch] = self::getUniord($uch);
1776 }
1777 return self::$cache_uniord[$uch];
1778 }
1779
1780 /**
1781 * Converts UTF-8 character to integer value.<br>
1782 * Invalid byte sequences will be replaced with 0xFFFD (replacement character)<br>
1783 * Based on: http://www.faqs.org/rfcs/rfc3629.html
1784 * <pre>
1785 * Char. number range | UTF-8 octet sequence
1786 * (hexadecimal) | (binary)
1787 * --------------------+-----------------------------------------------
1788 * 0000 0000-0000 007F | 0xxxxxxx
1789 * 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
1790 * 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
1791 * 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
1792 * ---------------------------------------------------------------------
1793 *
1794 * ABFN notation:
1795 * ---------------------------------------------------------------------
1796 * UTF8-octets = *( UTF8-char )
1797 * UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4
1798 * UTF8-1 = %x00-7F
1799 * UTF8-2 = %xC2-DF UTF8-tail
1800 *
1801 * UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /
1802 * %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
1803 * UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
1804 * %xF4 %x80-8F 2( UTF8-tail )
1805 * UTF8-tail = %x80-BF
1806 * ---------------------------------------------------------------------
1807 * </pre>
1808 * @param $uch (string) character string to process.
1809 * @return integer Unicode value
1810 * @author Nicola Asuni
1811 * @public static
1812 */
1813 public static function getUniord($uch) {
1814 if (function_exists('mb_convert_encoding')) {
1815 list(, $char) = @unpack('N', mb_convert_encoding($uch, 'UCS-4BE', 'UTF-8'));
1816 if ($char >= 0) {
1817 return $char;
1818 }
1819 }
1820 $bytes = array(); // array containing single character byte sequences
1821 $countbytes = 0;
1822 $numbytes = 1; // number of octetc needed to represent the UTF-8 character
1823 $length = strlen($uch);
1824 for ($i = 0; $i < $length; ++$i) {
1825 $char = ord($uch[$i]); // get one string character at time
1826 if ($countbytes == 0) { // get starting octect
1827 if ($char <= 0x7F) {
1828 return $char; // use the character "as is" because is ASCII
1829 } elseif (($char >> 0x05) == 0x06) { // 2 bytes character (0x06 = 110 BIN)
1830 $bytes[] = ($char - 0xC0) << 0x06;
1831 ++$countbytes;
1832 $numbytes = 2;
1833 } elseif (($char >> 0x04) == 0x0E) { // 3 bytes character (0x0E = 1110 BIN)
1834 $bytes[] = ($char - 0xE0) << 0x0C;
1835 ++$countbytes;
1836 $numbytes = 3;
1837 } elseif (($char >> 0x03) == 0x1E) { // 4 bytes character (0x1E = 11110 BIN)
1838 $bytes[] = ($char - 0xF0) << 0x12;
1839 ++$countbytes;
1840 $numbytes = 4;
1841 } else {
1842 // use replacement character for other invalid sequences
1843 return 0xFFFD;
1844 }
1845 } elseif (($char >> 0x06) == 0x02) { // bytes 2, 3 and 4 must start with 0x02 = 10 BIN
1846 $bytes[] = $char - 0x80;
1847 ++$countbytes;
1848 if ($countbytes == $numbytes) {
1849 // compose UTF-8 bytes to a single unicode value
1850 $char = $bytes[0];
1851 for ($j = 1; $j < $numbytes; ++$j) {
1852 $char += ($bytes[$j] << (($numbytes - $j - 1) * 0x06));
1853 }
1854 if ((($char >= 0xD800) AND ($char <= 0xDFFF)) OR ($char >= 0x10FFFF)) {
1855 // The definition of UTF-8 prohibits encoding character numbers between
1856 // U+D800 and U+DFFF, which are reserved for use with the UTF-16
1857 // encoding form (as surrogate pairs) and do not directly represent
1858 // characters.
1859 return 0xFFFD; // use replacement character
1860 } else {
1861 return $char;
1862 }
1863 }
1864 } else {
1865 // use replacement character for other invalid sequences
1866 return 0xFFFD;
1867 }
1868 }
1869 return 0xFFFD;
1870 }
1871
1872 /**
1873 * Converts UTF-8 strings to codepoints array.<br>
1874 * Invalid byte sequences will be replaced with 0xFFFD (replacement character)<br>
1875 * @param $str (string) string to process.
1876 * @param $isunicode (boolean) True when the documetn is in Unicode mode, false otherwise.
1877 * @param $currentfont (array) Reference to current font array.
1878 * @return array containing codepoints (UTF-8 characters values)
1879 * @author Nicola Asuni
1880 * @public static
1881 */
1882 public static function UTF8StringToArray($str, $isunicode=true, &$currentfont) {
1883 if ($isunicode) {
1884 // requires PCRE unicode support turned on
1885 $chars = TCPDF_STATIC::pregSplit('//','u', $str, -1, PREG_SPLIT_NO_EMPTY);
1886 $carr = array_map(array('TCPDF_FONTS', 'uniord'), $chars);
1887 } else {
1888 $chars = str_split($str);
1889 $carr = array_map('ord', $chars);
1890 }
1891 $currentfont['subsetchars'] += array_fill_keys($carr, true);
1892 return $carr;
1893 }
1894
1895 /**
1896 * Converts UTF-8 strings to Latin1 when using the standard 14 core fonts.<br>
1897 * @param $str (string) string to process.
1898 * @param $isunicode (boolean) True when the documetn is in Unicode mode, false otherwise.
1899 * @param $currentfont (array) Reference to current font array.
1900 * @return string
1901 * @since 3.2.000 (2008-06-23)
1902 * @public static
1903 */
1904 public static function UTF8ToLatin1($str, $isunicode=true, &$currentfont) {
1905 $unicode = self::UTF8StringToArray($str, $isunicode, $currentfont); // array containing UTF-8 unicode values
1906 return self::UTF8ArrToLatin1($unicode);
1907 }
1908
1909 /**
1910 * Converts UTF-8 strings to UTF16-BE.<br>
1911 * @param $str (string) string to process.
1912 * @param $setbom (boolean) if true set the Byte Order Mark (BOM = 0xFEFF)
1913 * @param $isunicode (boolean) True when the documetn is in Unicode mode, false otherwise.
1914 * @param $currentfont (array) Reference to current font array.
1915 * @return string
1916 * @author Nicola Asuni
1917 * @since 1.53.0.TC005 (2005-01-05)
1918 * @public static
1919 */
1920 public static function UTF8ToUTF16BE($str, $setbom=false, $isunicode=true, &$currentfont) {
1921 if (!$isunicode) {
1922 return $str; // string is not in unicode
1923 }
1924 $unicode = self::UTF8StringToArray($str, $isunicode, $currentfont); // array containing UTF-8 unicode values
1925 return self::arrUTF8ToUTF16BE($unicode, $setbom);
1926 }
1927
1928 /**
1929 * Reverse the RLT substrings using the Bidirectional Algorithm (http://unicode.org/reports/tr9/).
1930 * @param $str (string) string to manipulate.
1931 * @param $setbom (bool) if true set the Byte Order Mark (BOM = 0xFEFF)
1932 * @param $forcertl (bool) if true forces RTL text direction
1933 * @param $isunicode (boolean) True if the document is in Unicode mode, false otherwise.
1934 * @param $currentfont (array) Reference to current font array.
1935 * @return string
1936 * @author Nicola Asuni
1937 * @since 2.1.000 (2008-01-08)
1938 * @public static
1939 */
1940 public static function utf8StrRev($str, $setbom=false, $forcertl=false, $isunicode=true, &$currentfont) {
1941 return self::utf8StrArrRev(self::UTF8StringToArray($str, $isunicode, $currentfont), $str, $setbom, $forcertl, $isunicode, $currentfont);
1942 }
1943
1944 /**
1945 * Reverse the RLT substrings array using the Bidirectional Algorithm (http://unicode.org/reports/tr9/).
1946 * @param $arr (array) array of unicode values.
1947 * @param $str (string) string to manipulate (or empty value).
1948 * @param $setbom (bool) if true set the Byte Order Mark (BOM = 0xFEFF)
1949 * @param $forcertl (bool) if true forces RTL text direction
1950 * @param $isunicode (boolean) True if the document is in Unicode mode, false otherwise.
1951 * @param $currentfont (array) Reference to current font array.
1952 * @return string
1953 * @author Nicola Asuni
1954 * @since 4.9.000 (2010-03-27)
1955 * @public static
1956 */
1957 public static function utf8StrArrRev($arr, $str='', $setbom=false, $forcertl=false, $isunicode=true, &$currentfont) {
1958 return self::arrUTF8ToUTF16BE(self::utf8Bidi($arr, $str, $forcertl, $isunicode, $currentfont), $setbom);
1959 }
1960
1961 /**
1962 * Reverse the RLT substrings using the Bidirectional Algorithm (http://unicode.org/reports/tr9/).
1963 * @param $ta (array) array of characters composing the string.
1964 * @param $str (string) string to process
1965 * @param $forcertl (bool) if 'R' forces RTL, if 'L' forces LTR
1966 * @param $isunicode (boolean) True if the document is in Unicode mode, false otherwise.
1967 * @param $currentfont (array) Reference to current font array.
1968 * @return array of unicode chars
1969 * @author Nicola Asuni
1970 * @since 2.4.000 (2008-03-06)
1971 * @public static
1972 */
1973 public static function utf8Bidi($ta, $str='', $forcertl=false, $isunicode=true, &$currentfont) {
1974 // paragraph embedding level
1975 $pel = 0;
1976 // max level
1977 $maxlevel = 0;
1978 if (TCPDF_STATIC::empty_string($str)) {
1979 // create string from array
1980 $str = self::UTF8ArrSubString($ta, '', '', $isunicode);
1981 }
1982 // check if string contains arabic text
1983 if (preg_match(TCPDF_FONT_DATA::$uni_RE_PATTERN_ARABIC, $str)) {
1984 $arabic = true;
1985 } else {
1986 $arabic = false;
1987 }
1988 // check if string contains RTL text
1989 if (!($forcertl OR $arabic OR preg_match(TCPDF_FONT_DATA::$uni_RE_PATTERN_RTL, $str))) {
1990 return $ta;
1991 }
1992
1993 // get number of chars
1994 $numchars = count($ta);
1995
1996 if ($forcertl == 'R') {
1997 $pel = 1;
1998 } elseif ($forcertl == 'L') {
1999 $pel = 0;
2000 } else {
2001 // P2. In each paragraph, find the first character of type L, AL, or R.
2002 // P3. If a character is found in P2 and it is of type AL or R, then set the paragraph embedding level to one; otherwise, set it to zero.
2003 for ($i=0; $i < $numchars; ++$i) {
2004 $type = TCPDF_FONT_DATA::$uni_type[$ta[$i]];
2005 if ($type == 'L') {
2006 $pel = 0;
2007 break;
2008 } elseif (($type == 'AL') OR ($type == 'R')) {
2009 $pel = 1;
2010 break;
2011 }
2012 }
2013 }
2014
2015 // Current Embedding Level
2016 $cel = $pel;
2017 // directional override status
2018 $dos = 'N';
2019 $remember = array();
2020 // start-of-level-run
2021 $sor = $pel % 2 ? 'R' : 'L';
2022 $eor = $sor;
2023
2024 // Array of characters data
2025 $chardata = Array();
2026
2027 // X1. Begin by setting the current embedding level to the paragraph embedding level. Set the directional override status to neutral. Process each character iteratively, applying rules X2 through X9. Only embedding levels from 0 to 61 are valid in this phase.
2028 // In the resolution of levels in rules I1 and I2, the maximum embedding level of 62 can be reached.
2029 for ($i=0; $i < $numchars; ++$i) {
2030 if ($ta[$i] == TCPDF_FONT_DATA::$uni_RLE) {
2031 // X2. With each RLE, compute the least greater odd embedding level.
2032 // a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to neutral.
2033 // b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status.
2034 $next_level = $cel + ($cel % 2) + 1;
2035 if ($next_level < 62) {
2036 $remember[] = array('num' => TCPDF_FONT_DATA::$uni_RLE, 'cel' => $cel, 'dos' => $dos);
2037 $cel = $next_level;
2038 $dos = 'N';
2039 $sor = $eor;
2040 $eor = $cel % 2 ? 'R' : 'L';
2041 }
2042 } elseif ($ta[$i] == TCPDF_FONT_DATA::$uni_LRE) {
2043 // X3. With each LRE, compute the least greater even embedding level.
2044 // a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to neutral.
2045 // b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status.
2046 $next_level = $cel + 2 - ($cel % 2);
2047 if ( $next_level < 62 ) {
2048 $remember[] = array('num' => TCPDF_FONT_DATA::$uni_LRE, 'cel' => $cel, 'dos' => $dos);
2049 $cel = $next_level;
2050 $dos = 'N';
2051 $sor = $eor;
2052 $eor = $cel % 2 ? 'R' : 'L';
2053 }
2054 } elseif ($ta[$i] == TCPDF_FONT_DATA::$uni_RLO) {
2055 // X4. With each RLO, compute the least greater odd embedding level.
2056 // a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to right-to-left.
2057 // b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status.
2058 $next_level = $cel + ($cel % 2) + 1;
2059 if ($next_level < 62) {
2060 $remember[] = array('num' => TCPDF_FONT_DATA::$uni_RLO, 'cel' => $cel, 'dos' => $dos);
2061 $cel = $next_level;
2062 $dos = 'R';
2063 $sor = $eor;
2064 $eor = $cel % 2 ? 'R' : 'L';
2065 }
2066 } elseif ($ta[$i] == TCPDF_FONT_DATA::$uni_LRO) {
2067 // X5. With each LRO, compute the least greater even embedding level.
2068 // a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to left-to-right.
2069 // b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status.
2070 $next_level = $cel + 2 - ($cel % 2);
2071 if ( $next_level < 62 ) {
2072 $remember[] = array('num' => TCPDF_FONT_DATA::$uni_LRO, 'cel' => $cel, 'dos' => $dos);
2073 $cel = $next_level;
2074 $dos = 'L';
2075 $sor = $eor;
2076 $eor = $cel % 2 ? 'R' : 'L';
2077 }
2078 } elseif ($ta[$i] == TCPDF_FONT_DATA::$uni_PDF) {
2079 // X7. With each PDF, determine the matching embedding or override code. If there was a valid matching code, restore (pop) the last remembered (pushed) embedding level and directional override.
2080 if (count($remember)) {
2081 $last = count($remember ) - 1;
2082 if (($remember[$last]['num'] == TCPDF_FONT_DATA::$uni_RLE) OR
2083 ($remember[$last]['num'] == TCPDF_FONT_DATA::$uni_LRE) OR
2084 ($remember[$last]['num'] == TCPDF_FONT_DATA::$uni_RLO) OR
2085 ($remember[$last]['num'] == TCPDF_FONT_DATA::$uni_LRO)) {
2086 $match = array_pop($remember);
2087 $cel = $match['cel'];
2088 $dos = $match['dos'];
2089 $sor = $eor;
2090 $eor = ($cel > $match['cel'] ? $cel : $match['cel']) % 2 ? 'R' : 'L';
2091 }
2092 }
2093 } elseif (($ta[$i] != TCPDF_FONT_DATA::$uni_RLE) AND
2094 ($ta[$i] != TCPDF_FONT_DATA::$uni_LRE) AND
2095 ($ta[$i] != TCPDF_FONT_DATA::$uni_RLO) AND
2096 ($ta[$i] != TCPDF_FONT_DATA::$uni_LRO) AND
2097 ($ta[$i] != TCPDF_FONT_DATA::$uni_PDF)) {
2098 // X6. For all types besides RLE, LRE, RLO, LRO, and PDF:
2099 // a. Set the level of the current character to the current embedding level.
2100 // b. Whenever the directional override status is not neutral, reset the current character type to the directional override status.
2101 if ($dos != 'N') {
2102 $chardir = $dos;
2103 } else {
2104 if (isset(TCPDF_FONT_DATA::$uni_type[$ta[$i]])) {
2105 $chardir = TCPDF_FONT_DATA::$uni_type[$ta[$i]];
2106 } else {
2107 $chardir = 'L';
2108 }
2109 }
2110 // stores string characters and other information
2111 $chardata[] = array('char' => $ta[$i], 'level' => $cel, 'type' => $chardir, 'sor' => $sor, 'eor' => $eor);
2112 }
2113 } // end for each char
2114
2115 // X8. All explicit directional embeddings and overrides are completely terminated at the end of each paragraph. Paragraph separators are not included in the embedding.
2116 // X9. Remove all RLE, LRE, RLO, LRO, PDF, and BN codes.
2117 // X10. The remaining rules are applied to each run of characters at the same level. For each run, determine the start-of-level-run (sor) and end-of-level-run (eor) type, either L or R. This depends on the higher of the two levels on either side of the boundary (at the start or end of the paragraph, the level of the 'other' run is the base embedding level). If the higher level is odd, the type is R; otherwise, it is L.
2118
2119 // 3.3.3 Resolving Weak Types
2120 // Weak types are now resolved one level run at a time. At level run boundaries where the type of the character on the other side of the boundary is required, the type assigned to sor or eor is used.
2121 // Nonspacing marks are now resolved based on the previous characters.
2122 $numchars = count($chardata);
2123
2124 // W1. Examine each nonspacing mark (NSM) in the level run, and change the type of the NSM to the type of the previous character. If the NSM is at the start of the level run, it will get the type of sor.
2125 $prevlevel = -1; // track level changes
2126 $levcount = 0; // counts consecutive chars at the same level
2127 for ($i=0; $i < $numchars; ++$i) {
2128 if ($chardata[$i]['type'] == 'NSM') {
2129 if ($levcount) {
2130 $chardata[$i]['type'] = $chardata[$i]['sor'];
2131 } elseif ($i > 0) {
2132 $chardata[$i]['type'] = $chardata[($i-1)]['type'];
2133 }
2134 }
2135 if ($chardata[$i]['level'] != $prevlevel) {
2136 $levcount = 0;
2137 } else {
2138 ++$levcount;
2139 }
2140 $prevlevel = $chardata[$i]['level'];
2141 }
2142
2143 // W2. Search backward from each instance of a European number until the first strong type (R, L, AL, or sor) is found. If an AL is found, change the type of the European number to Arabic number.
2144 $prevlevel = -1;
2145 $levcount = 0;
2146 for ($i=0; $i < $numchars; ++$i) {
2147 if ($chardata[$i]['char'] == 'EN') {
2148 for ($j=$levcount; $j >= 0; $j--) {
2149 if ($chardata[$j]['type'] == 'AL') {
2150 $chardata[$i]['type'] = 'AN';
2151 } elseif (($chardata[$j]['type'] == 'L') OR ($chardata[$j]['type'] == 'R')) {
2152 break;
2153 }
2154 }
2155 }
2156 if ($chardata[$i]['level'] != $prevlevel) {
2157 $levcount = 0;
2158 } else {
2159 ++$levcount;
2160 }
2161 $prevlevel = $chardata[$i]['level'];
2162 }
2163
2164 // W3. Change all ALs to R.
2165 for ($i=0; $i < $numchars; ++$i) {
2166 if ($chardata[$i]['type'] == 'AL') {
2167 $chardata[$i]['type'] = 'R';
2168 }
2169 }
2170
2171 // W4. A single European separator between two European numbers changes to a European number. A single common separator between two numbers of the same type changes to that type.
2172 $prevlevel = -1;
2173 $levcount = 0;
2174 for ($i=0; $i < $numchars; ++$i) {
2175 if (($levcount > 0) AND (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] == $prevlevel)) {
2176 if (($chardata[$i]['type'] == 'ES') AND ($chardata[($i-1)]['type'] == 'EN') AND ($chardata[($i+1)]['type'] == 'EN')) {
2177 $chardata[$i]['type'] = 'EN';
2178 } elseif (($chardata[$i]['type'] == 'CS') AND ($chardata[($i-1)]['type'] == 'EN') AND ($chardata[($i+1)]['type'] == 'EN')) {
2179 $chardata[$i]['type'] = 'EN';
2180 } elseif (($chardata[$i]['type'] == 'CS') AND ($chardata[($i-1)]['type'] == 'AN') AND ($chardata[($i+1)]['type'] == 'AN')) {
2181 $chardata[$i]['type'] = 'AN';
2182 }
2183 }
2184 if ($chardata[$i]['level'] != $prevlevel) {
2185 $levcount = 0;
2186 } else {
2187 ++$levcount;
2188 }
2189 $prevlevel = $chardata[$i]['level'];
2190 }
2191
2192 // W5. A sequence of European terminators adjacent to European numbers changes to all European numbers.
2193 $prevlevel = -1;
2194 $levcount = 0;
2195 for ($i=0; $i < $numchars; ++$i) {
2196 if ($chardata[$i]['type'] == 'ET') {
2197 if (($levcount > 0) AND ($chardata[($i-1)]['type'] == 'EN')) {
2198 $chardata[$i]['type'] = 'EN';
2199 } else {
2200 $j = $i+1;
2201 while (($j < $numchars) AND ($chardata[$j]['level'] == $prevlevel)) {
2202 if ($chardata[$j]['type'] == 'EN') {
2203 $chardata[$i]['type'] = 'EN';
2204 break;
2205 } elseif ($chardata[$j]['type'] != 'ET') {
2206 break;
2207 }
2208 ++$j;
2209 }
2210 }
2211 }
2212 if ($chardata[$i]['level'] != $prevlevel) {
2213 $levcount = 0;
2214 } else {
2215 ++$levcount;
2216 }
2217 $prevlevel = $chardata[$i]['level'];
2218 }
2219
2220 // W6. Otherwise, separators and terminators change to Other Neutral.
2221 $prevlevel = -1;
2222 $levcount = 0;
2223 for ($i=0; $i < $numchars; ++$i) {
2224 if (($chardata[$i]['type'] == 'ET') OR ($chardata[$i]['type'] == 'ES') OR ($chardata[$i]['type'] == 'CS')) {
2225 $chardata[$i]['type'] = 'ON';
2226 }
2227 if ($chardata[$i]['level'] != $prevlevel) {
2228 $levcount = 0;
2229 } else {
2230 ++$levcount;
2231 }
2232 $prevlevel = $chardata[$i]['level'];
2233 }
2234
2235 //W7. Search backward from each instance of a European number until the first strong type (R, L, or sor) is found. If an L is found, then change the type of the European number to L.
2236 $prevlevel = -1;
2237 $levcount = 0;
2238 for ($i=0; $i < $numchars; ++$i) {
2239 if ($chardata[$i]['char'] == 'EN') {
2240 for ($j=$levcount; $j >= 0; $j--) {
2241 if ($chardata[$j]['type'] == 'L') {
2242 $chardata[$i]['type'] = 'L';
2243 } elseif ($chardata[$j]['type'] == 'R') {
2244 break;
2245 }
2246 }
2247 }
2248 if ($chardata[$i]['level'] != $prevlevel) {
2249 $levcount = 0;
2250 } else {
2251 ++$levcount;
2252 }
2253 $prevlevel = $chardata[$i]['level'];
2254 }
2255
2256 // N1. A sequence of neutrals takes the direction of the surrounding strong text if the text on both sides has the same direction. European and Arabic numbers act as if they were R in terms of their influence on neutrals. Start-of-level-run (sor) and end-of-level-run (eor) are used at level run boundaries.
2257 $prevlevel = -1;
2258 $levcount = 0;
2259 for ($i=0; $i < $numchars; ++$i) {
2260 if (($levcount > 0) AND (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] == $prevlevel)) {
2261 if (($chardata[$i]['type'] == 'N') AND ($chardata[($i-1)]['type'] == 'L') AND ($chardata[($i+1)]['type'] == 'L')) {
2262 $chardata[$i]['type'] = 'L';
2263 } elseif (($chardata[$i]['type'] == 'N') AND
2264 (($chardata[($i-1)]['type'] == 'R') OR ($chardata[($i-1)]['type'] == 'EN') OR ($chardata[($i-1)]['type'] == 'AN')) AND
2265 (($chardata[($i+1)]['type'] == 'R') OR ($chardata[($i+1)]['type'] == 'EN') OR ($chardata[($i+1)]['type'] == 'AN'))) {
2266 $chardata[$i]['type'] = 'R';
2267 } elseif ($chardata[$i]['type'] == 'N') {
2268 // N2. Any remaining neutrals take the embedding direction
2269 $chardata[$i]['type'] = $chardata[$i]['sor'];
2270 }
2271 } elseif (($levcount == 0) AND (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] == $prevlevel)) {
2272 // first char
2273 if (($chardata[$i]['type'] == 'N') AND ($chardata[$i]['sor'] == 'L') AND ($chardata[($i+1)]['type'] == 'L')) {
2274 $chardata[$i]['type'] = 'L';
2275 } elseif (($chardata[$i]['type'] == 'N') AND
2276 (($chardata[$i]['sor'] == 'R') OR ($chardata[$i]['sor'] == 'EN') OR ($chardata[$i]['sor'] == 'AN')) AND
2277 (($chardata[($i+1)]['type'] == 'R') OR ($chardata[($i+1)]['type'] == 'EN') OR ($chardata[($i+1)]['type'] == 'AN'))) {
2278 $chardata[$i]['type'] = 'R';
2279 } elseif ($chardata[$i]['type'] == 'N') {
2280 // N2. Any remaining neutrals take the embedding direction
2281 $chardata[$i]['type'] = $chardata[$i]['sor'];
2282 }
2283 } elseif (($levcount > 0) AND ((($i+1) == $numchars) OR (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] != $prevlevel))) {
2284 //last char
2285 if (($chardata[$i]['type'] == 'N') AND ($chardata[($i-1)]['type'] == 'L') AND ($chardata[$i]['eor'] == 'L')) {
2286 $chardata[$i]['type'] = 'L';
2287 } elseif (($chardata[$i]['type'] == 'N') AND
2288 (($chardata[($i-1)]['type'] == 'R') OR ($chardata[($i-1)]['type'] == 'EN') OR ($chardata[($i-1)]['type'] == 'AN')) AND
2289 (($chardata[$i]['eor'] == 'R') OR ($chardata[$i]['eor'] == 'EN') OR ($chardata[$i]['eor'] == 'AN'))) {
2290 $chardata[$i]['type'] = 'R';
2291 } elseif ($chardata[$i]['type'] == 'N') {
2292 // N2. Any remaining neutrals take the embedding direction
2293 $chardata[$i]['type'] = $chardata[$i]['sor'];
2294 }
2295 } elseif ($chardata[$i]['type'] == 'N') {
2296 // N2. Any remaining neutrals take the embedding direction
2297 $chardata[$i]['type'] = $chardata[$i]['sor'];
2298 }
2299 if ($chardata[$i]['level'] != $prevlevel) {
2300 $levcount = 0;
2301 } else {
2302 ++$levcount;
2303 }
2304 $prevlevel = $chardata[$i]['level'];
2305 }
2306
2307 // I1. For all characters with an even (left-to-right) embedding direction, those of type R go up one level and those of type AN or EN go up two levels.
2308 // I2. For all characters with an odd (right-to-left) embedding direction, those of type L, EN or AN go up one level.
2309 for ($i=0; $i < $numchars; ++$i) {
2310 $odd = $chardata[$i]['level'] % 2;
2311 if ($odd) {
2312 if (($chardata[$i]['type'] == 'L') OR ($chardata[$i]['type'] == 'AN') OR ($chardata[$i]['type'] == 'EN')) {
2313 $chardata[$i]['level'] += 1;
2314 }
2315 } else {
2316 if ($chardata[$i]['type'] == 'R') {
2317 $chardata[$i]['level'] += 1;
2318 } elseif (($chardata[$i]['type'] == 'AN') OR ($chardata[$i]['type'] == 'EN')) {
2319 $chardata[$i]['level'] += 2;
2320 }
2321 }
2322 $maxlevel = max($chardata[$i]['level'],$maxlevel);
2323 }
2324
2325 // L1. On each line, reset the embedding level of the following characters to the paragraph embedding level:
2326 // 1. Segment separators,
2327 // 2. Paragraph separators,
2328 // 3. Any sequence of whitespace characters preceding a segment separator or paragraph separator, and
2329 // 4. Any sequence of white space characters at the end of the line.
2330 for ($i=0; $i < $numchars; ++$i) {
2331 if (($chardata[$i]['type'] == 'B') OR ($chardata[$i]['type'] == 'S')) {
2332 $chardata[$i]['level'] = $pel;
2333 } elseif ($chardata[$i]['type'] == 'WS') {
2334 $j = $i+1;
2335 while ($j < $numchars) {
2336 if ((($chardata[$j]['type'] == 'B') OR ($chardata[$j]['type'] == 'S')) OR
2337 (($j == ($numchars-1)) AND ($chardata[$j]['type'] == 'WS'))) {
2338 $chardata[$i]['level'] = $pel;
2339 break;
2340 } elseif ($chardata[$j]['type'] != 'WS') {
2341 break;
2342 }
2343 ++$j;
2344 }
2345 }
2346 }
2347
2348 // Arabic Shaping
2349 // Cursively connected scripts, such as Arabic or Syriac, require the selection of positional character shapes that depend on adjacent characters. Shaping is logically applied after the Bidirectional Algorithm is used and is limited to characters within the same directional run.
2350 if ($arabic) {
2351 $endedletter = array(1569,1570,1571,1572,1573,1575,1577,1583,1584,1585,1586,1608,1688);
2352 $alfletter = array(1570,1571,1573,1575);
2353 $chardata2 = $chardata;
2354 $laaletter = false;
2355 $charAL = array();
2356 $x = 0;
2357 for ($i=0; $i < $numchars; ++$i) {
2358 if ((TCPDF_FONT_DATA::$uni_type[$chardata[$i]['char']] == 'AL') OR ($chardata[$i]['char'] == 32) OR ($chardata[$i]['char'] == 8204)) {
2359 $charAL[$x] = $chardata[$i];
2360 $charAL[$x]['i'] = $i;
2361 $chardata[$i]['x'] = $x;
2362 ++$x;
2363 }
2364 }
2365 $numAL = $x;
2366 for ($i=0; $i < $numchars; ++$i) {
2367 $thischar = $chardata[$i];
2368 if ($i > 0) {
2369 $prevchar = $chardata[($i-1)];
2370 } else {
2371 $prevchar = false;
2372 }
2373 if (($i+1) < $numchars) {
2374 $nextchar = $chardata[($i+1)];
2375 } else {
2376 $nextchar = false;
2377 }
2378 if (TCPDF_FONT_DATA::$uni_type[$thischar['char']] == 'AL') {
2379 $x = $thischar['x'];
2380 if ($x > 0) {
2381 $prevchar = $charAL[($x-1)];
2382 } else {
2383 $prevchar = false;
2384 }
2385 if (($x+1) < $numAL) {
2386 $nextchar = $charAL[($x+1)];
2387 } else {
2388 $nextchar = false;
2389 }
2390 // if laa letter
2391 if (($prevchar !== false) AND ($prevchar['char'] == 1604) AND (in_array($thischar['char'], $alfletter))) {
2392 $arabicarr = TCPDF_FONT_DATA::$uni_laa_array;
2393 $laaletter = true;
2394 if ($x > 1) {
2395 $prevchar = $charAL[($x-2)];
2396 } else {
2397 $prevchar = false;
2398 }
2399 } else {
2400 $arabicarr = TCPDF_FONT_DATA::$uni_arabicsubst;
2401 $laaletter = false;
2402 }
2403 if (($prevchar !== false) AND ($nextchar !== false) AND
2404 ((TCPDF_FONT_DATA::$uni_type[$prevchar['char']] == 'AL') OR (TCPDF_FONT_DATA::$uni_type[$prevchar['char']] == 'NSM')) AND
2405 ((TCPDF_FONT_DATA::$uni_type[$nextchar['char']] == 'AL') OR (TCPDF_FONT_DATA::$uni_type[$nextchar['char']] == 'NSM')) AND
2406 ($prevchar['type'] == $thischar['type']) AND
2407 ($nextchar['type'] == $thischar['type']) AND
2408 ($nextchar['char'] != 1567)) {
2409 if (in_array($prevchar['char'], $endedletter)) {
2410 if (isset($arabicarr[$thischar['char']][2])) {
2411 // initial
2412 $chardata2[$i]['char'] = $arabicarr[$thischar['char']][2];
2413 }
2414 } else {
2415 if (isset($arabicarr[$thischar['char']][3])) {
2416 // medial
2417 $chardata2[$i]['char'] = $arabicarr[$thischar['char']][3];
2418 }
2419 }
2420 } elseif (($nextchar !== false) AND
2421 ((TCPDF_FONT_DATA::$uni_type[$nextchar['char']] == 'AL') OR (TCPDF_FONT_DATA::$uni_type[$nextchar['char']] == 'NSM')) AND
2422 ($nextchar['type'] == $thischar['type']) AND
2423 ($nextchar['char'] != 1567)) {
2424 if (isset($arabicarr[$chardata[$i]['char']][2])) {
2425 // initial
2426 $chardata2[$i]['char'] = $arabicarr[$thischar['char']][2];
2427 }
2428 } elseif ((($prevchar !== false) AND
2429 ((TCPDF_FONT_DATA::$uni_type[$prevchar['char']] == 'AL') OR (TCPDF_FONT_DATA::$uni_type[$prevchar['char']] == 'NSM')) AND
2430 ($prevchar['type'] == $thischar['type'])) OR
2431 (($nextchar !== false) AND ($nextchar['char'] == 1567))) {
2432 // final
2433 if (($i > 1) AND ($thischar['char'] == 1607) AND
2434 ($chardata[$i-1]['char'] == 1604) AND
2435 ($chardata[$i-2]['char'] == 1604)) {
2436 //Allah Word
2437 // mark characters to delete with false
2438 $chardata2[$i-2]['char'] = false;
2439 $chardata2[$i-1]['char'] = false;
2440 $chardata2[$i]['char'] = 65010;
2441 } else {
2442 if (($prevchar !== false) AND in_array($prevchar['char'], $endedletter)) {
2443 if (isset($arabicarr[$thischar['char']][0])) {
2444 // isolated
2445 $chardata2[$i]['char'] = $arabicarr[$thischar['char']][0];
2446 }
2447 } else {
2448 if (isset($arabicarr[$thischar['char']][1])) {
2449 // final
2450 $chardata2[$i]['char'] = $arabicarr[$thischar['char']][1];
2451 }
2452 }
2453 }
2454 } elseif (isset($arabicarr[$thischar['char']][0])) {
2455 // isolated
2456 $chardata2[$i]['char'] = $arabicarr[$thischar['char']][0];
2457 }
2458 // if laa letter
2459 if ($laaletter) {
2460 // mark characters to delete with false
2461 $chardata2[($charAL[($x-1)]['i'])]['char'] = false;
2462 }
2463 } // end if AL (Arabic Letter)
2464 } // end for each char
2465 /*
2466 * Combining characters that can occur with Arabic Shadda (0651 HEX, 1617 DEC) are replaced.
2467 * Putting the combining mark and shadda in the same glyph allows us to avoid the two marks overlapping each other in an illegible manner.
2468 */
2469 for ($i = 0; $i < ($numchars-1); ++$i) {
2470 if (($chardata2[$i]['char'] == 1617) AND (isset(TCPDF_FONT_DATA::$uni_diacritics[($chardata2[$i+1]['char'])]))) {
2471 // check if the subtitution font is defined on current font
2472 if (isset($currentfont['cw'][(TCPDF_FONT_DATA::$uni_diacritics[($chardata2[$i+1]['char'])])])) {
2473 $chardata2[$i]['char'] = false;
2474 $chardata2[$i+1]['char'] = TCPDF_FONT_DATA::$uni_diacritics[($chardata2[$i+1]['char'])];
2475 }
2476 }
2477 }
2478 // remove marked characters
2479 foreach ($chardata2 as $key => $value) {
2480 if ($value['char'] === false) {
2481 unset($chardata2[$key]);
2482 }
2483 }
2484 $chardata = array_values($chardata2);
2485 $numchars = count($chardata);
2486 unset($chardata2);
2487 unset($arabicarr);
2488 unset($laaletter);
2489 unset($charAL);
2490 }
2491
2492 // L2. From the highest level found in the text to the lowest odd level on each line, including intermediate levels not actually present in the text, reverse any contiguous sequence of characters that are at that level or higher.
2493 for ($j=$maxlevel; $j > 0; $j--) {
2494 $ordarray = Array();
2495 $revarr = Array();
2496 $onlevel = false;
2497 for ($i=0; $i < $numchars; ++$i) {
2498 if ($chardata[$i]['level'] >= $j) {
2499 $onlevel = true;
2500 if (isset(TCPDF_FONT_DATA::$uni_mirror[$chardata[$i]['char']])) {
2501 // L4. A character is depicted by a mirrored glyph if and only if (a) the resolved directionality of that character is R, and (b) the Bidi_Mirrored property value of that character is true.
2502 $chardata[$i]['char'] = TCPDF_FONT_DATA::$uni_mirror[$chardata[$i]['char']];
2503 }
2504 $revarr[] = $chardata[$i];
2505 } else {
2506 if ($onlevel) {
2507 $revarr = array_reverse($revarr);
2508 $ordarray = array_merge($ordarray, $revarr);
2509 $revarr = Array();
2510 $onlevel = false;
2511 }
2512 $ordarray[] = $chardata[$i];
2513 }
2514 }
2515 if ($onlevel) {
2516 $revarr = array_reverse($revarr);
2517 $ordarray = array_merge($ordarray, $revarr);
2518 }
2519 $chardata = $ordarray;
2520 }
2521 $ordarray = array();
2522 foreach ($chardata as $cd) {
2523 $ordarray[] = $cd['char'];
2524 // store char values for subsetting
2525 $currentfont['subsetchars'][$cd['char']] = true;
2526 }
2527 return $ordarray;
2528 }
2529
2530 /**
2531 * Get a reference font size.
2532 * @param $size (string) String containing font size value.
2533 * @param $refsize (float) Reference font size in points.
2534 * @return float value in points
2535 * @public static
2536 */
2537 public static function getFontRefSize($size, $refsize=12) {
2538 switch ($size) {
2539 case 'xx-small': {
2540 $size = ($refsize - 4);
2541 break;
2542 }
2543 case 'x-small': {
2544 $size = ($refsize - 3);
2545 break;
2546 }
2547 case 'small': {
2548 $size = ($refsize - 2);
2549 break;
2550 }
2551 case 'medium': {
2552 $size = $refsize;
2553 break;
2554 }
2555 case 'large': {
2556 $size = ($refsize + 2);
2557 break;
2558 }
2559 case 'x-large': {
2560 $size = ($refsize + 4);
2561 break;
2562 }
2563 case 'xx-large': {
2564 $size = ($refsize + 6);
2565 break;
2566 }
2567 case 'smaller': {
2568 $size = ($refsize - 3);
2569 break;
2570 }
2571 case 'larger': {
2572 $size = ($refsize + 3);
2573 break;
2574 }
2575 }
2576 return $size;
2577 }
2578
2579} // END OF TCPDF_FONTS CLASS
2580
2581//============================================================+
2582// END OF FILE
2583//============================================================+
diff --git a/inc/3rdparty/libraries/tcpdf/include/tcpdf_images.php b/inc/3rdparty/libraries/tcpdf/include/tcpdf_images.php
new file mode 100644
index 00000000..150832ef
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/include/tcpdf_images.php
@@ -0,0 +1,355 @@
1<?php
2//============================================================+
3// File name : tcpdf_images.php
4// Version : 1.0.003
5// Begin : 2002-08-03
6// Last Update : 2014-04-03
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-2014 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 image methods used by the TCPDF class.
33//
34//============================================================+
35
36/**
37 * @file
38 * This is a PHP class that contains static image methods for the TCPDF class.<br>
39 * @package com.tecnick.tcpdf
40 * @author Nicola Asuni
41 * @version 1.0.003
42 */
43
44/**
45 * @class TCPDF_IMAGES
46 * Static image methods used by the TCPDF class.
47 * @package com.tecnick.tcpdf
48 * @brief PHP class for generating PDF documents without requiring external extensions.
49 * @version 1.0.003
50 * @author Nicola Asuni - info@tecnick.com
51 */
52class TCPDF_IMAGES {
53
54 /**
55 * Array of hinheritable SVG properties.
56 * @since 5.0.000 (2010-05-02)
57 * @public static
58 */
59 public static $svginheritprop = array('clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cursor', 'direction', 'fill', 'fill-opacity', 'fill-rule', 'font', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'glyph-orientation-horizontal', 'glyph-orientation-vertical', 'image-rendering', 'kerning', 'letter-spacing', 'marker', 'marker-end', 'marker-mid', 'marker-start', 'pointer-events', 'shape-rendering', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'text-anchor', 'text-rendering', 'visibility', 'word-spacing', 'writing-mode');
60
61// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
62
63 /**
64 * Return the image type given the file name or array returned by getimagesize() function.
65 * @param $imgfile (string) image file name
66 * @param $iminfo (array) array of image information returned by getimagesize() function.
67 * @return string image type
68 * @since 4.8.017 (2009-11-27)
69 * @public static
70 */
71 public static function getImageFileType($imgfile, $iminfo=array()) {
72 $type = '';
73 if (isset($iminfo['mime']) AND !empty($iminfo['mime'])) {
74 $mime = explode('/', $iminfo['mime']);
75 if ((count($mime) > 1) AND ($mime[0] == 'image') AND (!empty($mime[1]))) {
76 $type = strtolower(trim($mime[1]));
77 }
78 }
79 if (empty($type)) {
80 $fileinfo = pathinfo($imgfile);
81 if (isset($fileinfo['extension']) AND (!TCPDF_STATIC::empty_string($fileinfo['extension']))) {
82 $type = strtolower(trim($fileinfo['extension']));
83 }
84 }
85 if ($type == 'jpg') {
86 $type = 'jpeg';
87 }
88 return $type;
89 }
90
91 /**
92 * Set the transparency for the given GD image.
93 * @param $new_image (image) GD image object
94 * @param $image (image) GD image object.
95 * return GD image object.
96 * @since 4.9.016 (2010-04-20)
97 * @public static
98 */
99 public static function setGDImageTransparency($new_image, $image) {
100 // transparency index
101 $tid = imagecolortransparent($image);
102 // default transparency color
103 $tcol = array('red' => 255, 'green' => 255, 'blue' => 255);
104 if ($tid >= 0) {
105 // get the colors for the transparency index
106 $tcol = imagecolorsforindex($image, $tid);
107 }
108 $tid = imagecolorallocate($new_image, $tcol['red'], $tcol['green'], $tcol['blue']);
109 imagefill($new_image, 0, 0, $tid);
110 imagecolortransparent($new_image, $tid);
111 return $new_image;
112 }
113
114 /**
115 * Convert the loaded image to a PNG and then return a structure for the PDF creator.
116 * This function requires GD library and write access to the directory defined on K_PATH_CACHE constant.
117 * @param $image (image) Image object.
118 * return image PNG image object.
119 * @since 4.9.016 (2010-04-20)
120 * @public static
121 */
122 public static function _toPNG($image) {
123 // set temporary image file name
124 $tempname = TCPDF_STATIC::getObjFilename('img');
125 // turn off interlaced mode
126 imageinterlace($image, 0);
127 // create temporary PNG image
128 imagepng($image, $tempname);
129 // remove image from memory
130 imagedestroy($image);
131 // get PNG image data
132 $retvars = self::_parsepng($tempname);
133 // tidy up by removing temporary image
134 unlink($tempname);
135 return $retvars;
136 }
137
138 /**
139 * Convert the loaded image to a JPEG and then return a structure for the PDF creator.
140 * This function requires GD library and write access to the directory defined on K_PATH_CACHE constant.
141 * @param $image (image) Image object.
142 * @param $quality (int) JPEG quality.
143 * return image JPEG image object.
144 * @public static
145 */
146 public static function _toJPEG($image, $quality) {
147 $tempname = TCPDF_STATIC::getObjFilename('img');
148 imagejpeg($image, $tempname, $quality);
149 imagedestroy($image);
150 $retvars = self::_parsejpeg($tempname);
151 // tidy up by removing temporary image
152 unlink($tempname);
153 return $retvars;
154 }
155
156 /**
157 * Extract info from a JPEG file without using the GD library.
158 * @param $file (string) image file to parse
159 * @return array structure containing the image data
160 * @public static
161 */
162 public static function _parsejpeg($file) {
163 $a = getimagesize($file);
164 if (empty($a)) {
165 //Missing or incorrect image file
166 return false;
167 }
168 if ($a[2] != 2) {
169 // Not a JPEG file
170 return false;
171 }
172 // bits per pixel
173 $bpc = isset($a['bits']) ? intval($a['bits']) : 8;
174 // number of image channels
175 if (!isset($a['channels'])) {
176 $channels = 3;
177 } else {
178 $channels = intval($a['channels']);
179 }
180 // default colour space
181 switch ($channels) {
182 case 1: {
183 $colspace = 'DeviceGray';
184 break;
185 }
186 case 3: {
187 $colspace = 'DeviceRGB';
188 break;
189 }
190 case 4: {
191 $colspace = 'DeviceCMYK';
192 break;
193 }
194 default: {
195 $channels = 3;
196 $colspace = 'DeviceRGB';
197 break;
198 }
199 }
200 // get file content
201 $data = file_get_contents($file);
202 // check for embedded ICC profile
203 $icc = array();
204 $offset = 0;
205 while (($pos = strpos($data, "ICC_PROFILE\0", $offset)) !== false) {
206 // get ICC sequence length
207 $length = (TCPDF_STATIC::_getUSHORT($data, ($pos - 2)) - 16);
208 // marker sequence number
209 $msn = max(1, ord($data[($pos + 12)]));
210 // number of markers (total of APP2 used)
211 $nom = max(1, ord($data[($pos + 13)]));
212 // get sequence segment
213 $icc[($msn - 1)] = substr($data, ($pos + 14), $length);
214 // move forward to next sequence
215 $offset = ($pos + 14 + $length);
216 }
217 // order and compact ICC segments
218 if (count($icc) > 0) {
219 ksort($icc);
220 $icc = implode('', $icc);
221 if ((ord($icc[36]) != 0x61) OR (ord($icc[37]) != 0x63) OR (ord($icc[38]) != 0x73) OR (ord($icc[39]) != 0x70)) {
222 // invalid ICC profile
223 $icc = false;
224 }
225 } else {
226 $icc = false;
227 }
228 return array('w' => $a[0], 'h' => $a[1], 'ch' => $channels, 'icc' => $icc, 'cs' => $colspace, 'bpc' => $bpc, 'f' => 'DCTDecode', 'data' => $data);
229 }
230
231 /**
232 * Extract info from a PNG file without using the GD library.
233 * @param $file (string) image file to parse
234 * @return array structure containing the image data
235 * @public static
236 */
237 public static function _parsepng($file) {
238 $f = @fopen($file, 'rb');
239 if ($f === false) {
240 // Can't open image file
241 return false;
242 }
243 //Check signature
244 if (fread($f, 8) != chr(137).'PNG'.chr(13).chr(10).chr(26).chr(10)) {
245 // Not a PNG file
246 return false;
247 }
248 //Read header chunk
249 fread($f, 4);
250 if (fread($f, 4) != 'IHDR') {
251 //Incorrect PNG file
252 return false;
253 }
254 $w = TCPDF_STATIC::_freadint($f);
255 $h = TCPDF_STATIC::_freadint($f);
256 $bpc = ord(fread($f, 1));
257 $ct = ord(fread($f, 1));
258 if ($ct == 0) {
259 $colspace = 'DeviceGray';
260 } elseif ($ct == 2) {
261 $colspace = 'DeviceRGB';
262 } elseif ($ct == 3) {
263 $colspace = 'Indexed';
264 } else {
265 // alpha channel
266 fclose($f);
267 return 'pngalpha';
268 }
269 if (ord(fread($f, 1)) != 0) {
270 // Unknown compression method
271 fclose($f);
272 return false;
273 }
274 if (ord(fread($f, 1)) != 0) {
275 // Unknown filter method
276 fclose($f);
277 return false;
278 }
279 if (ord(fread($f, 1)) != 0) {
280 // Interlacing not supported
281 fclose($f);
282 return false;
283 }
284 fread($f, 4);
285 $channels = ($ct == 2 ? 3 : 1);
286 $parms = '/DecodeParms << /Predictor 15 /Colors '.$channels.' /BitsPerComponent '.$bpc.' /Columns '.$w.' >>';
287 //Scan chunks looking for palette, transparency and image data
288 $pal = '';
289 $trns = '';
290 $data = '';
291 $icc = false;
292 do {
293 $n = TCPDF_STATIC::_freadint($f);
294 $type = fread($f, 4);
295 if ($type == 'PLTE') {
296 // read palette
297 $pal = TCPDF_STATIC::rfread($f, $n);
298 fread($f, 4);
299 } elseif ($type == 'tRNS') {
300 // read transparency info
301 $t = TCPDF_STATIC::rfread($f, $n);
302 if ($ct == 0) { // DeviceGray
303 $trns = array(ord($t[1]));
304 } elseif ($ct == 2) { // DeviceRGB
305 $trns = array(ord($t[1]), ord($t[3]), ord($t[5]));
306 } else { // Indexed
307 if ($n > 0) {
308 $trns = array();
309 for ($i = 0; $i < $n; ++ $i) {
310 $trns[] = ord($t{$i});
311 }
312 }
313 }
314 fread($f, 4);
315 } elseif ($type == 'IDAT') {
316 // read image data block
317 $data .= TCPDF_STATIC::rfread($f, $n);
318 fread($f, 4);
319 } elseif ($type == 'iCCP') {
320 // skip profile name
321 $len = 0;
322 while ((ord(fread($f, 1)) != 0) AND ($len < 80)) {
323 ++$len;
324 }
325 // get compression method
326 if (ord(fread($f, 1)) != 0) {
327 // Unknown filter method
328 fclose($f);
329 return false;
330 }
331 // read ICC Color Profile
332 $icc = TCPDF_STATIC::rfread($f, ($n - $len - 2));
333 // decompress profile
334 $icc = gzuncompress($icc);
335 fread($f, 4);
336 } elseif ($type == 'IEND') {
337 break;
338 } else {
339 TCPDF_STATIC::rfread($f, $n + 4);
340 }
341 } while ($n);
342 if (($colspace == 'Indexed') AND (empty($pal))) {
343 // Missing palette
344 fclose($f);
345 return false;
346 }
347 fclose($f);
348 return array('w' => $w, 'h' => $h, 'ch' => $channels, 'icc' => $icc, 'cs' => $colspace, 'bpc' => $bpc, 'f' => 'FlateDecode', 'parms' => $parms, 'pal' => $pal, 'trns' => $trns, 'data' => $data);
349 }
350
351} // END OF TCPDF_IMAGES CLASS
352
353//============================================================+
354// END OF FILE
355//============================================================+
diff --git a/inc/3rdparty/libraries/tcpdf/include/tcpdf_static.php b/inc/3rdparty/libraries/tcpdf/include/tcpdf_static.php
new file mode 100644
index 00000000..e657446a
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/include/tcpdf_static.php
@@ -0,0 +1,2851 @@
1<?php
2//============================================================+
3// File name : tcpdf_static.php
4// Version : 1.0.004
5// Begin : 2002-08-03
6// Last Update : 2014-09-02
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-2014 Nicola Asuni - Tecnick.com LTD
11//
12// This file is part of TCPDF software library.
13//
14// TCPDF is free software: you can redistribute it and/or modify it
15// under the terms of the GNU Lesser General Public License as
16// published by the Free Software Foundation, either version 3 of the
17// License, or (at your option) any later version.
18//
19// TCPDF is distributed in the hope that it will be useful, but
20// WITHOUT ANY WARRANTY; without even the implied warranty of
21// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22// See the GNU Lesser General Public License for more details.
23//
24// You should have received a copy of the License
25// along with TCPDF. If not, see
26// <http://www.tecnick.com/pagefiles/tcpdf/LICENSE.TXT>.
27//
28// See LICENSE.TXT file for more information.
29// -------------------------------------------------------------------
30//
31// Description :
32// Static methods used by the TCPDF class.
33//
34//============================================================+
35
36/**
37 * @file
38 * This is a PHP class that contains static methods for the TCPDF class.<br>
39 * @package com.tecnick.tcpdf
40 * @author Nicola Asuni
41 * @version 1.0.004
42 */
43
44/**
45 * @class TCPDF_STATIC
46 * Static methods used by the TCPDF class.
47 * @package com.tecnick.tcpdf
48 * @brief PHP class for generating PDF documents without requiring external extensions.
49 * @version 1.0.004
50 * @author Nicola Asuni - info@tecnick.com
51 */
52class TCPDF_STATIC {
53
54 /**
55 * Current TCPDF version.
56 * @private static
57 */
58 private static $tcpdf_version = '6.0.093';
59
60 /**
61 * String alias for total number of pages.
62 * @public static
63 */
64 public static $alias_tot_pages = '{:ptp:}';
65
66 /**
67 * String alias for page number.
68 * @public static
69 */
70 public static $alias_num_page = '{:pnp:}';
71
72 /**
73 * String alias for total number of pages in a single group.
74 * @public static
75 */
76 public static $alias_group_tot_pages = '{:ptg:}';
77
78 /**
79 * String alias for group page number.
80 * @public static
81 */
82 public static $alias_group_num_page = '{:png:}';
83
84 /**
85 * String alias for right shift compensation used to correctly align page numbers on the right.
86 * @public static
87 */
88 public static $alias_right_shift = '{rsc:';
89
90 /**
91 * Encryption padding string.
92 * @public static
93 */
94 public static $enc_padding = "\x28\xBF\x4E\x5E\x4E\x75\x8A\x41\x64\x00\x4E\x56\xFF\xFA\x01\x08\x2E\x2E\x00\xB6\xD0\x68\x3E\x80\x2F\x0C\xA9\xFE\x64\x53\x69\x7A";
95
96 /**
97 * ByteRange placemark used during digital signature process.
98 * @since 4.6.028 (2009-08-25)
99 * @public static
100 */
101 public static $byterange_string = '/ByteRange[0 ********** ********** **********]';
102
103 /**
104 * Array page boxes names
105 * @public static
106 */
107 public static $pageboxes = array('MediaBox', 'CropBox', 'BleedBox', 'TrimBox', 'ArtBox');
108
109 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
110
111 /**
112 * Return the current TCPDF version.
113 * @return TCPDF version string
114 * @since 5.9.012 (2010-11-10)
115 * @public static
116 */
117 public static function getTCPDFVersion() {
118 return self::$tcpdf_version;
119 }
120
121 /**
122 * Return the current TCPDF producer.
123 * @return TCPDF producer string
124 * @since 6.0.000 (2013-03-16)
125 * @public static
126 */
127 public static function getTCPDFProducer() {
128 return "\x54\x43\x50\x44\x46\x20".self::getTCPDFVersion()."\x20\x28\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x74\x63\x70\x64\x66\x2e\x6f\x72\x67\x29";
129 }
130
131 /**
132 * Sets the current active configuration setting of magic_quotes_runtime (if the set_magic_quotes_runtime function exist)
133 * @param $mqr (boolean) FALSE for off, TRUE for on.
134 * @since 4.6.025 (2009-08-17)
135 * @public static
136 */
137 public static function set_mqr($mqr) {
138 if (!defined('PHP_VERSION_ID')) {
139 $version = PHP_VERSION;
140 define('PHP_VERSION_ID', (($version[0] * 10000) + ($version[2] * 100) + $version[4]));
141 }
142 if (PHP_VERSION_ID < 50300) {
143 @set_magic_quotes_runtime($mqr);
144 }
145 }
146
147 /**
148 * Gets the current active configuration setting of magic_quotes_runtime (if the get_magic_quotes_runtime function exist)
149 * @return Returns 0 if magic quotes runtime is off or get_magic_quotes_runtime doesn't exist, 1 otherwise.
150 * @since 4.6.025 (2009-08-17)
151 * @public static
152 */
153 public static function get_mqr() {
154 if (!defined('PHP_VERSION_ID')) {
155 $version = PHP_VERSION;
156 define('PHP_VERSION_ID', (($version[0] * 10000) + ($version[2] * 100) + $version[4]));
157 }
158 if (PHP_VERSION_ID < 50300) {
159 return @get_magic_quotes_runtime();
160 }
161 return 0;
162 }
163
164 /**
165 * Get page dimensions from format name.
166 * @param $format (mixed) The format name. It can be: <ul>
167 * <li><b>ISO 216 A Series + 2 SIS 014711 extensions</b></li>
168 * <li>A0 (841x1189 mm ; 33.11x46.81 in)</li>
169 * <li>A1 (594x841 mm ; 23.39x33.11 in)</li>
170 * <li>A2 (420x594 mm ; 16.54x23.39 in)</li>
171 * <li>A3 (297x420 mm ; 11.69x16.54 in)</li>
172 * <li>A4 (210x297 mm ; 8.27x11.69 in)</li>
173 * <li>A5 (148x210 mm ; 5.83x8.27 in)</li>
174 * <li>A6 (105x148 mm ; 4.13x5.83 in)</li>
175 * <li>A7 (74x105 mm ; 2.91x4.13 in)</li>
176 * <li>A8 (52x74 mm ; 2.05x2.91 in)</li>
177 * <li>A9 (37x52 mm ; 1.46x2.05 in)</li>
178 * <li>A10 (26x37 mm ; 1.02x1.46 in)</li>
179 * <li>A11 (18x26 mm ; 0.71x1.02 in)</li>
180 * <li>A12 (13x18 mm ; 0.51x0.71 in)</li>
181 * <li><b>ISO 216 B Series + 2 SIS 014711 extensions</b></li>
182 * <li>B0 (1000x1414 mm ; 39.37x55.67 in)</li>
183 * <li>B1 (707x1000 mm ; 27.83x39.37 in)</li>
184 * <li>B2 (500x707 mm ; 19.69x27.83 in)</li>
185 * <li>B3 (353x500 mm ; 13.90x19.69 in)</li>
186 * <li>B4 (250x353 mm ; 9.84x13.90 in)</li>
187 * <li>B5 (176x250 mm ; 6.93x9.84 in)</li>
188 * <li>B6 (125x176 mm ; 4.92x6.93 in)</li>
189 * <li>B7 (88x125 mm ; 3.46x4.92 in)</li>
190 * <li>B8 (62x88 mm ; 2.44x3.46 in)</li>
191 * <li>B9 (44x62 mm ; 1.73x2.44 in)</li>
192 * <li>B10 (31x44 mm ; 1.22x1.73 in)</li>
193 * <li>B11 (22x31 mm ; 0.87x1.22 in)</li>
194 * <li>B12 (15x22 mm ; 0.59x0.87 in)</li>
195 * <li><b>ISO 216 C Series + 2 SIS 014711 extensions + 2 EXTENSION</b></li>
196 * <li>C0 (917x1297 mm ; 36.10x51.06 in)</li>
197 * <li>C1 (648x917 mm ; 25.51x36.10 in)</li>
198 * <li>C2 (458x648 mm ; 18.03x25.51 in)</li>
199 * <li>C3 (324x458 mm ; 12.76x18.03 in)</li>
200 * <li>C4 (229x324 mm ; 9.02x12.76 in)</li>
201 * <li>C5 (162x229 mm ; 6.38x9.02 in)</li>
202 * <li>C6 (114x162 mm ; 4.49x6.38 in)</li>
203 * <li>C7 (81x114 mm ; 3.19x4.49 in)</li>
204 * <li>C8 (57x81 mm ; 2.24x3.19 in)</li>
205 * <li>C9 (40x57 mm ; 1.57x2.24 in)</li>
206 * <li>C10 (28x40 mm ; 1.10x1.57 in)</li>
207 * <li>C11 (20x28 mm ; 0.79x1.10 in)</li>
208 * <li>C12 (14x20 mm ; 0.55x0.79 in)</li>
209 * <li>C76 (81x162 mm ; 3.19x6.38 in)</li>
210 * <li>DL (110x220 mm ; 4.33x8.66 in)</li>
211 * <li><b>SIS 014711 E Series</b></li>
212 * <li>E0 (879x1241 mm ; 34.61x48.86 in)</li>
213 * <li>E1 (620x879 mm ; 24.41x34.61 in)</li>
214 * <li>E2 (440x620 mm ; 17.32x24.41 in)</li>
215 * <li>E3 (310x440 mm ; 12.20x17.32 in)</li>
216 * <li>E4 (220x310 mm ; 8.66x12.20 in)</li>
217 * <li>E5 (155x220 mm ; 6.10x8.66 in)</li>
218 * <li>E6 (110x155 mm ; 4.33x6.10 in)</li>
219 * <li>E7 (78x110 mm ; 3.07x4.33 in)</li>
220 * <li>E8 (55x78 mm ; 2.17x3.07 in)</li>
221 * <li>E9 (39x55 mm ; 1.54x2.17 in)</li>
222 * <li>E10 (27x39 mm ; 1.06x1.54 in)</li>
223 * <li>E11 (19x27 mm ; 0.75x1.06 in)</li>
224 * <li>E12 (13x19 mm ; 0.51x0.75 in)</li>
225 * <li><b>SIS 014711 G Series</b></li>
226 * <li>G0 (958x1354 mm ; 37.72x53.31 in)</li>
227 * <li>G1 (677x958 mm ; 26.65x37.72 in)</li>
228 * <li>G2 (479x677 mm ; 18.86x26.65 in)</li>
229 * <li>G3 (338x479 mm ; 13.31x18.86 in)</li>
230 * <li>G4 (239x338 mm ; 9.41x13.31 in)</li>
231 * <li>G5 (169x239 mm ; 6.65x9.41 in)</li>
232 * <li>G6 (119x169 mm ; 4.69x6.65 in)</li>
233 * <li>G7 (84x119 mm ; 3.31x4.69 in)</li>
234 * <li>G8 (59x84 mm ; 2.32x3.31 in)</li>
235 * <li>G9 (42x59 mm ; 1.65x2.32 in)</li>
236 * <li>G10 (29x42 mm ; 1.14x1.65 in)</li>
237 * <li>G11 (21x29 mm ; 0.83x1.14 in)</li>
238 * <li>G12 (14x21 mm ; 0.55x0.83 in)</li>
239 * <li><b>ISO Press</b></li>
240 * <li>RA0 (860x1220 mm ; 33.86x48.03 in)</li>
241 * <li>RA1 (610x860 mm ; 24.02x33.86 in)</li>
242 * <li>RA2 (430x610 mm ; 16.93x24.02 in)</li>
243 * <li>RA3 (305x430 mm ; 12.01x16.93 in)</li>
244 * <li>RA4 (215x305 mm ; 8.46x12.01 in)</li>
245 * <li>SRA0 (900x1280 mm ; 35.43x50.39 in)</li>
246 * <li>SRA1 (640x900 mm ; 25.20x35.43 in)</li>
247 * <li>SRA2 (450x640 mm ; 17.72x25.20 in)</li>
248 * <li>SRA3 (320x450 mm ; 12.60x17.72 in)</li>
249 * <li>SRA4 (225x320 mm ; 8.86x12.60 in)</li>
250 * <li><b>German DIN 476</b></li>
251 * <li>4A0 (1682x2378 mm ; 66.22x93.62 in)</li>
252 * <li>2A0 (1189x1682 mm ; 46.81x66.22 in)</li>
253 * <li><b>Variations on the ISO Standard</b></li>
254 * <li>A2_EXTRA (445x619 mm ; 17.52x24.37 in)</li>
255 * <li>A3+ (329x483 mm ; 12.95x19.02 in)</li>
256 * <li>A3_EXTRA (322x445 mm ; 12.68x17.52 in)</li>
257 * <li>A3_SUPER (305x508 mm ; 12.01x20.00 in)</li>
258 * <li>SUPER_A3 (305x487 mm ; 12.01x19.17 in)</li>
259 * <li>A4_EXTRA (235x322 mm ; 9.25x12.68 in)</li>
260 * <li>A4_SUPER (229x322 mm ; 9.02x12.68 in)</li>
261 * <li>SUPER_A4 (227x356 mm ; 8.94x14.02 in)</li>
262 * <li>A4_LONG (210x348 mm ; 8.27x13.70 in)</li>
263 * <li>F4 (210x330 mm ; 8.27x12.99 in)</li>
264 * <li>SO_B5_EXTRA (202x276 mm ; 7.95x10.87 in)</li>
265 * <li>A5_EXTRA (173x235 mm ; 6.81x9.25 in)</li>
266 * <li><b>ANSI Series</b></li>
267 * <li>ANSI_E (864x1118 mm ; 34.00x44.00 in)</li>
268 * <li>ANSI_D (559x864 mm ; 22.00x34.00 in)</li>
269 * <li>ANSI_C (432x559 mm ; 17.00x22.00 in)</li>
270 * <li>ANSI_B (279x432 mm ; 11.00x17.00 in)</li>
271 * <li>ANSI_A (216x279 mm ; 8.50x11.00 in)</li>
272 * <li><b>Traditional 'Loose' North American Paper Sizes</b></li>
273 * <li>LEDGER, USLEDGER (432x279 mm ; 17.00x11.00 in)</li>
274 * <li>TABLOID, USTABLOID, BIBLE, ORGANIZERK (279x432 mm ; 11.00x17.00 in)</li>
275 * <li>LETTER, USLETTER, ORGANIZERM (216x279 mm ; 8.50x11.00 in)</li>
276 * <li>LEGAL, USLEGAL (216x356 mm ; 8.50x14.00 in)</li>
277 * <li>GLETTER, GOVERNMENTLETTER (203x267 mm ; 8.00x10.50 in)</li>
278 * <li>JLEGAL, JUNIORLEGAL (203x127 mm ; 8.00x5.00 in)</li>
279 * <li><b>Other North American Paper Sizes</b></li>
280 * <li>QUADDEMY (889x1143 mm ; 35.00x45.00 in)</li>
281 * <li>SUPER_B (330x483 mm ; 13.00x19.00 in)</li>
282 * <li>QUARTO (229x279 mm ; 9.00x11.00 in)</li>
283 * <li>FOLIO, GOVERNMENTLEGAL (216x330 mm ; 8.50x13.00 in)</li>
284 * <li>EXECUTIVE, MONARCH (184x267 mm ; 7.25x10.50 in)</li>
285 * <li>MEMO, STATEMENT, ORGANIZERL (140x216 mm ; 5.50x8.50 in)</li>
286 * <li>FOOLSCAP (210x330 mm ; 8.27x13.00 in)</li>
287 * <li>COMPACT (108x171 mm ; 4.25x6.75 in)</li>
288 * <li>ORGANIZERJ (70x127 mm ; 2.75x5.00 in)</li>
289 * <li><b>Canadian standard CAN 2-9.60M</b></li>
290 * <li>P1 (560x860 mm ; 22.05x33.86 in)</li>
291 * <li>P2 (430x560 mm ; 16.93x22.05 in)</li>
292 * <li>P3 (280x430 mm ; 11.02x16.93 in)</li>
293 * <li>P4 (215x280 mm ; 8.46x11.02 in)</li>
294 * <li>P5 (140x215 mm ; 5.51x8.46 in)</li>
295 * <li>P6 (107x140 mm ; 4.21x5.51 in)</li>
296 * <li><b>North American Architectural Sizes</b></li>
297 * <li>ARCH_E (914x1219 mm ; 36.00x48.00 in)</li>
298 * <li>ARCH_E1 (762x1067 mm ; 30.00x42.00 in)</li>
299 * <li>ARCH_D (610x914 mm ; 24.00x36.00 in)</li>
300 * <li>ARCH_C, BROADSHEET (457x610 mm ; 18.00x24.00 in)</li>
301 * <li>ARCH_B (305x457 mm ; 12.00x18.00 in)</li>
302 * <li>ARCH_A (229x305 mm ; 9.00x12.00 in)</li>
303 * <li><b>Announcement Envelopes</b></li>
304 * <li>ANNENV_A2 (111x146 mm ; 4.37x5.75 in)</li>
305 * <li>ANNENV_A6 (121x165 mm ; 4.75x6.50 in)</li>
306 * <li>ANNENV_A7 (133x184 mm ; 5.25x7.25 in)</li>
307 * <li>ANNENV_A8 (140x206 mm ; 5.50x8.12 in)</li>
308 * <li>ANNENV_A10 (159x244 mm ; 6.25x9.62 in)</li>
309 * <li>ANNENV_SLIM (98x225 mm ; 3.87x8.87 in)</li>
310 * <li><b>Commercial Envelopes</b></li>
311 * <li>COMMENV_N6_1/4 (89x152 mm ; 3.50x6.00 in)</li>
312 * <li>COMMENV_N6_3/4 (92x165 mm ; 3.62x6.50 in)</li>
313 * <li>COMMENV_N8 (98x191 mm ; 3.87x7.50 in)</li>
314 * <li>COMMENV_N9 (98x225 mm ; 3.87x8.87 in)</li>
315 * <li>COMMENV_N10 (105x241 mm ; 4.12x9.50 in)</li>
316 * <li>COMMENV_N11 (114x263 mm ; 4.50x10.37 in)</li>
317 * <li>COMMENV_N12 (121x279 mm ; 4.75x11.00 in)</li>
318 * <li>COMMENV_N14 (127x292 mm ; 5.00x11.50 in)</li>
319 * <li><b>Catalogue Envelopes</b></li>
320 * <li>CATENV_N1 (152x229 mm ; 6.00x9.00 in)</li>
321 * <li>CATENV_N1_3/4 (165x241 mm ; 6.50x9.50 in)</li>
322 * <li>CATENV_N2 (165x254 mm ; 6.50x10.00 in)</li>
323 * <li>CATENV_N3 (178x254 mm ; 7.00x10.00 in)</li>
324 * <li>CATENV_N6 (191x267 mm ; 7.50x10.50 in)</li>
325 * <li>CATENV_N7 (203x279 mm ; 8.00x11.00 in)</li>
326 * <li>CATENV_N8 (210x286 mm ; 8.25x11.25 in)</li>
327 * <li>CATENV_N9_1/2 (216x267 mm ; 8.50x10.50 in)</li>
328 * <li>CATENV_N9_3/4 (222x286 mm ; 8.75x11.25 in)</li>
329 * <li>CATENV_N10_1/2 (229x305 mm ; 9.00x12.00 in)</li>
330 * <li>CATENV_N12_1/2 (241x318 mm ; 9.50x12.50 in)</li>
331 * <li>CATENV_N13_1/2 (254x330 mm ; 10.00x13.00 in)</li>
332 * <li>CATENV_N14_1/4 (286x311 mm ; 11.25x12.25 in)</li>
333 * <li>CATENV_N14_1/2 (292x368 mm ; 11.50x14.50 in)</li>
334 * <li><b>Japanese (JIS P 0138-61) Standard B-Series</b></li>
335 * <li>JIS_B0 (1030x1456 mm ; 40.55x57.32 in)</li>
336 * <li>JIS_B1 (728x1030 mm ; 28.66x40.55 in)</li>
337 * <li>JIS_B2 (515x728 mm ; 20.28x28.66 in)</li>
338 * <li>JIS_B3 (364x515 mm ; 14.33x20.28 in)</li>
339 * <li>JIS_B4 (257x364 mm ; 10.12x14.33 in)</li>
340 * <li>JIS_B5 (182x257 mm ; 7.17x10.12 in)</li>
341 * <li>JIS_B6 (128x182 mm ; 5.04x7.17 in)</li>
342 * <li>JIS_B7 (91x128 mm ; 3.58x5.04 in)</li>
343 * <li>JIS_B8 (64x91 mm ; 2.52x3.58 in)</li>
344 * <li>JIS_B9 (45x64 mm ; 1.77x2.52 in)</li>
345 * <li>JIS_B10 (32x45 mm ; 1.26x1.77 in)</li>
346 * <li>JIS_B11 (22x32 mm ; 0.87x1.26 in)</li>
347 * <li>JIS_B12 (16x22 mm ; 0.63x0.87 in)</li>
348 * <li><b>PA Series</b></li>
349 * <li>PA0 (840x1120 mm ; 33.07x44.09 in)</li>
350 * <li>PA1 (560x840 mm ; 22.05x33.07 in)</li>
351 * <li>PA2 (420x560 mm ; 16.54x22.05 in)</li>
352 * <li>PA3 (280x420 mm ; 11.02x16.54 in)</li>
353 * <li>PA4 (210x280 mm ; 8.27x11.02 in)</li>
354 * <li>PA5 (140x210 mm ; 5.51x8.27 in)</li>
355 * <li>PA6 (105x140 mm ; 4.13x5.51 in)</li>
356 * <li>PA7 (70x105 mm ; 2.76x4.13 in)</li>
357 * <li>PA8 (52x70 mm ; 2.05x2.76 in)</li>
358 * <li>PA9 (35x52 mm ; 1.38x2.05 in)</li>
359 * <li>PA10 (26x35 mm ; 1.02x1.38 in)</li>
360 * <li><b>Standard Photographic Print Sizes</b></li>
361 * <li>PASSPORT_PHOTO (35x45 mm ; 1.38x1.77 in)</li>
362 * <li>E (82x120 mm ; 3.25x4.72 in)</li>
363 * <li>3R, L (89x127 mm ; 3.50x5.00 in)</li>
364 * <li>4R, KG (102x152 mm ; 4.02x5.98 in)</li>
365 * <li>4D (120x152 mm ; 4.72x5.98 in)</li>
366 * <li>5R, 2L (127x178 mm ; 5.00x7.01 in)</li>
367 * <li>6R, 8P (152x203 mm ; 5.98x7.99 in)</li>
368 * <li>8R, 6P (203x254 mm ; 7.99x10.00 in)</li>
369 * <li>S8R, 6PW (203x305 mm ; 7.99x12.01 in)</li>
370 * <li>10R, 4P (254x305 mm ; 10.00x12.01 in)</li>
371 * <li>S10R, 4PW (254x381 mm ; 10.00x15.00 in)</li>
372 * <li>11R (279x356 mm ; 10.98x14.02 in)</li>
373 * <li>S11R (279x432 mm ; 10.98x17.01 in)</li>
374 * <li>12R (305x381 mm ; 12.01x15.00 in)</li>
375 * <li>S12R (305x456 mm ; 12.01x17.95 in)</li>
376 * <li><b>Common Newspaper Sizes</b></li>
377 * <li>NEWSPAPER_BROADSHEET (750x600 mm ; 29.53x23.62 in)</li>
378 * <li>NEWSPAPER_BERLINER (470x315 mm ; 18.50x12.40 in)</li>
379 * <li>NEWSPAPER_COMPACT, NEWSPAPER_TABLOID (430x280 mm ; 16.93x11.02 in)</li>
380 * <li><b>Business Cards</b></li>
381 * <li>CREDIT_CARD, BUSINESS_CARD, BUSINESS_CARD_ISO7810 (54x86 mm ; 2.13x3.37 in)</li>
382 * <li>BUSINESS_CARD_ISO216 (52x74 mm ; 2.05x2.91 in)</li>
383 * <li>BUSINESS_CARD_IT, BUSINESS_CARD_UK, BUSINESS_CARD_FR, BUSINESS_CARD_DE, BUSINESS_CARD_ES (55x85 mm ; 2.17x3.35 in)</li>
384 * <li>BUSINESS_CARD_US, BUSINESS_CARD_CA (51x89 mm ; 2.01x3.50 in)</li>
385 * <li>BUSINESS_CARD_JP (55x91 mm ; 2.17x3.58 in)</li>
386 * <li>BUSINESS_CARD_HK (54x90 mm ; 2.13x3.54 in)</li>
387 * <li>BUSINESS_CARD_AU, BUSINESS_CARD_DK, BUSINESS_CARD_SE (55x90 mm ; 2.17x3.54 in)</li>
388 * <li>BUSINESS_CARD_RU, BUSINESS_CARD_CZ, BUSINESS_CARD_FI, BUSINESS_CARD_HU, BUSINESS_CARD_IL (50x90 mm ; 1.97x3.54 in)</li>
389 * <li><b>Billboards</b></li>
390 * <li>4SHEET (1016x1524 mm ; 40.00x60.00 in)</li>
391 * <li>6SHEET (1200x1800 mm ; 47.24x70.87 in)</li>
392 * <li>12SHEET (3048x1524 mm ; 120.00x60.00 in)</li>
393 * <li>16SHEET (2032x3048 mm ; 80.00x120.00 in)</li>
394 * <li>32SHEET (4064x3048 mm ; 160.00x120.00 in)</li>
395 * <li>48SHEET (6096x3048 mm ; 240.00x120.00 in)</li>
396 * <li>64SHEET (8128x3048 mm ; 320.00x120.00 in)</li>
397 * <li>96SHEET (12192x3048 mm ; 480.00x120.00 in)</li>
398 * <li><b>Old Imperial English (some are still used in USA)</b></li>
399 * <li>EN_EMPEROR (1219x1829 mm ; 48.00x72.00 in)</li>
400 * <li>EN_ANTIQUARIAN (787x1346 mm ; 31.00x53.00 in)</li>
401 * <li>EN_GRAND_EAGLE (730x1067 mm ; 28.75x42.00 in)</li>
402 * <li>EN_DOUBLE_ELEPHANT (679x1016 mm ; 26.75x40.00 in)</li>
403 * <li>EN_ATLAS (660x864 mm ; 26.00x34.00 in)</li>
404 * <li>EN_COLOMBIER (597x876 mm ; 23.50x34.50 in)</li>
405 * <li>EN_ELEPHANT (584x711 mm ; 23.00x28.00 in)</li>
406 * <li>EN_DOUBLE_DEMY (572x902 mm ; 22.50x35.50 in)</li>
407 * <li>EN_IMPERIAL (559x762 mm ; 22.00x30.00 in)</li>
408 * <li>EN_PRINCESS (546x711 mm ; 21.50x28.00 in)</li>
409 * <li>EN_CARTRIDGE (533x660 mm ; 21.00x26.00 in)</li>
410 * <li>EN_DOUBLE_LARGE_POST (533x838 mm ; 21.00x33.00 in)</li>
411 * <li>EN_ROYAL (508x635 mm ; 20.00x25.00 in)</li>
412 * <li>EN_SHEET, EN_HALF_POST (495x597 mm ; 19.50x23.50 in)</li>
413 * <li>EN_SUPER_ROYAL (483x686 mm ; 19.00x27.00 in)</li>
414 * <li>EN_DOUBLE_POST (483x775 mm ; 19.00x30.50 in)</li>
415 * <li>EN_MEDIUM (445x584 mm ; 17.50x23.00 in)</li>
416 * <li>EN_DEMY (445x572 mm ; 17.50x22.50 in)</li>
417 * <li>EN_LARGE_POST (419x533 mm ; 16.50x21.00 in)</li>
418 * <li>EN_COPY_DRAUGHT (406x508 mm ; 16.00x20.00 in)</li>
419 * <li>EN_POST (394x489 mm ; 15.50x19.25 in)</li>
420 * <li>EN_CROWN (381x508 mm ; 15.00x20.00 in)</li>
421 * <li>EN_PINCHED_POST (375x470 mm ; 14.75x18.50 in)</li>
422 * <li>EN_BRIEF (343x406 mm ; 13.50x16.00 in)</li>
423 * <li>EN_FOOLSCAP (343x432 mm ; 13.50x17.00 in)</li>
424 * <li>EN_SMALL_FOOLSCAP (337x419 mm ; 13.25x16.50 in)</li>
425 * <li>EN_POTT (318x381 mm ; 12.50x15.00 in)</li>
426 * <li><b>Old Imperial Belgian</b></li>
427 * <li>BE_GRAND_AIGLE (700x1040 mm ; 27.56x40.94 in)</li>
428 * <li>BE_COLOMBIER (620x850 mm ; 24.41x33.46 in)</li>
429 * <li>BE_DOUBLE_CARRE (620x920 mm ; 24.41x36.22 in)</li>
430 * <li>BE_ELEPHANT (616x770 mm ; 24.25x30.31 in)</li>
431 * <li>BE_PETIT_AIGLE (600x840 mm ; 23.62x33.07 in)</li>
432 * <li>BE_GRAND_JESUS (550x730 mm ; 21.65x28.74 in)</li>
433 * <li>BE_JESUS (540x730 mm ; 21.26x28.74 in)</li>
434 * <li>BE_RAISIN (500x650 mm ; 19.69x25.59 in)</li>
435 * <li>BE_GRAND_MEDIAN (460x605 mm ; 18.11x23.82 in)</li>
436 * <li>BE_DOUBLE_POSTE (435x565 mm ; 17.13x22.24 in)</li>
437 * <li>BE_COQUILLE (430x560 mm ; 16.93x22.05 in)</li>
438 * <li>BE_PETIT_MEDIAN (415x530 mm ; 16.34x20.87 in)</li>
439 * <li>BE_RUCHE (360x460 mm ; 14.17x18.11 in)</li>
440 * <li>BE_PROPATRIA (345x430 mm ; 13.58x16.93 in)</li>
441 * <li>BE_LYS (317x397 mm ; 12.48x15.63 in)</li>
442 * <li>BE_POT (307x384 mm ; 12.09x15.12 in)</li>
443 * <li>BE_ROSETTE (270x347 mm ; 10.63x13.66 in)</li>
444 * <li><b>Old Imperial French</b></li>
445 * <li>FR_UNIVERS (1000x1300 mm ; 39.37x51.18 in)</li>
446 * <li>FR_DOUBLE_COLOMBIER (900x1260 mm ; 35.43x49.61 in)</li>
447 * <li>FR_GRANDE_MONDE (900x1260 mm ; 35.43x49.61 in)</li>
448 * <li>FR_DOUBLE_SOLEIL (800x1200 mm ; 31.50x47.24 in)</li>
449 * <li>FR_DOUBLE_JESUS (760x1120 mm ; 29.92x44.09 in)</li>
450 * <li>FR_GRAND_AIGLE (750x1060 mm ; 29.53x41.73 in)</li>
451 * <li>FR_PETIT_AIGLE (700x940 mm ; 27.56x37.01 in)</li>
452 * <li>FR_DOUBLE_RAISIN (650x1000 mm ; 25.59x39.37 in)</li>
453 * <li>FR_JOURNAL (650x940 mm ; 25.59x37.01 in)</li>
454 * <li>FR_COLOMBIER_AFFICHE (630x900 mm ; 24.80x35.43 in)</li>
455 * <li>FR_DOUBLE_CAVALIER (620x920 mm ; 24.41x36.22 in)</li>
456 * <li>FR_CLOCHE (600x800 mm ; 23.62x31.50 in)</li>
457 * <li>FR_SOLEIL (600x800 mm ; 23.62x31.50 in)</li>
458 * <li>FR_DOUBLE_CARRE (560x900 mm ; 22.05x35.43 in)</li>
459 * <li>FR_DOUBLE_COQUILLE (560x880 mm ; 22.05x34.65 in)</li>
460 * <li>FR_JESUS (560x760 mm ; 22.05x29.92 in)</li>
461 * <li>FR_RAISIN (500x650 mm ; 19.69x25.59 in)</li>
462 * <li>FR_CAVALIER (460x620 mm ; 18.11x24.41 in)</li>
463 * <li>FR_DOUBLE_COURONNE (460x720 mm ; 18.11x28.35 in)</li>
464 * <li>FR_CARRE (450x560 mm ; 17.72x22.05 in)</li>
465 * <li>FR_COQUILLE (440x560 mm ; 17.32x22.05 in)</li>
466 * <li>FR_DOUBLE_TELLIERE (440x680 mm ; 17.32x26.77 in)</li>
467 * <li>FR_DOUBLE_CLOCHE (400x600 mm ; 15.75x23.62 in)</li>
468 * <li>FR_DOUBLE_POT (400x620 mm ; 15.75x24.41 in)</li>
469 * <li>FR_ECU (400x520 mm ; 15.75x20.47 in)</li>
470 * <li>FR_COURONNE (360x460 mm ; 14.17x18.11 in)</li>
471 * <li>FR_TELLIERE (340x440 mm ; 13.39x17.32 in)</li>
472 * <li>FR_POT (310x400 mm ; 12.20x15.75 in)</li>
473 * </ul>
474 * @return array containing page width and height in points
475 * @since 5.0.010 (2010-05-17)
476 * @public static
477 */
478 public static function getPageSizeFromFormat($format) {
479 // Paper cordinates are calculated in this way: (inches * 72) where (1 inch = 25.4 mm)
480 switch (strtoupper($format)) {
481 // ISO 216 A Series + 2 SIS 014711 extensions
482 case 'A0' : {$pf = array( 2383.937, 3370.394); break;}
483 case 'A1' : {$pf = array( 1683.780, 2383.937); break;}
484 case 'A2' : {$pf = array( 1190.551, 1683.780); break;}
485 case 'A3' : {$pf = array( 841.890, 1190.551); break;}
486 case 'A4' : {$pf = array( 595.276, 841.890); break;}
487 case 'A5' : {$pf = array( 419.528, 595.276); break;}
488 case 'A6' : {$pf = array( 297.638, 419.528); break;}
489 case 'A7' : {$pf = array( 209.764, 297.638); break;}
490 case 'A8' : {$pf = array( 147.402, 209.764); break;}
491 case 'A9' : {$pf = array( 104.882, 147.402); break;}
492 case 'A10': {$pf = array( 73.701, 104.882); break;}
493 case 'A11': {$pf = array( 51.024, 73.701); break;}
494 case 'A12': {$pf = array( 36.850, 51.024); break;}
495 // ISO 216 B Series + 2 SIS 014711 extensions
496 case 'B0' : {$pf = array( 2834.646, 4008.189); break;}
497 case 'B1' : {$pf = array( 2004.094, 2834.646); break;}
498 case 'B2' : {$pf = array( 1417.323, 2004.094); break;}
499 case 'B3' : {$pf = array( 1000.630, 1417.323); break;}
500 case 'B4' : {$pf = array( 708.661, 1000.630); break;}
501 case 'B5' : {$pf = array( 498.898, 708.661); break;}
502 case 'B6' : {$pf = array( 354.331, 498.898); break;}
503 case 'B7' : {$pf = array( 249.449, 354.331); break;}
504 case 'B8' : {$pf = array( 175.748, 249.449); break;}
505 case 'B9' : {$pf = array( 124.724, 175.748); break;}
506 case 'B10': {$pf = array( 87.874, 124.724); break;}
507 case 'B11': {$pf = array( 62.362, 87.874); break;}
508 case 'B12': {$pf = array( 42.520, 62.362); break;}
509 // ISO 216 C Series + 2 SIS 014711 extensions + 2 EXTENSION
510 case 'C0' : {$pf = array( 2599.370, 3676.535); break;}
511 case 'C1' : {$pf = array( 1836.850, 2599.370); break;}
512 case 'C2' : {$pf = array( 1298.268, 1836.850); break;}
513 case 'C3' : {$pf = array( 918.425, 1298.268); break;}
514 case 'C4' : {$pf = array( 649.134, 918.425); break;}
515 case 'C5' : {$pf = array( 459.213, 649.134); break;}
516 case 'C6' : {$pf = array( 323.150, 459.213); break;}
517 case 'C7' : {$pf = array( 229.606, 323.150); break;}
518 case 'C8' : {$pf = array( 161.575, 229.606); break;}
519 case 'C9' : {$pf = array( 113.386, 161.575); break;}
520 case 'C10': {$pf = array( 79.370, 113.386); break;}
521 case 'C11': {$pf = array( 56.693, 79.370); break;}
522 case 'C12': {$pf = array( 39.685, 56.693); break;}
523 case 'C76': {$pf = array( 229.606, 459.213); break;}
524 case 'DL' : {$pf = array( 311.811, 623.622); break;}
525 // SIS 014711 E Series
526 case 'E0' : {$pf = array( 2491.654, 3517.795); break;}
527 case 'E1' : {$pf = array( 1757.480, 2491.654); break;}
528 case 'E2' : {$pf = array( 1247.244, 1757.480); break;}
529 case 'E3' : {$pf = array( 878.740, 1247.244); break;}
530 case 'E4' : {$pf = array( 623.622, 878.740); break;}
531 case 'E5' : {$pf = array( 439.370, 623.622); break;}
532 case 'E6' : {$pf = array( 311.811, 439.370); break;}
533 case 'E7' : {$pf = array( 221.102, 311.811); break;}
534 case 'E8' : {$pf = array( 155.906, 221.102); break;}
535 case 'E9' : {$pf = array( 110.551, 155.906); break;}
536 case 'E10': {$pf = array( 76.535, 110.551); break;}
537 case 'E11': {$pf = array( 53.858, 76.535); break;}
538 case 'E12': {$pf = array( 36.850, 53.858); break;}
539 // SIS 014711 G Series
540 case 'G0' : {$pf = array( 2715.591, 3838.110); break;}
541 case 'G1' : {$pf = array( 1919.055, 2715.591); break;}
542 case 'G2' : {$pf = array( 1357.795, 1919.055); break;}
543 case 'G3' : {$pf = array( 958.110, 1357.795); break;}
544 case 'G4' : {$pf = array( 677.480, 958.110); break;}
545 case 'G5' : {$pf = array( 479.055, 677.480); break;}
546 case 'G6' : {$pf = array( 337.323, 479.055); break;}
547 case 'G7' : {$pf = array( 238.110, 337.323); break;}
548 case 'G8' : {$pf = array( 167.244, 238.110); break;}
549 case 'G9' : {$pf = array( 119.055, 167.244); break;}
550 case 'G10': {$pf = array( 82.205, 119.055); break;}
551 case 'G11': {$pf = array( 59.528, 82.205); break;}
552 case 'G12': {$pf = array( 39.685, 59.528); break;}
553 // ISO Press
554 case 'RA0': {$pf = array( 2437.795, 3458.268); break;}
555 case 'RA1': {$pf = array( 1729.134, 2437.795); break;}
556 case 'RA2': {$pf = array( 1218.898, 1729.134); break;}
557 case 'RA3': {$pf = array( 864.567, 1218.898); break;}
558 case 'RA4': {$pf = array( 609.449, 864.567); break;}
559 case 'SRA0': {$pf = array( 2551.181, 3628.346); break;}
560 case 'SRA1': {$pf = array( 1814.173, 2551.181); break;}
561 case 'SRA2': {$pf = array( 1275.591, 1814.173); break;}
562 case 'SRA3': {$pf = array( 907.087, 1275.591); break;}
563 case 'SRA4': {$pf = array( 637.795, 907.087); break;}
564 // German DIN 476
565 case '4A0': {$pf = array( 4767.874, 6740.787); break;}
566 case '2A0': {$pf = array( 3370.394, 4767.874); break;}
567 // Variations on the ISO Standard
568 case 'A2_EXTRA' : {$pf = array( 1261.417, 1754.646); break;}
569 case 'A3+' : {$pf = array( 932.598, 1369.134); break;}
570 case 'A3_EXTRA' : {$pf = array( 912.756, 1261.417); break;}
571 case 'A3_SUPER' : {$pf = array( 864.567, 1440.000); break;}
572 case 'SUPER_A3' : {$pf = array( 864.567, 1380.472); break;}
573 case 'A4_EXTRA' : {$pf = array( 666.142, 912.756); break;}
574 case 'A4_SUPER' : {$pf = array( 649.134, 912.756); break;}
575 case 'SUPER_A4' : {$pf = array( 643.465, 1009.134); break;}
576 case 'A4_LONG' : {$pf = array( 595.276, 986.457); break;}
577 case 'F4' : {$pf = array( 595.276, 935.433); break;}
578 case 'SO_B5_EXTRA': {$pf = array( 572.598, 782.362); break;}
579 case 'A5_EXTRA' : {$pf = array( 490.394, 666.142); break;}
580 // ANSI Series
581 case 'ANSI_E': {$pf = array( 2448.000, 3168.000); break;}
582 case 'ANSI_D': {$pf = array( 1584.000, 2448.000); break;}
583 case 'ANSI_C': {$pf = array( 1224.000, 1584.000); break;}
584 case 'ANSI_B': {$pf = array( 792.000, 1224.000); break;}
585 case 'ANSI_A': {$pf = array( 612.000, 792.000); break;}
586 // Traditional 'Loose' North American Paper Sizes
587 case 'USLEDGER':
588 case 'LEDGER' : {$pf = array( 1224.000, 792.000); break;}
589 case 'ORGANIZERK':
590 case 'BIBLE':
591 case 'USTABLOID':
592 case 'TABLOID': {$pf = array( 792.000, 1224.000); break;}
593 case 'ORGANIZERM':
594 case 'USLETTER':
595 case 'LETTER' : {$pf = array( 612.000, 792.000); break;}
596 case 'USLEGAL':
597 case 'LEGAL' : {$pf = array( 612.000, 1008.000); break;}
598 case 'GOVERNMENTLETTER':
599 case 'GLETTER': {$pf = array( 576.000, 756.000); break;}
600 case 'JUNIORLEGAL':
601 case 'JLEGAL' : {$pf = array( 576.000, 360.000); break;}
602 // Other North American Paper Sizes
603 case 'QUADDEMY': {$pf = array( 2520.000, 3240.000); break;}
604 case 'SUPER_B': {$pf = array( 936.000, 1368.000); break;}
605 case 'QUARTO': {$pf = array( 648.000, 792.000); break;}
606 case 'GOVERNMENTLEGAL':
607 case 'FOLIO': {$pf = array( 612.000, 936.000); break;}
608 case 'MONARCH':
609 case 'EXECUTIVE': {$pf = array( 522.000, 756.000); break;}
610 case 'ORGANIZERL':
611 case 'STATEMENT':
612 case 'MEMO': {$pf = array( 396.000, 612.000); break;}
613 case 'FOOLSCAP': {$pf = array( 595.440, 936.000); break;}
614 case 'COMPACT': {$pf = array( 306.000, 486.000); break;}
615 case 'ORGANIZERJ': {$pf = array( 198.000, 360.000); break;}
616 // Canadian standard CAN 2-9.60M
617 case 'P1': {$pf = array( 1587.402, 2437.795); break;}
618 case 'P2': {$pf = array( 1218.898, 1587.402); break;}
619 case 'P3': {$pf = array( 793.701, 1218.898); break;}
620 case 'P4': {$pf = array( 609.449, 793.701); break;}
621 case 'P5': {$pf = array( 396.850, 609.449); break;}
622 case 'P6': {$pf = array( 303.307, 396.850); break;}
623 // North American Architectural Sizes
624 case 'ARCH_E' : {$pf = array( 2592.000, 3456.000); break;}
625 case 'ARCH_E1': {$pf = array( 2160.000, 3024.000); break;}
626 case 'ARCH_D' : {$pf = array( 1728.000, 2592.000); break;}
627 case 'BROADSHEET':
628 case 'ARCH_C' : {$pf = array( 1296.000, 1728.000); break;}
629 case 'ARCH_B' : {$pf = array( 864.000, 1296.000); break;}
630 case 'ARCH_A' : {$pf = array( 648.000, 864.000); break;}
631 // --- North American Envelope Sizes ---
632 // - Announcement Envelopes
633 case 'ANNENV_A2' : {$pf = array( 314.640, 414.000); break;}
634 case 'ANNENV_A6' : {$pf = array( 342.000, 468.000); break;}
635 case 'ANNENV_A7' : {$pf = array( 378.000, 522.000); break;}
636 case 'ANNENV_A8' : {$pf = array( 396.000, 584.640); break;}
637 case 'ANNENV_A10' : {$pf = array( 450.000, 692.640); break;}
638 case 'ANNENV_SLIM': {$pf = array( 278.640, 638.640); break;}
639 // - Commercial Envelopes
640 case 'COMMENV_N6_1/4': {$pf = array( 252.000, 432.000); break;}
641 case 'COMMENV_N6_3/4': {$pf = array( 260.640, 468.000); break;}
642 case 'COMMENV_N8' : {$pf = array( 278.640, 540.000); break;}
643 case 'COMMENV_N9' : {$pf = array( 278.640, 638.640); break;}
644 case 'COMMENV_N10' : {$pf = array( 296.640, 684.000); break;}
645 case 'COMMENV_N11' : {$pf = array( 324.000, 746.640); break;}
646 case 'COMMENV_N12' : {$pf = array( 342.000, 792.000); break;}
647 case 'COMMENV_N14' : {$pf = array( 360.000, 828.000); break;}
648 // - Catalogue Envelopes
649 case 'CATENV_N1' : {$pf = array( 432.000, 648.000); break;}
650 case 'CATENV_N1_3/4' : {$pf = array( 468.000, 684.000); break;}
651 case 'CATENV_N2' : {$pf = array( 468.000, 720.000); break;}
652 case 'CATENV_N3' : {$pf = array( 504.000, 720.000); break;}
653 case 'CATENV_N6' : {$pf = array( 540.000, 756.000); break;}
654 case 'CATENV_N7' : {$pf = array( 576.000, 792.000); break;}
655 case 'CATENV_N8' : {$pf = array( 594.000, 810.000); break;}
656 case 'CATENV_N9_1/2' : {$pf = array( 612.000, 756.000); break;}
657 case 'CATENV_N9_3/4' : {$pf = array( 630.000, 810.000); break;}
658 case 'CATENV_N10_1/2': {$pf = array( 648.000, 864.000); break;}
659 case 'CATENV_N12_1/2': {$pf = array( 684.000, 900.000); break;}
660 case 'CATENV_N13_1/2': {$pf = array( 720.000, 936.000); break;}
661 case 'CATENV_N14_1/4': {$pf = array( 810.000, 882.000); break;}
662 case 'CATENV_N14_1/2': {$pf = array( 828.000, 1044.000); break;}
663 // Japanese (JIS P 0138-61) Standard B-Series
664 case 'JIS_B0' : {$pf = array( 2919.685, 4127.244); break;}
665 case 'JIS_B1' : {$pf = array( 2063.622, 2919.685); break;}
666 case 'JIS_B2' : {$pf = array( 1459.843, 2063.622); break;}
667 case 'JIS_B3' : {$pf = array( 1031.811, 1459.843); break;}
668 case 'JIS_B4' : {$pf = array( 728.504, 1031.811); break;}
669 case 'JIS_B5' : {$pf = array( 515.906, 728.504); break;}
670 case 'JIS_B6' : {$pf = array( 362.835, 515.906); break;}
671 case 'JIS_B7' : {$pf = array( 257.953, 362.835); break;}
672 case 'JIS_B8' : {$pf = array( 181.417, 257.953); break;}
673 case 'JIS_B9' : {$pf = array( 127.559, 181.417); break;}
674 case 'JIS_B10': {$pf = array( 90.709, 127.559); break;}
675 case 'JIS_B11': {$pf = array( 62.362, 90.709); break;}
676 case 'JIS_B12': {$pf = array( 45.354, 62.362); break;}
677 // PA Series
678 case 'PA0' : {$pf = array( 2381.102, 3174.803,); break;}
679 case 'PA1' : {$pf = array( 1587.402, 2381.102); break;}
680 case 'PA2' : {$pf = array( 1190.551, 1587.402); break;}
681 case 'PA3' : {$pf = array( 793.701, 1190.551); break;}
682 case 'PA4' : {$pf = array( 595.276, 793.701); break;}
683 case 'PA5' : {$pf = array( 396.850, 595.276); break;}
684 case 'PA6' : {$pf = array( 297.638, 396.850); break;}
685 case 'PA7' : {$pf = array( 198.425, 297.638); break;}
686 case 'PA8' : {$pf = array( 147.402, 198.425); break;}
687 case 'PA9' : {$pf = array( 99.213, 147.402); break;}
688 case 'PA10': {$pf = array( 73.701, 99.213); break;}
689 // Standard Photographic Print Sizes
690 case 'PASSPORT_PHOTO': {$pf = array( 99.213, 127.559); break;}
691 case 'E' : {$pf = array( 233.858, 340.157); break;}
692 case 'L':
693 case '3R' : {$pf = array( 252.283, 360.000); break;}
694 case 'KG':
695 case '4R' : {$pf = array( 289.134, 430.866); break;}
696 case '4D' : {$pf = array( 340.157, 430.866); break;}
697 case '2L':
698 case '5R' : {$pf = array( 360.000, 504.567); break;}
699 case '8P':
700 case '6R' : {$pf = array( 430.866, 575.433); break;}
701 case '6P':
702 case '8R' : {$pf = array( 575.433, 720.000); break;}
703 case '6PW':
704 case 'S8R' : {$pf = array( 575.433, 864.567); break;}
705 case '4P':
706 case '10R' : {$pf = array( 720.000, 864.567); break;}
707 case '4PW':
708 case 'S10R': {$pf = array( 720.000, 1080.000); break;}
709 case '11R' : {$pf = array( 790.866, 1009.134); break;}
710 case 'S11R': {$pf = array( 790.866, 1224.567); break;}
711 case '12R' : {$pf = array( 864.567, 1080.000); break;}
712 case 'S12R': {$pf = array( 864.567, 1292.598); break;}
713 // Common Newspaper Sizes
714 case 'NEWSPAPER_BROADSHEET': {$pf = array( 2125.984, 1700.787); break;}
715 case 'NEWSPAPER_BERLINER' : {$pf = array( 1332.283, 892.913); break;}
716 case 'NEWSPAPER_TABLOID':
717 case 'NEWSPAPER_COMPACT' : {$pf = array( 1218.898, 793.701); break;}
718 // Business Cards
719 case 'CREDIT_CARD':
720 case 'BUSINESS_CARD':
721 case 'BUSINESS_CARD_ISO7810': {$pf = array( 153.014, 242.646); break;}
722 case 'BUSINESS_CARD_ISO216' : {$pf = array( 147.402, 209.764); break;}
723 case 'BUSINESS_CARD_IT':
724 case 'BUSINESS_CARD_UK':
725 case 'BUSINESS_CARD_FR':
726 case 'BUSINESS_CARD_DE':
727 case 'BUSINESS_CARD_ES' : {$pf = array( 155.906, 240.945); break;}
728 case 'BUSINESS_CARD_CA':
729 case 'BUSINESS_CARD_US' : {$pf = array( 144.567, 252.283); break;}
730 case 'BUSINESS_CARD_JP' : {$pf = array( 155.906, 257.953); break;}
731 case 'BUSINESS_CARD_HK' : {$pf = array( 153.071, 255.118); break;}
732 case 'BUSINESS_CARD_AU':
733 case 'BUSINESS_CARD_DK':
734 case 'BUSINESS_CARD_SE' : {$pf = array( 155.906, 255.118); break;}
735 case 'BUSINESS_CARD_RU':
736 case 'BUSINESS_CARD_CZ':
737 case 'BUSINESS_CARD_FI':
738 case 'BUSINESS_CARD_HU':
739 case 'BUSINESS_CARD_IL' : {$pf = array( 141.732, 255.118); break;}
740 // Billboards
741 case '4SHEET' : {$pf = array( 2880.000, 4320.000); break;}
742 case '6SHEET' : {$pf = array( 3401.575, 5102.362); break;}
743 case '12SHEET': {$pf = array( 8640.000, 4320.000); break;}
744 case '16SHEET': {$pf = array( 5760.000, 8640.000); break;}
745 case '32SHEET': {$pf = array(11520.000, 8640.000); break;}
746 case '48SHEET': {$pf = array(17280.000, 8640.000); break;}
747 case '64SHEET': {$pf = array(23040.000, 8640.000); break;}
748 case '96SHEET': {$pf = array(34560.000, 8640.000); break;}
749 // Old European Sizes
750 // - Old Imperial English Sizes
751 case 'EN_EMPEROR' : {$pf = array( 3456.000, 5184.000); break;}
752 case 'EN_ANTIQUARIAN' : {$pf = array( 2232.000, 3816.000); break;}
753 case 'EN_GRAND_EAGLE' : {$pf = array( 2070.000, 3024.000); break;}
754 case 'EN_DOUBLE_ELEPHANT' : {$pf = array( 1926.000, 2880.000); break;}
755 case 'EN_ATLAS' : {$pf = array( 1872.000, 2448.000); break;}
756 case 'EN_COLOMBIER' : {$pf = array( 1692.000, 2484.000); break;}
757 case 'EN_ELEPHANT' : {$pf = array( 1656.000, 2016.000); break;}
758 case 'EN_DOUBLE_DEMY' : {$pf = array( 1620.000, 2556.000); break;}
759 case 'EN_IMPERIAL' : {$pf = array( 1584.000, 2160.000); break;}
760 case 'EN_PRINCESS' : {$pf = array( 1548.000, 2016.000); break;}
761 case 'EN_CARTRIDGE' : {$pf = array( 1512.000, 1872.000); break;}
762 case 'EN_DOUBLE_LARGE_POST': {$pf = array( 1512.000, 2376.000); break;}
763 case 'EN_ROYAL' : {$pf = array( 1440.000, 1800.000); break;}
764 case 'EN_SHEET':
765 case 'EN_HALF_POST' : {$pf = array( 1404.000, 1692.000); break;}
766 case 'EN_SUPER_ROYAL' : {$pf = array( 1368.000, 1944.000); break;}
767 case 'EN_DOUBLE_POST' : {$pf = array( 1368.000, 2196.000); break;}
768 case 'EN_MEDIUM' : {$pf = array( 1260.000, 1656.000); break;}
769 case 'EN_DEMY' : {$pf = array( 1260.000, 1620.000); break;}
770 case 'EN_LARGE_POST' : {$pf = array( 1188.000, 1512.000); break;}
771 case 'EN_COPY_DRAUGHT' : {$pf = array( 1152.000, 1440.000); break;}
772 case 'EN_POST' : {$pf = array( 1116.000, 1386.000); break;}
773 case 'EN_CROWN' : {$pf = array( 1080.000, 1440.000); break;}
774 case 'EN_PINCHED_POST' : {$pf = array( 1062.000, 1332.000); break;}
775 case 'EN_BRIEF' : {$pf = array( 972.000, 1152.000); break;}
776 case 'EN_FOOLSCAP' : {$pf = array( 972.000, 1224.000); break;}
777 case 'EN_SMALL_FOOLSCAP' : {$pf = array( 954.000, 1188.000); break;}
778 case 'EN_POTT' : {$pf = array( 900.000, 1080.000); break;}
779 // - Old Imperial Belgian Sizes
780 case 'BE_GRAND_AIGLE' : {$pf = array( 1984.252, 2948.031); break;}
781 case 'BE_COLOMBIER' : {$pf = array( 1757.480, 2409.449); break;}
782 case 'BE_DOUBLE_CARRE': {$pf = array( 1757.480, 2607.874); break;}
783 case 'BE_ELEPHANT' : {$pf = array( 1746.142, 2182.677); break;}
784 case 'BE_PETIT_AIGLE' : {$pf = array( 1700.787, 2381.102); break;}
785 case 'BE_GRAND_JESUS' : {$pf = array( 1559.055, 2069.291); break;}
786 case 'BE_JESUS' : {$pf = array( 1530.709, 2069.291); break;}
787 case 'BE_RAISIN' : {$pf = array( 1417.323, 1842.520); break;}
788 case 'BE_GRAND_MEDIAN': {$pf = array( 1303.937, 1714.961); break;}
789 case 'BE_DOUBLE_POSTE': {$pf = array( 1233.071, 1601.575); break;}
790 case 'BE_COQUILLE' : {$pf = array( 1218.898, 1587.402); break;}
791 case 'BE_PETIT_MEDIAN': {$pf = array( 1176.378, 1502.362); break;}
792 case 'BE_RUCHE' : {$pf = array( 1020.472, 1303.937); break;}
793 case 'BE_PROPATRIA' : {$pf = array( 977.953, 1218.898); break;}
794 case 'BE_LYS' : {$pf = array( 898.583, 1125.354); break;}
795 case 'BE_POT' : {$pf = array( 870.236, 1088.504); break;}
796 case 'BE_ROSETTE' : {$pf = array( 765.354, 983.622); break;}
797 // - Old Imperial French Sizes
798 case 'FR_UNIVERS' : {$pf = array( 2834.646, 3685.039); break;}
799 case 'FR_DOUBLE_COLOMBIER' : {$pf = array( 2551.181, 3571.654); break;}
800 case 'FR_GRANDE_MONDE' : {$pf = array( 2551.181, 3571.654); break;}
801 case 'FR_DOUBLE_SOLEIL' : {$pf = array( 2267.717, 3401.575); break;}
802 case 'FR_DOUBLE_JESUS' : {$pf = array( 2154.331, 3174.803); break;}
803 case 'FR_GRAND_AIGLE' : {$pf = array( 2125.984, 3004.724); break;}
804 case 'FR_PETIT_AIGLE' : {$pf = array( 1984.252, 2664.567); break;}
805 case 'FR_DOUBLE_RAISIN' : {$pf = array( 1842.520, 2834.646); break;}
806 case 'FR_JOURNAL' : {$pf = array( 1842.520, 2664.567); break;}
807 case 'FR_COLOMBIER_AFFICHE': {$pf = array( 1785.827, 2551.181); break;}
808 case 'FR_DOUBLE_CAVALIER' : {$pf = array( 1757.480, 2607.874); break;}
809 case 'FR_CLOCHE' : {$pf = array( 1700.787, 2267.717); break;}
810 case 'FR_SOLEIL' : {$pf = array( 1700.787, 2267.717); break;}
811 case 'FR_DOUBLE_CARRE' : {$pf = array( 1587.402, 2551.181); break;}
812 case 'FR_DOUBLE_COQUILLE' : {$pf = array( 1587.402, 2494.488); break;}
813 case 'FR_JESUS' : {$pf = array( 1587.402, 2154.331); break;}
814 case 'FR_RAISIN' : {$pf = array( 1417.323, 1842.520); break;}
815 case 'FR_CAVALIER' : {$pf = array( 1303.937, 1757.480); break;}
816 case 'FR_DOUBLE_COURONNE' : {$pf = array( 1303.937, 2040.945); break;}
817 case 'FR_CARRE' : {$pf = array( 1275.591, 1587.402); break;}
818 case 'FR_COQUILLE' : {$pf = array( 1247.244, 1587.402); break;}
819 case 'FR_DOUBLE_TELLIERE' : {$pf = array( 1247.244, 1927.559); break;}
820 case 'FR_DOUBLE_CLOCHE' : {$pf = array( 1133.858, 1700.787); break;}
821 case 'FR_DOUBLE_POT' : {$pf = array( 1133.858, 1757.480); break;}
822 case 'FR_ECU' : {$pf = array( 1133.858, 1474.016); break;}
823 case 'FR_COURONNE' : {$pf = array( 1020.472, 1303.937); break;}
824 case 'FR_TELLIERE' : {$pf = array( 963.780, 1247.244); break;}
825 case 'FR_POT' : {$pf = array( 878.740, 1133.858); break;}
826 // DEFAULT ISO A4
827 default: {$pf = array( 595.276, 841.890); break;}
828 }
829 return $pf;
830 }
831
832 /**
833 * Set page boundaries.
834 * @param $page (int) page number
835 * @param $type (string) valid values are: <ul><li>'MediaBox' : the boundaries of the physical medium on which the page shall be displayed or printed;</li><li>'CropBox' : the visible region of default user space;</li><li>'BleedBox' : the region to which the contents of the page shall be clipped when output in a production environment;</li><li>'TrimBox' : the intended dimensions of the finished page after trimming;</li><li>'ArtBox' : the page's meaningful content (including potential white space).</li></ul>
836 * @param $llx (float) lower-left x coordinate in user units.
837 * @param $lly (float) lower-left y coordinate in user units.
838 * @param $urx (float) upper-right x coordinate in user units.
839 * @param $ury (float) upper-right y coordinate in user units.
840 * @param $points (boolean) If true uses user units as unit of measure, otherwise uses PDF points.
841 * @param $k (float) Scale factor (number of points in user unit).
842 * @param $pagedim (array) Array of page dimensions.
843 * @return pagedim array of page dimensions.
844 * @since 5.0.010 (2010-05-17)
845 * @public static
846 */
847 public static function setPageBoxes($page, $type, $llx, $lly, $urx, $ury, $points=false, $k, $pagedim=array()) {
848 if (!isset($pagedim[$page])) {
849 // initialize array
850 $pagedim[$page] = array();
851 }
852 if (!in_array($type, self::$pageboxes)) {
853 return;
854 }
855 if ($points) {
856 $k = 1;
857 }
858 $pagedim[$page][$type]['llx'] = ($llx * $k);
859 $pagedim[$page][$type]['lly'] = ($lly * $k);
860 $pagedim[$page][$type]['urx'] = ($urx * $k);
861 $pagedim[$page][$type]['ury'] = ($ury * $k);
862 return $pagedim;
863 }
864
865 /**
866 * Swap X and Y coordinates of page boxes (change page boxes orientation).
867 * @param $page (int) page number
868 * @param $pagedim (array) Array of page dimensions.
869 * @return pagedim array of page dimensions.
870 * @since 5.0.010 (2010-05-17)
871 * @public static
872 */
873 public static function swapPageBoxCoordinates($page, $pagedim) {
874 foreach (self::$pageboxes as $type) {
875 // swap X and Y coordinates
876 if (isset($pagedim[$page][$type])) {
877 $tmp = $pagedim[$page][$type]['llx'];
878 $pagedim[$page][$type]['llx'] = $pagedim[$page][$type]['lly'];
879 $pagedim[$page][$type]['lly'] = $tmp;
880 $tmp = $pagedim[$page][$type]['urx'];
881 $pagedim[$page][$type]['urx'] = $pagedim[$page][$type]['ury'];
882 $pagedim[$page][$type]['ury'] = $tmp;
883 }
884 }
885 return $pagedim;
886 }
887
888 /**
889 * Get the canonical page layout mode.
890 * @param $layout (string) The page layout. Possible values are:<ul><li>SinglePage Display one page at a time</li><li>OneColumn Display the pages in one column</li><li>TwoColumnLeft Display the pages in two columns, with odd-numbered pages on the left</li><li>TwoColumnRight Display the pages in two columns, with odd-numbered pages on the right</li><li>TwoPageLeft (PDF 1.5) Display the pages two at a time, with odd-numbered pages on the left</li><li>TwoPageRight (PDF 1.5) Display the pages two at a time, with odd-numbered pages on the right</li></ul>
891 * @return (string) Canonical page layout name.
892 * @public static
893 */
894 public static function getPageLayoutMode($layout='SinglePage') {
895 switch ($layout) {
896 case 'default':
897 case 'single':
898 case 'SinglePage': {
899 $layout_mode = 'SinglePage';
900 break;
901 }
902 case 'continuous':
903 case 'OneColumn': {
904 $layout_mode = 'OneColumn';
905 break;
906 }
907 case 'two':
908 case 'TwoColumnLeft': {
909 $layout_mode = 'TwoColumnLeft';
910 break;
911 }
912 case 'TwoColumnRight': {
913 $layout_mode = 'TwoColumnRight';
914 break;
915 }
916 case 'TwoPageLeft': {
917 $layout_mode = 'TwoPageLeft';
918 break;
919 }
920 case 'TwoPageRight': {
921 $layout_mode = 'TwoPageRight';
922 break;
923 }
924 default: {
925 $layout_mode = 'SinglePage';
926 }
927 }
928 return $layout_mode;
929 }
930
931 /**
932 * Get the canonical page layout mode.
933 * @param $mode (string) A name object specifying how the document should be displayed when opened:<ul><li>UseNone Neither document outline nor thumbnail images visible</li><li>UseOutlines Document outline visible</li><li>UseThumbs Thumbnail images visible</li><li>FullScreen Full-screen mode, with no menu bar, window controls, or any other window visible</li><li>UseOC (PDF 1.5) Optional content group panel visible</li><li>UseAttachments (PDF 1.6) Attachments panel visible</li></ul>
934 * @return (string) Canonical page mode name.
935 * @public static
936 */
937 public static function getPageMode($mode='UseNone') {
938 switch ($mode) {
939 case 'UseNone': {
940 $page_mode = 'UseNone';
941 break;
942 }
943 case 'UseOutlines': {
944 $page_mode = 'UseOutlines';
945 break;
946 }
947 case 'UseThumbs': {
948 $page_mode = 'UseThumbs';
949 break;
950 }
951 case 'FullScreen': {
952 $page_mode = 'FullScreen';
953 break;
954 }
955 case 'UseOC': {
956 $page_mode = 'UseOC';
957 break;
958 }
959 case '': {
960 $page_mode = 'UseAttachments';
961 break;
962 }
963 default: {
964 $page_mode = 'UseNone';
965 }
966 }
967 return $page_mode;
968 }
969
970 /**
971 * Check if the URL exist.
972 * @param $url (string) URL to check.
973 * @return Boolean true if the URl exist, false otherwise.
974 * @since 5.9.204 (2013-01-28)
975 * @public static
976 */
977 public static function isValidURL($url) {
978 $headers = @get_headers($url);
979 return (strpos($headers[0], '200') !== false);
980 }
981
982 /**
983 * Removes SHY characters from text.
984 * Unicode Data:<ul>
985 * <li>Name : SOFT HYPHEN, commonly abbreviated as SHY</li>
986 * <li>HTML Entity (decimal): "&amp;#173;"</li>
987 * <li>HTML Entity (hex): "&amp;#xad;"</li>
988 * <li>HTML Entity (named): "&amp;shy;"</li>
989 * <li>How to type in Microsoft Windows: [Alt +00AD] or [Alt 0173]</li>
990 * <li>UTF-8 (hex): 0xC2 0xAD (c2ad)</li>
991 * <li>UTF-8 character: chr(194).chr(173)</li>
992 * </ul>
993 * @param $txt (string) input string
994 * @param $unicode (boolean) True if we are in unicode mode, false otherwise.
995 * @return string without SHY characters.
996 * @since (4.5.019) 2009-02-28
997 * @public static
998 */
999 public static function removeSHY($txt='', $unicode=true) {
1000 $txt = preg_replace('/([\\xc2]{1}[\\xad]{1})/', '', $txt);
1001 if (!$unicode) {
1002 $txt = preg_replace('/([\\xad]{1})/', '', $txt);
1003 }
1004 return $txt;
1005 }
1006
1007
1008 /**
1009 * Get the border mode accounting for multicell position (opens bottom side of multicell crossing pages)
1010 * @param $brd (mixed) Indicates if borders must be drawn around the cell block. The value can be a number:<ul><li>0: no border (default)</li><li>1: frame</li></ul>or a string containing some or all of the following characters (in any order):<ul><li>L: left</li><li>T: top</li><li>R: right</li><li>B: bottom</li></ul> or an array of line styles for each border group: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0)))
1011 * @param $position (string) multicell position: 'start', 'middle', 'end'
1012 * @param $opencell (boolean) True when the cell is left open at the page bottom, false otherwise.
1013 * @return border mode array
1014 * @since 4.4.002 (2008-12-09)
1015 * @public static
1016 */
1017 public static function getBorderMode($brd, $position='start', $opencell=true) {
1018 if ((!$opencell) OR empty($brd)) {
1019 return $brd;
1020 }
1021 if ($brd == 1) {
1022 $brd = 'LTRB';
1023 }
1024 if (is_string($brd)) {
1025 // convert string to array
1026 $slen = strlen($brd);
1027 $newbrd = array();
1028 for ($i = 0; $i < $slen; ++$i) {
1029 $newbrd[$brd[$i]] = array('cap' => 'square', 'join' => 'miter');
1030 }
1031 $brd = $newbrd;
1032 }
1033 foreach ($brd as $border => $style) {
1034 switch ($position) {
1035 case 'start': {
1036 if (strpos($border, 'B') !== false) {
1037 // remove bottom line
1038 $newkey = str_replace('B', '', $border);
1039 if (strlen($newkey) > 0) {
1040 $brd[$newkey] = $style;
1041 }
1042 unset($brd[$border]);
1043 }
1044 break;
1045 }
1046 case 'middle': {
1047 if (strpos($border, 'B') !== false) {
1048 // remove bottom line
1049 $newkey = str_replace('B', '', $border);
1050 if (strlen($newkey) > 0) {
1051 $brd[$newkey] = $style;
1052 }
1053 unset($brd[$border]);
1054 $border = $newkey;
1055 }
1056 if (strpos($border, 'T') !== false) {
1057 // remove bottom line
1058 $newkey = str_replace('T', '', $border);
1059 if (strlen($newkey) > 0) {
1060 $brd[$newkey] = $style;
1061 }
1062 unset($brd[$border]);
1063 }
1064 break;
1065 }
1066 case 'end': {
1067 if (strpos($border, 'T') !== false) {
1068 // remove bottom line
1069 $newkey = str_replace('T', '', $border);
1070 if (strlen($newkey) > 0) {
1071 $brd[$newkey] = $style;
1072 }
1073 unset($brd[$border]);
1074 }
1075 break;
1076 }
1077 }
1078 }
1079 return $brd;
1080 }
1081
1082 /**
1083 * Determine whether a string is empty.
1084 * @param $str (string) string to be checked
1085 * @return boolean true if string is empty
1086 * @since 4.5.044 (2009-04-16)
1087 * @public static
1088 */
1089 public static function empty_string($str) {
1090 return (is_null($str) OR (is_string($str) AND (strlen($str) == 0)));
1091 }
1092
1093 /**
1094 * Returns a temporary filename for caching object on filesystem.
1095 * @param $type (string) Type of file (name of the subdir on the tcpdf cache folder).
1096 * @return string filename.
1097 * @since 4.5.000 (2008-12-31)
1098 * @public static
1099 */
1100 public static function getObjFilename($type='tmp') {
1101 return tempnam(K_PATH_CACHE, '__tcpdf_'.$type.'_'.md5(uniqid('', true).rand().microtime(true)).'_');
1102 }
1103
1104 /**
1105 * Add "\" before "\", "(" and ")"
1106 * @param $s (string) string to escape.
1107 * @return string escaped string.
1108 * @public static
1109 */
1110 public static function _escape($s) {
1111 // the chr(13) substitution fixes the Bugs item #1421290.
1112 return strtr($s, array(')' => '\\)', '(' => '\\(', '\\' => '\\\\', chr(13) => '\r'));
1113 }
1114
1115 /**
1116 * Escape some special characters (&lt; &gt; &amp;) for XML output.
1117 * @param $str (string) Input string to convert.
1118 * @return converted string
1119 * @since 5.9.121 (2011-09-28)
1120 * @public static
1121 */
1122 public static function _escapeXML($str) {
1123 $replaceTable = array("\0" => '', '&' => '&amp;', '<' => '&lt;', '>' => '&gt;');
1124 $str = strtr($str, $replaceTable);
1125 return $str;
1126 }
1127
1128 /**
1129 * Creates a copy of a class object
1130 * @param $object (object) class object to be cloned
1131 * @return cloned object
1132 * @since 4.5.029 (2009-03-19)
1133 * @public static
1134 */
1135 public static function objclone($object) {
1136 if (($object instanceof Imagick) AND (version_compare(phpversion('imagick'), '3.0.1') !== 1)) {
1137 // on the versions after 3.0.1 the clone() method was deprecated in favour of clone keyword
1138 return @$object->clone();
1139 }
1140 return @clone($object);
1141 }
1142
1143 /**
1144 * Ouput input data and compress it if possible.
1145 * @param $data (string) Data to output.
1146 * @param $length (int) Data length in bytes.
1147 * @since 5.9.086
1148 * @public static
1149 */
1150 public static function sendOutputData($data, $length) {
1151 if (!isset($_SERVER['HTTP_ACCEPT_ENCODING']) OR empty($_SERVER['HTTP_ACCEPT_ENCODING'])) {
1152 // the content length may vary if the server is using compression
1153 header('Content-Length: '.$length);
1154 }
1155 echo $data;
1156 }
1157
1158 /**
1159 * Replace page number aliases with number.
1160 * @param $page (string) Page content.
1161 * @param $replace (array) Array of replacements (array keys are replacement strings, values are alias arrays).
1162 * @param $diff (int) If passed, this will be set to the total char number difference between alias and replacements.
1163 * @return replaced page content and updated $diff parameter as array.
1164 * @public static
1165 */
1166 public static function replacePageNumAliases($page, $replace, $diff=0) {
1167 foreach ($replace as $rep) {
1168 foreach ($rep[3] as $a) {
1169 if (strpos($page, $a) !== false) {
1170 $page = str_replace($a, $rep[0], $page);
1171 $diff += ($rep[2] - $rep[1]);
1172 }
1173 }
1174 }
1175 return array($page, $diff);
1176 }
1177
1178 /**
1179 * Returns timestamp in seconds from formatted date-time.
1180 * @param $date (string) Formatted date-time.
1181 * @return int seconds.
1182 * @since 5.9.152 (2012-03-23)
1183 * @public static
1184 */
1185 public static function getTimestamp($date) {
1186 if (($date[0] == 'D') AND ($date[1] == ':')) {
1187 // remove date prefix if present
1188 $date = substr($date, 2);
1189 }
1190 return strtotime($date);
1191 }
1192
1193 /**
1194 * Returns a formatted date-time.
1195 * @param $time (int) Time in seconds.
1196 * @return string escaped date string.
1197 * @since 5.9.152 (2012-03-23)
1198 * @public static
1199 */
1200 public static function getFormattedDate($time) {
1201 return substr_replace(date('YmdHisO', intval($time)), '\'', (0 - 2), 0).'\'';
1202 }
1203
1204 /**
1205 * Get ULONG from string (Big Endian 32-bit unsigned integer).
1206 * @param $str (string) string from where to extract value
1207 * @param $offset (int) point from where to read the data
1208 * @return int 32 bit value
1209 * @author Nicola Asuni
1210 * @since 5.2.000 (2010-06-02)
1211 * @public static
1212 */
1213 public static function _getULONG($str, $offset) {
1214 $v = unpack('Ni', substr($str, $offset, 4));
1215 return $v['i'];
1216 }
1217
1218 /**
1219 * Get USHORT from string (Big Endian 16-bit unsigned integer).
1220 * @param $str (string) string from where to extract value
1221 * @param $offset (int) point from where to read the data
1222 * @return int 16 bit value
1223 * @author Nicola Asuni
1224 * @since 5.2.000 (2010-06-02)
1225 * @public static
1226 */
1227 public static function _getUSHORT($str, $offset) {
1228 $v = unpack('ni', substr($str, $offset, 2));
1229 return $v['i'];
1230 }
1231
1232 /**
1233 * Get SHORT from string (Big Endian 16-bit signed integer).
1234 * @param $str (string) String from where to extract value.
1235 * @param $offset (int) Point from where to read the data.
1236 * @return int 16 bit value
1237 * @author Nicola Asuni
1238 * @since 5.2.000 (2010-06-02)
1239 * @public static
1240 */
1241 public static function _getSHORT($str, $offset) {
1242 $v = unpack('si', substr($str, $offset, 2));
1243 return $v['i'];
1244 }
1245
1246 /**
1247 * Get FWORD from string (Big Endian 16-bit signed integer).
1248 * @param $str (string) String from where to extract value.
1249 * @param $offset (int) Point from where to read the data.
1250 * @return int 16 bit value
1251 * @author Nicola Asuni
1252 * @since 5.9.123 (2011-09-30)
1253 * @public static
1254 */
1255 public static function _getFWORD($str, $offset) {
1256 $v = self::_getUSHORT($str, $offset);
1257 if ($v > 0x7fff) {
1258 $v -= 0x10000;
1259 }
1260 return $v;
1261 }
1262
1263 /**
1264 * Get UFWORD from string (Big Endian 16-bit unsigned integer).
1265 * @param $str (string) string from where to extract value
1266 * @param $offset (int) point from where to read the data
1267 * @return int 16 bit value
1268 * @author Nicola Asuni
1269 * @since 5.9.123 (2011-09-30)
1270 * @public static
1271 */
1272 public static function _getUFWORD($str, $offset) {
1273 $v = self::_getUSHORT($str, $offset);
1274 return $v;
1275 }
1276
1277 /**
1278 * Get FIXED from string (32-bit signed fixed-point number (16.16).
1279 * @param $str (string) string from where to extract value
1280 * @param $offset (int) point from where to read the data
1281 * @return int 16 bit value
1282 * @author Nicola Asuni
1283 * @since 5.9.123 (2011-09-30)
1284 * @public static
1285 */
1286 public static function _getFIXED($str, $offset) {
1287 // mantissa
1288 $m = self::_getFWORD($str, $offset);
1289 // fraction
1290 $f = self::_getUSHORT($str, ($offset + 2));
1291 $v = floatval(''.$m.'.'.$f.'');
1292 return $v;
1293 }
1294
1295 /**
1296 * Get BYTE from string (8-bit unsigned integer).
1297 * @param $str (string) String from where to extract value.
1298 * @param $offset (int) Point from where to read the data.
1299 * @return int 8 bit value
1300 * @author Nicola Asuni
1301 * @since 5.2.000 (2010-06-02)
1302 * @public static
1303 */
1304 public static function _getBYTE($str, $offset) {
1305 $v = unpack('Ci', substr($str, $offset, 1));
1306 return $v['i'];
1307 }
1308 /**
1309 * Binary-safe and URL-safe file read.
1310 * Reads up to length bytes from the file pointer referenced by handle. Reading stops as soon as one of the following conditions is met: length bytes have been read; EOF (end of file) is reached.
1311 * @param $handle (resource)
1312 * @param $length (int)
1313 * @return Returns the read string or FALSE in case of error.
1314 * @author Nicola Asuni
1315 * @since 4.5.027 (2009-03-16)
1316 * @public static
1317 */
1318 public static function rfread($handle, $length) {
1319 $data = fread($handle, $length);
1320 if ($data === false) {
1321 return false;
1322 }
1323 $rest = ($length - strlen($data));
1324 if ($rest > 0) {
1325 $data .= self::rfread($handle, $rest);
1326 }
1327 return $data;
1328 }
1329
1330 /**
1331 * Read a 4-byte (32 bit) integer from file.
1332 * @param $f (string) file name.
1333 * @return 4-byte integer
1334 * @public static
1335 */
1336 public static function _freadint($f) {
1337 $a = unpack('Ni', fread($f, 4));
1338 return $a['i'];
1339 }
1340
1341 /**
1342 * Returns a string containing random data to be used as a seed for encryption methods.
1343 * @param $seed (string) starting seed value
1344 * @return string containing random data
1345 * @author Nicola Asuni
1346 * @since 5.9.006 (2010-10-19)
1347 * @public static
1348 */
1349 public static function getRandomSeed($seed='') {
1350 $seed .= microtime();
1351 if (function_exists('openssl_random_pseudo_bytes') AND (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')) {
1352 // this is not used on windows systems because it is very slow for a know bug
1353 $seed .= openssl_random_pseudo_bytes(512);
1354 } else {
1355 for ($i = 0; $i < 23; ++$i) {
1356 $seed .= uniqid('', true);
1357 }
1358 }
1359 $seed .= uniqid('', true);
1360 $seed .= rand();
1361 $seed .= __FILE__;
1362 if (isset($_SERVER['REMOTE_ADDR'])) {
1363 $seed .= $_SERVER['REMOTE_ADDR'];
1364 }
1365 if (isset($_SERVER['HTTP_USER_AGENT'])) {
1366 $seed .= $_SERVER['HTTP_USER_AGENT'];
1367 }
1368 if (isset($_SERVER['HTTP_ACCEPT'])) {
1369 $seed .= $_SERVER['HTTP_ACCEPT'];
1370 }
1371 if (isset($_SERVER['HTTP_ACCEPT_ENCODING'])) {
1372 $seed .= $_SERVER['HTTP_ACCEPT_ENCODING'];
1373 }
1374 if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
1375 $seed .= $_SERVER['HTTP_ACCEPT_LANGUAGE'];
1376 }
1377 if (isset($_SERVER['HTTP_ACCEPT_CHARSET'])) {
1378 $seed .= $_SERVER['HTTP_ACCEPT_CHARSET'];
1379 }
1380 $seed .= rand();
1381 $seed .= uniqid('', true);
1382 $seed .= microtime();
1383 return $seed;
1384 }
1385
1386 /**
1387 * Encrypts a string using MD5 and returns it's value as a binary string.
1388 * @param $str (string) input string
1389 * @return String MD5 encrypted binary string
1390 * @since 2.0.000 (2008-01-02)
1391 * @public static
1392 */
1393 public static function _md5_16($str) {
1394 return pack('H*', md5($str));
1395 }
1396
1397 /**
1398 * Returns the input text exrypted using AES algorithm and the specified key.
1399 * This method requires mcrypt.
1400 * @param $key (string) encryption key
1401 * @param $text (String) input text to be encrypted
1402 * @return String encrypted text
1403 * @author Nicola Asuni
1404 * @since 5.0.005 (2010-05-11)
1405 * @public static
1406 */
1407 public static function _AES($key, $text) {
1408 // padding (RFC 2898, PKCS #5: Password-Based Cryptography Specification Version 2.0)
1409 $padding = 16 - (strlen($text) % 16);
1410 $text .= str_repeat(chr($padding), $padding);
1411 $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC), MCRYPT_RAND);
1412 $text = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $text, MCRYPT_MODE_CBC, $iv);
1413 $text = $iv.$text;
1414 return $text;
1415 }
1416
1417 /**
1418 * Returns the input text encrypted using RC4 algorithm and the specified key.
1419 * RC4 is the standard encryption algorithm used in PDF format
1420 * @param $key (string) Encryption key.
1421 * @param $text (String) Input text to be encrypted.
1422 * @param $last_enc_key (String) Reference to last RC4 key encrypted.
1423 * @param $last_enc_key_c (String) Reference to last RC4 computed key.
1424 * @return String encrypted text
1425 * @since 2.0.000 (2008-01-02)
1426 * @author Klemen Vodopivec, Nicola Asuni
1427 * @public static
1428 */
1429 public static function _RC4($key, $text, &$last_enc_key, &$last_enc_key_c) {
1430 if (function_exists('mcrypt_encrypt') AND ($out = @mcrypt_encrypt(MCRYPT_ARCFOUR, $key, $text, MCRYPT_MODE_STREAM, ''))) {
1431 // try to use mcrypt function if exist
1432 return $out;
1433 }
1434 if ($last_enc_key != $key) {
1435 $k = str_repeat($key, ((256 / strlen($key)) + 1));
1436 $rc4 = range(0, 255);
1437 $j = 0;
1438 for ($i = 0; $i < 256; ++$i) {
1439 $t = $rc4[$i];
1440 $j = ($j + $t + ord($k[$i])) % 256;
1441 $rc4[$i] = $rc4[$j];
1442 $rc4[$j] = $t;
1443 }
1444 $last_enc_key = $key;
1445 $last_enc_key_c = $rc4;
1446 } else {
1447 $rc4 = $last_enc_key_c;
1448 }
1449 $len = strlen($text);
1450 $a = 0;
1451 $b = 0;
1452 $out = '';
1453 for ($i = 0; $i < $len; ++$i) {
1454 $a = ($a + 1) % 256;
1455 $t = $rc4[$a];
1456 $b = ($b + $t) % 256;
1457 $rc4[$a] = $rc4[$b];
1458 $rc4[$b] = $t;
1459 $k = $rc4[($rc4[$a] + $rc4[$b]) % 256];
1460 $out .= chr(ord($text[$i]) ^ $k);
1461 }
1462 return $out;
1463 }
1464
1465 /**
1466 * Return the premission code used on encryption (P value).
1467 * @param $permissions (Array) the set of permissions (specify the ones you want to block).
1468 * @param $mode (int) encryption strength: 0 = RC4 40 bit; 1 = RC4 128 bit; 2 = AES 128 bit; 3 = AES 256 bit.
1469 * @since 5.0.005 (2010-05-12)
1470 * @author Nicola Asuni
1471 * @public static
1472 */
1473 public static function getUserPermissionCode($permissions, $mode=0) {
1474 $options = array(
1475 'owner' => 2, // bit 2 -- inverted logic: cleared by default
1476 'print' => 4, // bit 3
1477 'modify' => 8, // bit 4
1478 'copy' => 16, // bit 5
1479 'annot-forms' => 32, // bit 6
1480 'fill-forms' => 256, // bit 9
1481 'extract' => 512, // bit 10
1482 'assemble' => 1024,// bit 11
1483 'print-high' => 2048 // bit 12
1484 );
1485 $protection = 2147422012; // 32 bit: (01111111 11111111 00001111 00111100)
1486 foreach ($permissions as $permission) {
1487 if (isset($options[$permission])) {
1488 if (($mode > 0) OR ($options[$permission] <= 32)) {
1489 // set only valid permissions
1490 if ($options[$permission] == 2) {
1491 // the logic for bit 2 is inverted (cleared by default)
1492 $protection += $options[$permission];
1493 } else {
1494 $protection -= $options[$permission];
1495 }
1496 }
1497 }
1498 }
1499 return $protection;
1500 }
1501
1502 /**
1503 * Convert hexadecimal string to string
1504 * @param $bs (string) byte-string to convert
1505 * @return String
1506 * @since 5.0.005 (2010-05-12)
1507 * @author Nicola Asuni
1508 * @public static
1509 */
1510 public static function convertHexStringToString($bs) {
1511 $string = ''; // string to be returned
1512 $bslength = strlen($bs);
1513 if (($bslength % 2) != 0) {
1514 // padding
1515 $bs .= '0';
1516 ++$bslength;
1517 }
1518 for ($i = 0; $i < $bslength; $i += 2) {
1519 $string .= chr(hexdec($bs[$i].$bs[($i + 1)]));
1520 }
1521 return $string;
1522 }
1523
1524 /**
1525 * Convert string to hexadecimal string (byte string)
1526 * @param $s (string) string to convert
1527 * @return byte string
1528 * @since 5.0.010 (2010-05-17)
1529 * @author Nicola Asuni
1530 * @public static
1531 */
1532 public static function convertStringToHexString($s) {
1533 $bs = '';
1534 $chars = preg_split('//', $s, -1, PREG_SPLIT_NO_EMPTY);
1535 foreach ($chars as $c) {
1536 $bs .= sprintf('%02s', dechex(ord($c)));
1537 }
1538 return $bs;
1539 }
1540
1541 /**
1542 * Convert encryption P value to a string of bytes, low-order byte first.
1543 * @param $protection (string) 32bit encryption permission value (P value)
1544 * @return String
1545 * @since 5.0.005 (2010-05-12)
1546 * @author Nicola Asuni
1547 * @public static
1548 */
1549 public static function getEncPermissionsString($protection) {
1550 $binprot = sprintf('%032b', $protection);
1551 $str = chr(bindec(substr($binprot, 24, 8)));
1552 $str .= chr(bindec(substr($binprot, 16, 8)));
1553 $str .= chr(bindec(substr($binprot, 8, 8)));
1554 $str .= chr(bindec(substr($binprot, 0, 8)));
1555 return $str;
1556 }
1557
1558 /**
1559 * Encode a name object.
1560 * @param $name (string) Name object to encode.
1561 * @return (string) Encoded name object.
1562 * @author Nicola Asuni
1563 * @since 5.9.097 (2011-06-23)
1564 * @public static
1565 */
1566 public static function encodeNameObject($name) {
1567 $escname = '';
1568 $length = strlen($name);
1569 for ($i = 0; $i < $length; ++$i) {
1570 $chr = $name[$i];
1571 if (preg_match('/[0-9a-zA-Z#_=-]/', $chr) == 1) {
1572 $escname .= $chr;
1573 } else {
1574 $escname .= sprintf('#%02X', ord($chr));
1575 }
1576 }
1577 return $escname;
1578 }
1579
1580 /**
1581 * Convert JavaScript form fields properties array to Annotation Properties array.
1582 * @param $prop (array) javascript field properties. Possible values are described on official Javascript for Acrobat API reference.
1583 * @param $spot_colors (array) Reference to spot colors array.
1584 * @param $rtl (boolean) True if in Right-To-Left text direction mode, false otherwise.
1585 * @return array of annotation properties
1586 * @author Nicola Asuni
1587 * @since 4.8.000 (2009-09-06)
1588 * @public static
1589 */
1590 public static function getAnnotOptFromJSProp($prop, &$spot_colors, $rtl=false) {
1591 if (isset($prop['aopt']) AND is_array($prop['aopt'])) {
1592 // the annotation options area lready defined
1593 return $prop['aopt'];
1594 }
1595 $opt = array(); // value to be returned
1596 // alignment: Controls how the text is laid out within the text field.
1597 if (isset($prop['alignment'])) {
1598 switch ($prop['alignment']) {
1599 case 'left': {
1600 $opt['q'] = 0;
1601 break;
1602 }
1603 case 'center': {
1604 $opt['q'] = 1;
1605 break;
1606 }
1607 case 'right': {
1608 $opt['q'] = 2;
1609 break;
1610 }
1611 default: {
1612 $opt['q'] = ($rtl)?2:0;
1613 break;
1614 }
1615 }
1616 }
1617 // lineWidth: Specifies the thickness of the border when stroking the perimeter of a field's rectangle.
1618 if (isset($prop['lineWidth'])) {
1619 $linewidth = intval($prop['lineWidth']);
1620 } else {
1621 $linewidth = 1;
1622 }
1623 // borderStyle: The border style for a field.
1624 if (isset($prop['borderStyle'])) {
1625 switch ($prop['borderStyle']) {
1626 case 'border.d':
1627 case 'dashed': {
1628 $opt['border'] = array(0, 0, $linewidth, array(3, 2));
1629 $opt['bs'] = array('w'=>$linewidth, 's'=>'D', 'd'=>array(3, 2));
1630 break;
1631 }
1632 case 'border.b':
1633 case 'beveled': {
1634 $opt['border'] = array(0, 0, $linewidth);
1635 $opt['bs'] = array('w'=>$linewidth, 's'=>'B');
1636 break;
1637 }
1638 case 'border.i':
1639 case 'inset': {
1640 $opt['border'] = array(0, 0, $linewidth);
1641 $opt['bs'] = array('w'=>$linewidth, 's'=>'I');
1642 break;
1643 }
1644 case 'border.u':
1645 case 'underline': {
1646 $opt['border'] = array(0, 0, $linewidth);
1647 $opt['bs'] = array('w'=>$linewidth, 's'=>'U');
1648 break;
1649 }
1650 case 'border.s':
1651 case 'solid': {
1652 $opt['border'] = array(0, 0, $linewidth);
1653 $opt['bs'] = array('w'=>$linewidth, 's'=>'S');
1654 break;
1655 }
1656 default: {
1657 break;
1658 }
1659 }
1660 }
1661 if (isset($prop['border']) AND is_array($prop['border'])) {
1662 $opt['border'] = $prop['border'];
1663 }
1664 if (!isset($opt['mk'])) {
1665 $opt['mk'] = array();
1666 }
1667 if (!isset($opt['mk']['if'])) {
1668 $opt['mk']['if'] = array();
1669 }
1670 $opt['mk']['if']['a'] = array(0.5, 0.5);
1671 // buttonAlignX: Controls how space is distributed from the left of the button face with respect to the icon.
1672 if (isset($prop['buttonAlignX'])) {
1673 $opt['mk']['if']['a'][0] = $prop['buttonAlignX'];
1674 }
1675 // buttonAlignY: Controls how unused space is distributed from the bottom of the button face with respect to the icon.
1676 if (isset($prop['buttonAlignY'])) {
1677 $opt['mk']['if']['a'][1] = $prop['buttonAlignY'];
1678 }
1679 // buttonFitBounds: If true, the extent to which the icon may be scaled is set to the bounds of the button field.
1680 if (isset($prop['buttonFitBounds']) AND ($prop['buttonFitBounds'] == 'true')) {
1681 $opt['mk']['if']['fb'] = true;
1682 }
1683 // buttonScaleHow: Controls how the icon is scaled (if necessary) to fit inside the button face.
1684 if (isset($prop['buttonScaleHow'])) {
1685 switch ($prop['buttonScaleHow']) {
1686 case 'scaleHow.proportional': {
1687 $opt['mk']['if']['s'] = 'P';
1688 break;
1689 }
1690 case 'scaleHow.anamorphic': {
1691 $opt['mk']['if']['s'] = 'A';
1692 break;
1693 }
1694 }
1695 }
1696 // buttonScaleWhen: Controls when an icon is scaled to fit inside the button face.
1697 if (isset($prop['buttonScaleWhen'])) {
1698 switch ($prop['buttonScaleWhen']) {
1699 case 'scaleWhen.always': {
1700 $opt['mk']['if']['sw'] = 'A';
1701 break;
1702 }
1703 case 'scaleWhen.never': {
1704 $opt['mk']['if']['sw'] = 'N';
1705 break;
1706 }
1707 case 'scaleWhen.tooBig': {
1708 $opt['mk']['if']['sw'] = 'B';
1709 break;
1710 }
1711 case 'scaleWhen.tooSmall': {
1712 $opt['mk']['if']['sw'] = 'S';
1713 break;
1714 }
1715 }
1716 }
1717 // buttonPosition: Controls how the text and the icon of the button are positioned with respect to each other within the button face.
1718 if (isset($prop['buttonPosition'])) {
1719 switch ($prop['buttonPosition']) {
1720 case 0:
1721 case 'position.textOnly': {
1722 $opt['mk']['tp'] = 0;
1723 break;
1724 }
1725 case 1:
1726 case 'position.iconOnly': {
1727 $opt['mk']['tp'] = 1;
1728 break;
1729 }
1730 case 2:
1731 case 'position.iconTextV': {
1732 $opt['mk']['tp'] = 2;
1733 break;
1734 }
1735 case 3:
1736 case 'position.textIconV': {
1737 $opt['mk']['tp'] = 3;
1738 break;
1739 }
1740 case 4:
1741 case 'position.iconTextH': {
1742 $opt['mk']['tp'] = 4;
1743 break;
1744 }
1745 case 5:
1746 case 'position.textIconH': {
1747 $opt['mk']['tp'] = 5;
1748 break;
1749 }
1750 case 6:
1751 case 'position.overlay': {
1752 $opt['mk']['tp'] = 6;
1753 break;
1754 }
1755 }
1756 }
1757 // fillColor: Specifies the background color for a field.
1758 if (isset($prop['fillColor'])) {
1759 if (is_array($prop['fillColor'])) {
1760 $opt['mk']['bg'] = $prop['fillColor'];
1761 } else {
1762 $opt['mk']['bg'] = TCPDF_COLORS::convertHTMLColorToDec($prop['fillColor'], $spot_colors);
1763 }
1764 }
1765 // 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.
1766 if (isset($prop['strokeColor'])) {
1767 if (is_array($prop['strokeColor'])) {
1768 $opt['mk']['bc'] = $prop['strokeColor'];
1769 } else {
1770 $opt['mk']['bc'] = TCPDF_COLORS::convertHTMLColorToDec($prop['strokeColor'], $spot_colors);
1771 }
1772 }
1773 // rotation: The rotation of a widget in counterclockwise increments.
1774 if (isset($prop['rotation'])) {
1775 $opt['mk']['r'] = $prop['rotation'];
1776 }
1777 // charLimit: Limits the number of characters that a user can type into a text field.
1778 if (isset($prop['charLimit'])) {
1779 $opt['maxlen'] = intval($prop['charLimit']);
1780 }
1781 if (!isset($ff)) {
1782 $ff = 0; // default value
1783 }
1784 // readonly: The read-only characteristic of a field. If a field is read-only, the user can see the field but cannot change it.
1785 if (isset($prop['readonly']) AND ($prop['readonly'] == 'true')) {
1786 $ff += 1 << 0;
1787 }
1788 // required: Specifies whether a field requires a value.
1789 if (isset($prop['required']) AND ($prop['required'] == 'true')) {
1790 $ff += 1 << 1;
1791 }
1792 // multiline: Controls how text is wrapped within the field.
1793 if (isset($prop['multiline']) AND ($prop['multiline'] == 'true')) {
1794 $ff += 1 << 12;
1795 }
1796 // password: Specifies whether the field should display asterisks when data is entered in the field.
1797 if (isset($prop['password']) AND ($prop['password'] == 'true')) {
1798 $ff += 1 << 13;
1799 }
1800 // NoToggleToOff: If set, exactly one radio button shall be selected at all times; selecting the currently selected button has no effect.
1801 if (isset($prop['NoToggleToOff']) AND ($prop['NoToggleToOff'] == 'true')) {
1802 $ff += 1 << 14;
1803 }
1804 // Radio: If set, the field is a set of radio buttons.
1805 if (isset($prop['Radio']) AND ($prop['Radio'] == 'true')) {
1806 $ff += 1 << 15;
1807 }
1808 // Pushbutton: If set, the field is a pushbutton that does not retain a permanent value.
1809 if (isset($prop['Pushbutton']) AND ($prop['Pushbutton'] == 'true')) {
1810 $ff += 1 << 16;
1811 }
1812 // Combo: If set, the field is a combo box; if clear, the field is a list box.
1813 if (isset($prop['Combo']) AND ($prop['Combo'] == 'true')) {
1814 $ff += 1 << 17;
1815 }
1816 // editable: Controls whether a combo box is editable.
1817 if (isset($prop['editable']) AND ($prop['editable'] == 'true')) {
1818 $ff += 1 << 18;
1819 }
1820 // Sort: If set, the field's option items shall be sorted alphabetically.
1821 if (isset($prop['Sort']) AND ($prop['Sort'] == 'true')) {
1822 $ff += 1 << 19;
1823 }
1824 // fileSelect: If true, sets the file-select flag in the Options tab of the text field (Field is Used for File Selection).
1825 if (isset($prop['fileSelect']) AND ($prop['fileSelect'] == 'true')) {
1826 $ff += 1 << 20;
1827 }
1828 // multipleSelection: If true, indicates that a list box allows a multiple selection of items.
1829 if (isset($prop['multipleSelection']) AND ($prop['multipleSelection'] == 'true')) {
1830 $ff += 1 << 21;
1831 }
1832 // doNotSpellCheck: If true, spell checking is not performed on this editable text field.
1833 if (isset($prop['doNotSpellCheck']) AND ($prop['doNotSpellCheck'] == 'true')) {
1834 $ff += 1 << 22;
1835 }
1836 // doNotScroll: If true, the text field does not scroll and the user, therefore, is limited by the rectangular region designed for the field.
1837 if (isset($prop['doNotScroll']) AND ($prop['doNotScroll'] == 'true')) {
1838 $ff += 1 << 23;
1839 }
1840 // 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.
1841 if (isset($prop['comb']) AND ($prop['comb'] == 'true')) {
1842 $ff += 1 << 24;
1843 }
1844 // 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.
1845 if (isset($prop['radiosInUnison']) AND ($prop['radiosInUnison'] == 'true')) {
1846 $ff += 1 << 25;
1847 }
1848 // richText: If true, the field allows rich text formatting.
1849 if (isset($prop['richText']) AND ($prop['richText'] == 'true')) {
1850 $ff += 1 << 25;
1851 }
1852 // commitOnSelChange: Controls whether a field value is committed after a selection change.
1853 if (isset($prop['commitOnSelChange']) AND ($prop['commitOnSelChange'] == 'true')) {
1854 $ff += 1 << 26;
1855 }
1856 $opt['ff'] = $ff;
1857 // defaultValue: The default value of a field - that is, the value that the field is set to when the form is reset.
1858 if (isset($prop['defaultValue'])) {
1859 $opt['dv'] = $prop['defaultValue'];
1860 }
1861 $f = 4; // default value for annotation flags
1862 // readonly: The read-only characteristic of a field. If a field is read-only, the user can see the field but cannot change it.
1863 if (isset($prop['readonly']) AND ($prop['readonly'] == 'true')) {
1864 $f += 1 << 6;
1865 }
1866 // display: Controls whether the field is hidden or visible on screen and in print.
1867 if (isset($prop['display'])) {
1868 if ($prop['display'] == 'display.visible') {
1869 //
1870 } elseif ($prop['display'] == 'display.hidden') {
1871 $f += 1 << 1;
1872 } elseif ($prop['display'] == 'display.noPrint') {
1873 $f -= 1 << 2;
1874 } elseif ($prop['display'] == 'display.noView') {
1875 $f += 1 << 5;
1876 }
1877 }
1878 $opt['f'] = $f;
1879 // currentValueIndices: Reads and writes single or multiple values of a list box or combo box.
1880 if (isset($prop['currentValueIndices']) AND is_array($prop['currentValueIndices'])) {
1881 $opt['i'] = $prop['currentValueIndices'];
1882 }
1883 // value: The value of the field data that the user has entered.
1884 if (isset($prop['value'])) {
1885 if (is_array($prop['value'])) {
1886 $opt['opt'] = array();
1887 foreach ($prop['value'] AS $key => $optval) {
1888 // exportValues: An array of strings representing the export values for the field.
1889 if (isset($prop['exportValues'][$key])) {
1890 $opt['opt'][$key] = array($prop['exportValues'][$key], $prop['value'][$key]);
1891 } else {
1892 $opt['opt'][$key] = $prop['value'][$key];
1893 }
1894 }
1895 } else {
1896 $opt['v'] = $prop['value'];
1897 }
1898 }
1899 // richValue: This property specifies the text contents and formatting of a rich text field.
1900 if (isset($prop['richValue'])) {
1901 $opt['rv'] = $prop['richValue'];
1902 }
1903 // submitName: If nonempty, used during form submission instead of name. Only applicable if submitting in HTML format (that is, URL-encoded).
1904 if (isset($prop['submitName'])) {
1905 $opt['tm'] = $prop['submitName'];
1906 }
1907 // name: Fully qualified field name.
1908 if (isset($prop['name'])) {
1909 $opt['t'] = $prop['name'];
1910 }
1911 // userName: The user name (short description string) of the field.
1912 if (isset($prop['userName'])) {
1913 $opt['tu'] = $prop['userName'];
1914 }
1915 // highlight: Defines how a button reacts when a user clicks it.
1916 if (isset($prop['highlight'])) {
1917 switch ($prop['highlight']) {
1918 case 'none':
1919 case 'highlight.n': {
1920 $opt['h'] = 'N';
1921 break;
1922 }
1923 case 'invert':
1924 case 'highlight.i': {
1925 $opt['h'] = 'i';
1926 break;
1927 }
1928 case 'push':
1929 case 'highlight.p': {
1930 $opt['h'] = 'P';
1931 break;
1932 }
1933 case 'outline':
1934 case 'highlight.o': {
1935 $opt['h'] = 'O';
1936 break;
1937 }
1938 }
1939 }
1940 // Unsupported options:
1941 // - calcOrderIndex: Changes the calculation order of fields in the document.
1942 // - delay: Delays the redrawing of a field's appearance.
1943 // - defaultStyle: This property defines the default style attributes for the form field.
1944 // - style: Allows the user to set the glyph style of a check box or radio button.
1945 // - textColor, textFont, textSize
1946 return $opt;
1947 }
1948
1949 /**
1950 * Format the page numbers.
1951 * This method can be overriden for custom formats.
1952 * @param $num (int) page number
1953 * @since 4.2.005 (2008-11-06)
1954 * @public static
1955 */
1956 public static function formatPageNumber($num) {
1957 return number_format((float)$num, 0, '', '.');
1958 }
1959
1960 /**
1961 * Format the page numbers on the Table Of Content.
1962 * This method can be overriden for custom formats.
1963 * @param $num (int) page number
1964 * @since 4.5.001 (2009-01-04)
1965 * @see addTOC(), addHTMLTOC()
1966 * @public static
1967 */
1968 public static function formatTOCPageNumber($num) {
1969 return number_format((float)$num, 0, '', '.');
1970 }
1971
1972 /**
1973 * Extracts the CSS properties from a CSS string.
1974 * @param $cssdata (string) string containing CSS definitions.
1975 * @return An array where the keys are the CSS selectors and the values are the CSS properties.
1976 * @author Nicola Asuni
1977 * @since 5.1.000 (2010-05-25)
1978 * @public static
1979 */
1980 public static function extractCSSproperties($cssdata) {
1981 if (empty($cssdata)) {
1982 return array();
1983 }
1984 // remove comments
1985 $cssdata = preg_replace('/\/\*[^\*]*\*\//', '', $cssdata);
1986 // remove newlines and multiple spaces
1987 $cssdata = preg_replace('/[\s]+/', ' ', $cssdata);
1988 // remove some spaces
1989 $cssdata = preg_replace('/[\s]*([;:\{\}]{1})[\s]*/', '\\1', $cssdata);
1990 // remove empty blocks
1991 $cssdata = preg_replace('/([^\}\{]+)\{\}/', '', $cssdata);
1992 // replace media type parenthesis
1993 $cssdata = preg_replace('/@media[\s]+([^\{]*)\{/i', '@media \\1§', $cssdata);
1994 $cssdata = preg_replace('/\}\}/si', '}§', $cssdata);
1995 // trim string
1996 $cssdata = trim($cssdata);
1997 // find media blocks (all, braille, embossed, handheld, print, projection, screen, speech, tty, tv)
1998 $cssblocks = array();
1999 $matches = array();
2000 if (preg_match_all('/@media[\s]+([^\§]*)§([^§]*)§/i', $cssdata, $matches) > 0) {
2001 foreach ($matches[1] as $key => $type) {
2002 $cssblocks[$type] = $matches[2][$key];
2003 }
2004 // remove media blocks
2005 $cssdata = preg_replace('/@media[\s]+([^\§]*)§([^§]*)§/i', '', $cssdata);
2006 }
2007 // keep 'all' and 'print' media, other media types are discarded
2008 if (isset($cssblocks['all']) AND !empty($cssblocks['all'])) {
2009 $cssdata .= $cssblocks['all'];
2010 }
2011 if (isset($cssblocks['print']) AND !empty($cssblocks['print'])) {
2012 $cssdata .= $cssblocks['print'];
2013 }
2014 // reset css blocks array
2015 $cssblocks = array();
2016 $matches = array();
2017 // explode css data string into array
2018 if (substr($cssdata, -1) == '}') {
2019 // remove last parethesis
2020 $cssdata = substr($cssdata, 0, -1);
2021 }
2022 $matches = explode('}', $cssdata);
2023 foreach ($matches as $key => $block) {
2024 // index 0 contains the CSS selector, index 1 contains CSS properties
2025 $cssblocks[$key] = explode('{', $block);
2026 if (!isset($cssblocks[$key][1])) {
2027 // remove empty definitions
2028 unset($cssblocks[$key]);
2029 }
2030 }
2031 // split groups of selectors (comma-separated list of selectors)
2032 foreach ($cssblocks as $key => $block) {
2033 if (strpos($block[0], ',') > 0) {
2034 $selectors = explode(',', $block[0]);
2035 foreach ($selectors as $sel) {
2036 $cssblocks[] = array(0 => trim($sel), 1 => $block[1]);
2037 }
2038 unset($cssblocks[$key]);
2039 }
2040 }
2041 // covert array to selector => properties
2042 $cssdata = array();
2043 foreach ($cssblocks as $block) {
2044 $selector = $block[0];
2045 // calculate selector's specificity
2046 $matches = array();
2047 $a = 0; // the declaration is not from is a 'style' attribute
2048 $b = intval(preg_match_all('/[\#]/', $selector, $matches)); // number of ID attributes
2049 $c = intval(preg_match_all('/[\[\.]/', $selector, $matches)); // number of other attributes
2050 $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
2051 $d = intval(preg_match_all('/[\>\+\~\s]{1}[a-zA-Z0-9]+/', ' '.$selector, $matches)); // number of element names
2052 $d += intval(preg_match_all('/[\:][\:]/', $selector, $matches)); // number of pseudo-elements
2053 $specificity = $a.$b.$c.$d;
2054 // add specificity to the beginning of the selector
2055 $cssdata[$specificity.' '.$selector] = $block[1];
2056 }
2057 // sort selectors alphabetically to account for specificity
2058 ksort($cssdata, SORT_STRING);
2059 // return array
2060 return $cssdata;
2061 }
2062
2063 /**
2064 * Cleanup HTML code (requires HTML Tidy library).
2065 * @param $html (string) htmlcode to fix
2066 * @param $default_css (string) CSS commands to add
2067 * @param $tagvs (array) parameters for setHtmlVSpace method
2068 * @param $tidy_options (array) options for tidy_parse_string function
2069 * @param $tagvspaces (array) Array of vertical spaces for tags.
2070 * @return string XHTML code cleaned up
2071 * @author Nicola Asuni
2072 * @since 5.9.017 (2010-11-16)
2073 * @see setHtmlVSpace()
2074 * @public static
2075 */
2076 public static function fixHTMLCode($html, $default_css='', $tagvs='', $tidy_options='', &$tagvspaces) {
2077 // configure parameters for HTML Tidy
2078 if ($tidy_options === '') {
2079 $tidy_options = array (
2080 'clean' => 1,
2081 'drop-empty-paras' => 0,
2082 'drop-proprietary-attributes' => 1,
2083 'fix-backslash' => 1,
2084 'hide-comments' => 1,
2085 'join-styles' => 1,
2086 'lower-literals' => 1,
2087 'merge-divs' => 1,
2088 'merge-spans' => 1,
2089 'output-xhtml' => 1,
2090 'word-2000' => 1,
2091 'wrap' => 0,
2092 'output-bom' => 0,
2093 //'char-encoding' => 'utf8',
2094 //'input-encoding' => 'utf8',
2095 //'output-encoding' => 'utf8'
2096 );
2097 }
2098 // clean up the HTML code
2099 $tidy = tidy_parse_string($html, $tidy_options);
2100 // fix the HTML
2101 $tidy->cleanRepair();
2102 // get the CSS part
2103 $tidy_head = tidy_get_head($tidy);
2104 $css = $tidy_head->value;
2105 $css = preg_replace('/<style([^>]+)>/ims', '<style>', $css);
2106 $css = preg_replace('/<\/style>(.*)<style>/ims', "\n", $css);
2107 $css = str_replace('/*<![CDATA[*/', '', $css);
2108 $css = str_replace('/*]]>*/', '', $css);
2109 preg_match('/<style>(.*)<\/style>/ims', $css, $matches);
2110 if (isset($matches[1])) {
2111 $css = strtolower($matches[1]);
2112 } else {
2113 $css = '';
2114 }
2115 // include default css
2116 $css = '<style>'.$default_css.$css.'</style>';
2117 // get the body part
2118 $tidy_body = tidy_get_body($tidy);
2119 $html = $tidy_body->value;
2120 // fix some self-closing tags
2121 $html = str_replace('<br>', '<br />', $html);
2122 // remove some empty tag blocks
2123 $html = preg_replace('/<div([^\>]*)><\/div>/', '', $html);
2124 $html = preg_replace('/<p([^\>]*)><\/p>/', '', $html);
2125 if ($tagvs !== '') {
2126 // set vertical space for some XHTML tags
2127 $tagvspaces = $tagvs;
2128 }
2129 // return the cleaned XHTML code + CSS
2130 return $css.$html;
2131 }
2132
2133 /**
2134 * Returns true if the CSS selector is valid for the selected HTML tag
2135 * @param $dom (array) array of HTML tags and properties
2136 * @param $key (int) key of the current HTML tag
2137 * @param $selector (string) CSS selector string
2138 * @return true if the selector is valid, false otherwise
2139 * @since 5.1.000 (2010-05-25)
2140 * @public static
2141 */
2142 public static function isValidCSSSelectorForTag($dom, $key, $selector) {
2143 $valid = false; // value to be returned
2144 $tag = $dom[$key]['value'];
2145 $class = array();
2146 if (isset($dom[$key]['attribute']['class']) AND !empty($dom[$key]['attribute']['class'])) {
2147 $class = explode(' ', strtolower($dom[$key]['attribute']['class']));
2148 }
2149 $id = '';
2150 if (isset($dom[$key]['attribute']['id']) AND !empty($dom[$key]['attribute']['id'])) {
2151 $id = strtolower($dom[$key]['attribute']['id']);
2152 }
2153 $selector = preg_replace('/([\>\+\~\s]{1})([\.]{1})([^\>\+\~\s]*)/si', '\\1*.\\3', $selector);
2154 $matches = array();
2155 if (preg_match_all('/([\>\+\~\s]{1})([a-zA-Z0-9\*]+)([^\>\+\~\s]*)/si', $selector, $matches, PREG_PATTERN_ORDER | PREG_OFFSET_CAPTURE) > 0) {
2156 $parentop = array_pop($matches[1]);
2157 $operator = $parentop[0];
2158 $offset = $parentop[1];
2159 $lasttag = array_pop($matches[2]);
2160 $lasttag = strtolower(trim($lasttag[0]));
2161 if (($lasttag == '*') OR ($lasttag == $tag)) {
2162 // the last element on selector is our tag or 'any tag'
2163 $attrib = array_pop($matches[3]);
2164 $attrib = strtolower(trim($attrib[0]));
2165 if (!empty($attrib)) {
2166 // check if matches class, id, attribute, pseudo-class or pseudo-element
2167 switch ($attrib[0]) {
2168 case '.': { // class
2169 if (in_array(substr($attrib, 1), $class)) {
2170 $valid = true;
2171 }
2172 break;
2173 }
2174 case '#': { // ID
2175 if (substr($attrib, 1) == $id) {
2176 $valid = true;
2177 }
2178 break;
2179 }
2180 case '[': { // attribute
2181 $attrmatch = array();
2182 if (preg_match('/\[([a-zA-Z0-9]*)[\s]*([\~\^\$\*\|\=]*)[\s]*["]?([^"\]]*)["]?\]/i', $attrib, $attrmatch) > 0) {
2183 $att = strtolower($attrmatch[1]);
2184 $val = $attrmatch[3];
2185 if (isset($dom[$key]['attribute'][$att])) {
2186 switch ($attrmatch[2]) {
2187 case '=': {
2188 if ($dom[$key]['attribute'][$att] == $val) {
2189 $valid = true;
2190 }
2191 break;
2192 }
2193 case '~=': {
2194 if (in_array($val, explode(' ', $dom[$key]['attribute'][$att]))) {
2195 $valid = true;
2196 }
2197 break;
2198 }
2199 case '^=': {
2200 if ($val == substr($dom[$key]['attribute'][$att], 0, strlen($val))) {
2201 $valid = true;
2202 }
2203 break;
2204 }
2205 case '$=': {
2206 if ($val == substr($dom[$key]['attribute'][$att], -strlen($val))) {
2207 $valid = true;
2208 }
2209 break;
2210 }
2211 case '*=': {
2212 if (strpos($dom[$key]['attribute'][$att], $val) !== false) {
2213 $valid = true;
2214 }
2215 break;
2216 }
2217 case '|=': {
2218 if ($dom[$key]['attribute'][$att] == $val) {
2219 $valid = true;
2220 } elseif (preg_match('/'.$val.'[\-]{1}/i', $dom[$key]['attribute'][$att]) > 0) {
2221 $valid = true;
2222 }
2223 break;
2224 }
2225 default: {
2226 $valid = true;
2227 }
2228 }
2229 }
2230 }
2231 break;
2232 }
2233 case ':': { // pseudo-class or pseudo-element
2234 if ($attrib[1] == ':') { // pseudo-element
2235 // pseudo-elements are not supported!
2236 // (::first-line, ::first-letter, ::before, ::after)
2237 } else { // pseudo-class
2238 // pseudo-classes are not supported!
2239 // (: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)
2240 }
2241 break;
2242 }
2243 } // end of switch
2244 } else {
2245 $valid = true;
2246 }
2247 if ($valid AND ($offset > 0)) {
2248 $valid = false;
2249 // check remaining selector part
2250 $selector = substr($selector, 0, $offset);
2251 switch ($operator) {
2252 case ' ': { // descendant of an element
2253 while ($dom[$key]['parent'] > 0) {
2254 if (self::isValidCSSSelectorForTag($dom, $dom[$key]['parent'], $selector)) {
2255 $valid = true;
2256 break;
2257 } else {
2258 $key = $dom[$key]['parent'];
2259 }
2260 }
2261 break;
2262 }
2263 case '>': { // child of an element
2264 $valid = self::isValidCSSSelectorForTag($dom, $dom[$key]['parent'], $selector);
2265 break;
2266 }
2267 case '+': { // immediately preceded by an element
2268 for ($i = ($key - 1); $i > $dom[$key]['parent']; --$i) {
2269 if ($dom[$i]['tag'] AND $dom[$i]['opening']) {
2270 $valid = self::isValidCSSSelectorForTag($dom, $i, $selector);
2271 break;
2272 }
2273 }
2274 break;
2275 }
2276 case '~': { // preceded by an element
2277 for ($i = ($key - 1); $i > $dom[$key]['parent']; --$i) {
2278 if ($dom[$i]['tag'] AND $dom[$i]['opening']) {
2279 if (self::isValidCSSSelectorForTag($dom, $i, $selector)) {
2280 break;
2281 }
2282 }
2283 }
2284 break;
2285 }
2286 }
2287 }
2288 }
2289 }
2290 return $valid;
2291 }
2292
2293 /**
2294 * Returns the styles array that apply for the selected HTML tag.
2295 * @param $dom (array) array of HTML tags and properties
2296 * @param $key (int) key of the current HTML tag
2297 * @param $css (array) array of CSS properties
2298 * @return array containing CSS properties
2299 * @since 5.1.000 (2010-05-25)
2300 * @public static
2301 */
2302 public static function getCSSdataArray($dom, $key, $css) {
2303 $cssarray = array(); // style to be returned
2304 // get parent CSS selectors
2305 $selectors = array();
2306 if (isset($dom[($dom[$key]['parent'])]['csssel'])) {
2307 $selectors = $dom[($dom[$key]['parent'])]['csssel'];
2308 }
2309 // get all styles that apply
2310 foreach($css as $selector => $style) {
2311 $pos = strpos($selector, ' ');
2312 // get specificity
2313 $specificity = substr($selector, 0, $pos);
2314 // remove specificity
2315 $selector = substr($selector, $pos);
2316 // check if this selector apply to current tag
2317 if (self::isValidCSSSelectorForTag($dom, $key, $selector)) {
2318 if (!in_array($selector, $selectors)) {
2319 // add style if not already added on parent selector
2320 $cssarray[] = array('k' => $selector, 's' => $specificity, 'c' => $style);
2321 $selectors[] = $selector;
2322 }
2323 }
2324 }
2325 if (isset($dom[$key]['attribute']['style'])) {
2326 // attach inline style (latest properties have high priority)
2327 $cssarray[] = array('k' => '', 's' => '1000', 'c' => $dom[$key]['attribute']['style']);
2328 }
2329 // order the css array to account for specificity
2330 $cssordered = array();
2331 foreach ($cssarray as $key => $val) {
2332 $skey = sprintf('%04d', $key);
2333 $cssordered[$val['s'].'_'.$skey] = $val;
2334 }
2335 // sort selectors alphabetically to account for specificity
2336 ksort($cssordered, SORT_STRING);
2337 return array($selectors, $cssordered);
2338 }
2339
2340 /**
2341 * Compact CSS data array into single string.
2342 * @param $css (array) array of CSS properties
2343 * @return string containing merged CSS properties
2344 * @since 5.9.070 (2011-04-19)
2345 * @public static
2346 */
2347 public static function getTagStyleFromCSSarray($css) {
2348 $tagstyle = ''; // value to be returned
2349 foreach ($css as $style) {
2350 // split single css commands
2351 $csscmds = explode(';', $style['c']);
2352 foreach ($csscmds as $cmd) {
2353 if (!empty($cmd)) {
2354 $pos = strpos($cmd, ':');
2355 if ($pos !== false) {
2356 $cmd = substr($cmd, 0, ($pos + 1));
2357 if (strpos($tagstyle, $cmd) !== false) {
2358 // remove duplicate commands (last commands have high priority)
2359 $tagstyle = preg_replace('/'.$cmd.'[^;]+/i', '', $tagstyle);
2360 }
2361 }
2362 }
2363 }
2364 $tagstyle .= ';'.$style['c'];
2365 }
2366 // remove multiple semicolons
2367 $tagstyle = preg_replace('/[;]+/', ';', $tagstyle);
2368 return $tagstyle;
2369 }
2370
2371 /**
2372 * Returns the Roman representation of an integer number
2373 * @param $number (int) number to convert
2374 * @return string roman representation of the specified number
2375 * @since 4.4.004 (2008-12-10)
2376 * @public static
2377 */
2378 public static function intToRoman($number) {
2379 $roman = '';
2380 while ($number >= 1000) {
2381 $roman .= 'M';
2382 $number -= 1000;
2383 }
2384 while ($number >= 900) {
2385 $roman .= 'CM';
2386 $number -= 900;
2387 }
2388 while ($number >= 500) {
2389 $roman .= 'D';
2390 $number -= 500;
2391 }
2392 while ($number >= 400) {
2393 $roman .= 'CD';
2394 $number -= 400;
2395 }
2396 while ($number >= 100) {
2397 $roman .= 'C';
2398 $number -= 100;
2399 }
2400 while ($number >= 90) {
2401 $roman .= 'XC';
2402 $number -= 90;
2403 }
2404 while ($number >= 50) {
2405 $roman .= 'L';
2406 $number -= 50;
2407 }
2408 while ($number >= 40) {
2409 $roman .= 'XL';
2410 $number -= 40;
2411 }
2412 while ($number >= 10) {
2413 $roman .= 'X';
2414 $number -= 10;
2415 }
2416 while ($number >= 9) {
2417 $roman .= 'IX';
2418 $number -= 9;
2419 }
2420 while ($number >= 5) {
2421 $roman .= 'V';
2422 $number -= 5;
2423 }
2424 while ($number >= 4) {
2425 $roman .= 'IV';
2426 $number -= 4;
2427 }
2428 while ($number >= 1) {
2429 $roman .= 'I';
2430 --$number;
2431 }
2432 return $roman;
2433 }
2434
2435 /**
2436 * Find position of last occurrence of a substring in a string
2437 * @param $haystack (string) The string to search in.
2438 * @param $needle (string) substring to search.
2439 * @param $offset (int) May be specified to begin searching an arbitrary number of characters into the string.
2440 * @return Returns the position where the needle exists. Returns FALSE if the needle was not found.
2441 * @since 4.8.038 (2010-03-13)
2442 * @public static
2443 */
2444 public static function revstrpos($haystack, $needle, $offset = 0) {
2445 $length = strlen($haystack);
2446 $offset = ($offset > 0)?($length - $offset):abs($offset);
2447 $pos = strpos(strrev($haystack), strrev($needle), $offset);
2448 return ($pos === false)?false:($length - $pos - strlen($needle));
2449 }
2450
2451 /**
2452 * Serialize an array of parameters to be used with TCPDF tag in HTML code.
2453 * @param $data (array) parameters array
2454 * @return string containing serialized data
2455 * @since 4.9.006 (2010-04-02)
2456 * @public static
2457 */
2458 public static function serializeTCPDFtagParameters($data) {
2459 return urlencode(json_encode($data));
2460 }
2461
2462 /**
2463 * Unserialize parameters to be used with TCPDF tag in HTML code.
2464 * @param $data (string) serialized data
2465 * @return array containing unserialized data
2466 * @public static
2467 */
2468 public static function unserializeTCPDFtagParameters($data) {
2469 return json_decode(urldecode($data), true);
2470 }
2471
2472 /**
2473 * Returns an array of hyphenation patterns.
2474 * @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/
2475 * @return array of hyphenation patterns
2476 * @author Nicola Asuni
2477 * @since 4.9.012 (2010-04-12)
2478 * @public static
2479 */
2480 public static function getHyphenPatternsFromTEX($file) {
2481 // TEX patterns are available at:
2482 // http://www.ctan.org/tex-archive/language/hyph-utf8/tex/generic/hyph-utf8/patterns/
2483 $data = file_get_contents($file);
2484 $patterns = array();
2485 // remove comments
2486 $data = preg_replace('/\%[^\n]*/', '', $data);
2487 // extract the patterns part
2488 preg_match('/\\\\patterns\{([^\}]*)\}/i', $data, $matches);
2489 $data = trim(substr($matches[0], 10, -1));
2490 // extract each pattern
2491 $patterns_array = preg_split('/[\s]+/', $data);
2492 // create new language array of patterns
2493 $patterns = array();
2494 foreach($patterns_array as $val) {
2495 if (!TCPDF_STATIC::empty_string($val)) {
2496 $val = trim($val);
2497 $val = str_replace('\'', '\\\'', $val);
2498 $key = preg_replace('/[0-9]+/', '', $val);
2499 $patterns[$key] = $val;
2500 }
2501 }
2502 return $patterns;
2503 }
2504
2505 /**
2506 * Get the Path-Painting Operators.
2507 * @param $style (string) Style of rendering. Possible values are:
2508 * <ul>
2509 * <li>S or D: Stroke the path.</li>
2510 * <li>s or d: Close and stroke the path.</li>
2511 * <li>f or F: Fill the path, using the nonzero winding number rule to determine the region to fill.</li>
2512 * <li>f* or F*: Fill the path, using the even-odd rule to determine the region to fill.</li>
2513 * <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>
2514 * <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>
2515 * <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>
2516 * <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>
2517 * <li>CNZ: Clipping mode using the even-odd rule to determine which regions lie inside the clipping path.</li>
2518 * <li>CEO: Clipping mode using the nonzero winding number rule to determine which regions lie inside the clipping path</li>
2519 * <li>n: End the path object without filling or stroking it.</li>
2520 * </ul>
2521 * @param $default (string) default style
2522 * @author Nicola Asuni
2523 * @since 5.0.000 (2010-04-30)
2524 * @public static
2525 */
2526 public static function getPathPaintOperator($style, $default='S') {
2527 $op = '';
2528 switch($style) {
2529 case 'S':
2530 case 'D': {
2531 $op = 'S';
2532 break;
2533 }
2534 case 's':
2535 case 'd': {
2536 $op = 's';
2537 break;
2538 }
2539 case 'f':
2540 case 'F': {
2541 $op = 'f';
2542 break;
2543 }
2544 case 'f*':
2545 case 'F*': {
2546 $op = 'f*';
2547 break;
2548 }
2549 case 'B':
2550 case 'FD':
2551 case 'DF': {
2552 $op = 'B';
2553 break;
2554 }
2555 case 'B*':
2556 case 'F*D':
2557 case 'DF*': {
2558 $op = 'B*';
2559 break;
2560 }
2561 case 'b':
2562 case 'fd':
2563 case 'df': {
2564 $op = 'b';
2565 break;
2566 }
2567 case 'b*':
2568 case 'f*d':
2569 case 'df*': {
2570 $op = 'b*';
2571 break;
2572 }
2573 case 'CNZ': {
2574 $op = 'W n';
2575 break;
2576 }
2577 case 'CEO': {
2578 $op = 'W* n';
2579 break;
2580 }
2581 case 'n': {
2582 $op = 'n';
2583 break;
2584 }
2585 default: {
2586 if (!empty($default)) {
2587 $op = self::getPathPaintOperator($default, '');
2588 } else {
2589 $op = '';
2590 }
2591 }
2592 }
2593 return $op;
2594 }
2595
2596 /**
2597 * Get the product of two SVG tranformation matrices
2598 * @param $ta (array) first SVG tranformation matrix
2599 * @param $tb (array) second SVG tranformation matrix
2600 * @return transformation array
2601 * @author Nicola Asuni
2602 * @since 5.0.000 (2010-05-02)
2603 * @public static
2604 */
2605 public static function getTransformationMatrixProduct($ta, $tb) {
2606 $tm = array();
2607 $tm[0] = ($ta[0] * $tb[0]) + ($ta[2] * $tb[1]);
2608 $tm[1] = ($ta[1] * $tb[0]) + ($ta[3] * $tb[1]);
2609 $tm[2] = ($ta[0] * $tb[2]) + ($ta[2] * $tb[3]);
2610 $tm[3] = ($ta[1] * $tb[2]) + ($ta[3] * $tb[3]);
2611 $tm[4] = ($ta[0] * $tb[4]) + ($ta[2] * $tb[5]) + $ta[4];
2612 $tm[5] = ($ta[1] * $tb[4]) + ($ta[3] * $tb[5]) + $ta[5];
2613 return $tm;
2614 }
2615
2616 /**
2617 * Get the tranformation matrix from SVG transform attribute
2618 * @param $attribute (string) transformation
2619 * @return array of transformations
2620 * @author Nicola Asuni
2621 * @since 5.0.000 (2010-05-02)
2622 * @public static
2623 */
2624 public static function getSVGTransformMatrix($attribute) {
2625 // identity matrix
2626 $tm = array(1, 0, 0, 1, 0, 0);
2627 $transform = array();
2628 if (preg_match_all('/(matrix|translate|scale|rotate|skewX|skewY)[\s]*\(([^\)]+)\)/si', $attribute, $transform, PREG_SET_ORDER) > 0) {
2629 foreach ($transform as $key => $data) {
2630 if (!empty($data[2])) {
2631 $a = 1;
2632 $b = 0;
2633 $c = 0;
2634 $d = 1;
2635 $e = 0;
2636 $f = 0;
2637 $regs = array();
2638 switch ($data[1]) {
2639 case 'matrix': {
2640 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)) {
2641 $a = $regs[1];
2642 $b = $regs[2];
2643 $c = $regs[3];
2644 $d = $regs[4];
2645 $e = $regs[5];
2646 $f = $regs[6];
2647 }
2648 break;
2649 }
2650 case 'translate': {
2651 if (preg_match('/([a-z0-9\-\.]+)[\,\s]+([a-z0-9\-\.]+)/si', $data[2], $regs)) {
2652 $e = $regs[1];
2653 $f = $regs[2];
2654 } elseif (preg_match('/([a-z0-9\-\.]+)/si', $data[2], $regs)) {
2655 $e = $regs[1];
2656 }
2657 break;
2658 }
2659 case 'scale': {
2660 if (preg_match('/([a-z0-9\-\.]+)[\,\s]+([a-z0-9\-\.]+)/si', $data[2], $regs)) {
2661 $a = $regs[1];
2662 $d = $regs[2];
2663 } elseif (preg_match('/([a-z0-9\-\.]+)/si', $data[2], $regs)) {
2664 $a = $regs[1];
2665 $d = $a;
2666 }
2667 break;
2668 }
2669 case 'rotate': {
2670 if (preg_match('/([0-9\-\.]+)[\,\s]+([a-z0-9\-\.]+)[\,\s]+([a-z0-9\-\.]+)/si', $data[2], $regs)) {
2671 $ang = deg2rad($regs[1]);
2672 $x = $regs[2];
2673 $y = $regs[3];
2674 $a = cos($ang);
2675 $b = sin($ang);
2676 $c = -$b;
2677 $d = $a;
2678 $e = ($x * (1 - $a)) - ($y * $c);
2679 $f = ($y * (1 - $d)) - ($x * $b);
2680 } elseif (preg_match('/([0-9\-\.]+)/si', $data[2], $regs)) {
2681 $ang = deg2rad($regs[1]);
2682 $a = cos($ang);
2683 $b = sin($ang);
2684 $c = -$b;
2685 $d = $a;
2686 $e = 0;
2687 $f = 0;
2688 }
2689 break;
2690 }
2691 case 'skewX': {
2692 if (preg_match('/([0-9\-\.]+)/si', $data[2], $regs)) {
2693 $c = tan(deg2rad($regs[1]));
2694 }
2695 break;
2696 }
2697 case 'skewY': {
2698 if (preg_match('/([0-9\-\.]+)/si', $data[2], $regs)) {
2699 $b = tan(deg2rad($regs[1]));
2700 }
2701 break;
2702 }
2703 }
2704 $tm = self::getTransformationMatrixProduct($tm, array($a, $b, $c, $d, $e, $f));
2705 }
2706 }
2707 }
2708 return $tm;
2709 }
2710
2711 /**
2712 * Returns the angle in radiants between two vectors
2713 * @param $x1 (int) X coordinate of first vector point
2714 * @param $y1 (int) Y coordinate of first vector point
2715 * @param $x2 (int) X coordinate of second vector point
2716 * @param $y2 (int) Y coordinate of second vector point
2717 * @author Nicola Asuni
2718 * @since 5.0.000 (2010-05-04)
2719 * @public static
2720 */
2721 public static function getVectorsAngle($x1, $y1, $x2, $y2) {
2722 $dprod = ($x1 * $x2) + ($y1 * $y2);
2723 $dist1 = sqrt(($x1 * $x1) + ($y1 * $y1));
2724 $dist2 = sqrt(($x2 * $x2) + ($y2 * $y2));
2725 $angle = acos($dprod / ($dist1 * $dist2));
2726 if (is_nan($angle)) {
2727 $angle = M_PI;
2728 }
2729 if ((($x1 * $y2) - ($x2 * $y1)) < 0) {
2730 $angle *= -1;
2731 }
2732 return $angle;
2733 }
2734
2735 /**
2736 * Split string by a regular expression.
2737 * This is a wrapper for the preg_split function to avoid the bug: https://bugs.php.net/bug.php?id=45850
2738 * @param $pattern (string) The regular expression pattern to search for without the modifiers, as a string.
2739 * @param $modifiers (string) The modifiers part of the pattern,
2740 * @param $subject (string) The input string.
2741 * @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.
2742 * @param $flags (int) The flags as specified on the preg_split PHP function.
2743 * @return Returns an array containing substrings of subject split along boundaries matched by pattern.modifier
2744 * @author Nicola Asuni
2745 * @since 6.0.023
2746 * @public static
2747 */
2748 public static function pregSplit($pattern, $modifiers, $subject, $limit=NULL, $flags=NULL) {
2749 // the bug only happens on PHP 5.2 when using the u modifier
2750 if ((strpos($modifiers, 'u') === FALSE) OR (count(preg_split('//u', "\n\t", -1, PREG_SPLIT_NO_EMPTY)) == 2)) {
2751 return preg_split($pattern.$modifiers, $subject, $limit, $flags);
2752 }
2753 // preg_split is bugged - try alternative solution
2754 $ret = array();
2755 while (($nl = strpos($subject, "\n")) !== FALSE) {
2756 $ret = array_merge($ret, preg_split($pattern.$modifiers, substr($subject, 0, $nl), $limit, $flags));
2757 $ret[] = "\n";
2758 $subject = substr($subject, ($nl + 1));
2759 }
2760 if (strlen($subject) > 0) {
2761 $ret = array_merge($ret, preg_split($pattern.$modifiers, $subject, $limit, $flags));
2762 }
2763 return $ret;
2764 }
2765
2766 /**
2767 * Reads entire file into a string.
2768 * The file can be also an URL.
2769 * @param $file (string) Name of the file or URL to read.
2770 * @return The function returns the read data or FALSE on failure.
2771 * @author Nicola Asuni
2772 * @since 6.0.025
2773 * @public static
2774 */
2775 public static function fileGetContents($file) {
2776 //$file = html_entity_decode($file);
2777 // array of possible alternative paths/URLs
2778 $alt = array($file);
2779 // replace URL relative path with full real server path
2780 if ((strlen($file) > 1)
2781 AND ($file[0] == '/')
2782 AND ($file[1] != '/')
2783 AND !empty($_SERVER['DOCUMENT_ROOT'])
2784 AND ($_SERVER['DOCUMENT_ROOT'] != '/')) {
2785 $findroot = strpos($file, $_SERVER['DOCUMENT_ROOT']);
2786 if (($findroot === false) OR ($findroot > 1)) {
2787 if (substr($_SERVER['DOCUMENT_ROOT'], -1) == '/') {
2788 $tmp = substr($_SERVER['DOCUMENT_ROOT'], 0, -1).$file;
2789 } else {
2790 $tmp = $_SERVER['DOCUMENT_ROOT'].$file;
2791 }
2792 $alt[] = htmlspecialchars_decode(urldecode($tmp));
2793 }
2794 }
2795 // URL mode
2796 $url = $file;
2797 // check for missing protocol
2798 if (preg_match('%^/{2}%', $url)) {
2799 if (preg_match('%^([^:]+:)//%i', K_PATH_URL, $match)) {
2800 $url = $match[1].str_replace(' ', '%20', $url);
2801 $alt[] = $url;
2802 }
2803 }
2804 $urldata = @parse_url($url);
2805 if (!isset($urldata['query']) OR (strlen($urldata['query']) <= 0)) {
2806 if (strpos($url, K_PATH_URL) === 0) {
2807 // convert URL to full server path
2808 $tmp = str_replace(K_PATH_URL, K_PATH_MAIN, $url);
2809 $tmp = htmlspecialchars_decode(urldecode($tmp));
2810 $alt[] = $tmp;
2811 }
2812 }
2813 if (isset($_SERVER['SCRIPT_URI'])) {
2814 $urldata = @parse_url($_SERVER['SCRIPT_URI']);
2815 $alt[] = $urldata['scheme'].'://'.$urldata['host'].(($file[0] == '/') ? '' : '/').$file;
2816 }
2817 foreach ($alt as $f) {
2818 $ret = @file_get_contents($f);
2819 if (($ret === FALSE)
2820 AND !ini_get('allow_url_fopen')
2821 AND function_exists('curl_init')
2822 AND preg_match('%^(https?|ftp)://%', $f)) {
2823 // try to get remote file data using cURL
2824 $cs = curl_init(); // curl session
2825 curl_setopt($cs, CURLOPT_URL, $f);
2826 curl_setopt($cs, CURLOPT_BINARYTRANSFER, true);
2827 curl_setopt($cs, CURLOPT_FAILONERROR, true);
2828 curl_setopt($cs, CURLOPT_RETURNTRANSFER, true);
2829 if ((ini_get('open_basedir') == '') AND (!ini_get('safe_mode'))) {
2830 curl_setopt($cs, CURLOPT_FOLLOWLOCATION, true);
2831 }
2832 curl_setopt($cs, CURLOPT_CONNECTTIMEOUT, 5);
2833 curl_setopt($cs, CURLOPT_TIMEOUT, 30);
2834 curl_setopt($cs, CURLOPT_SSL_VERIFYPEER, false);
2835 curl_setopt($cs, CURLOPT_SSL_VERIFYHOST, false);
2836 curl_setopt($cs, CURLOPT_USERAGENT, 'TCPDF');
2837 $ret = curl_exec($cs);
2838 curl_close($cs);
2839 }
2840 if ($ret !== FALSE) {
2841 break;
2842 }
2843 }
2844 return $ret;
2845 }
2846
2847} // END OF TCPDF_STATIC CLASS
2848
2849//============================================================+
2850// END OF FILE
2851//============================================================+
diff --git a/inc/3rdparty/libraries/tcpdf/tcpdf.php b/inc/3rdparty/libraries/tcpdf/tcpdf.php
new file mode 100644
index 00000000..70c1747a
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/tcpdf.php
@@ -0,0 +1,24579 @@
1<?php
2//============================================================+
3// File name : tcpdf.php
4// Version : 6.0.093
5// Begin : 2002-08-03
6// Last Update : 2014-09-02
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-2014 Nicola Asuni - Tecnick.com LTD
11//
12// This file is part of TCPDF software library.
13//
14// TCPDF is free software: you can ioredistribute 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// This is a PHP class for generating PDF documents without requiring external extensions.
33//
34// NOTE:
35// This class was originally derived in 2002 from the Public
36// Domain FPDF class by Olivier Plathey (http://www.fpdf.org),
37// but now is almost entirely rewritten and contains thousands of
38// new lines of code and hundreds new features.
39//
40// Main features:
41// * no external libraries are required for the basic functions;
42// * all standard page formats, custom page formats, custom margins and units of measure;
43// * UTF-8 Unicode and Right-To-Left languages;
44// * TrueTypeUnicode, TrueType, Type1 and CID-0 fonts;
45// * font subsetting;
46// * methods to publish some XHTML + CSS code, Javascript and Forms;
47// * images, graphic (geometric figures) and transformation methods;
48// * supports JPEG, PNG and SVG images natively, all images supported by GD (GD, GD2, GD2PART, GIF, JPEG, PNG, BMP, XBM, XPM) and all images supported via ImagMagick (http://www.imagemagick.org/www/formats.html)
49// * 1D and 2D barcodes: CODE 39, ANSI MH10.8M-1983, USD-3, 3 of 9, CODE 93, USS-93, Standard 2 of 5, Interleaved 2 of 5, CODE 128 A/B/C, 2 and 5 Digits UPC-Based Extention, EAN 8, EAN 13, UPC-A, UPC-E, MSI, POSTNET, PLANET, RMS4CC (Royal Mail 4-state Customer Code), CBC (Customer Bar Code), KIX (Klant index - Customer index), Intelligent Mail Barcode, Onecode, USPS-B-3200, CODABAR, CODE 11, PHARMACODE, PHARMACODE TWO-TRACKS, Datamatrix, QR-Code, PDF417;
50// * JPEG and PNG ICC profiles, Grayscale, RGB, CMYK, Spot Colors and Transparencies;
51// * automatic page header and footer management;
52// * document encryption up to 256 bit and digital signature certifications;
53// * transactions to UNDO commands;
54// * PDF annotations, including links, text and file attachments;
55// * text rendering modes (fill, stroke and clipping);
56// * multiple columns mode;
57// * no-write page regions;
58// * bookmarks, named destinations and table of content;
59// * text hyphenation;
60// * text stretching and spacing (tracking);
61// * automatic page break, line break and text alignments including justification;
62// * automatic page numbering and page groups;
63// * move and delete pages;
64// * page compression (requires php-zlib extension);
65// * XOBject Templates;
66// * Layers and object visibility.
67// * PDF/A-1b support
68//============================================================+
69
70/**
71 * @file
72 * This is a PHP class for generating PDF documents without requiring external extensions.<br>
73 * TCPDF project (http://www.tcpdf.org) was originally derived in 2002 from the Public Domain FPDF class by Olivier Plathey (http://www.fpdf.org), but now is almost entirely rewritten.<br>
74 * <h3>TCPDF main features are:</h3>
75 * <ul>
76 * <li>no external libraries are required for the basic functions;</li>
77 * <li>all standard page formats, custom page formats, custom margins and units of measure;</li>
78 * <li>UTF-8 Unicode and Right-To-Left languages;</li>
79 * <li>TrueTypeUnicode, TrueType, Type1 and CID-0 fonts;</li>
80 * <li>font subsetting;</li>
81 * <li>methods to publish some XHTML + CSS code, Javascript and Forms;</li>
82 * <li>images, graphic (geometric figures) and transformation methods;
83 * <li>supports JPEG, PNG and SVG images natively, all images supported by GD (GD, GD2, GD2PART, GIF, JPEG, PNG, BMP, XBM, XPM) and all images supported via ImagMagick (http://www.imagemagick.org/www/formats.html)</li>
84 * <li>1D and 2D barcodes: CODE 39, ANSI MH10.8M-1983, USD-3, 3 of 9, CODE 93, USS-93, Standard 2 of 5, Interleaved 2 of 5, CODE 128 A/B/C, 2 and 5 Digits UPC-Based Extention, EAN 8, EAN 13, UPC-A, UPC-E, MSI, POSTNET, PLANET, RMS4CC (Royal Mail 4-state Customer Code), CBC (Customer Bar Code), KIX (Klant index - Customer index), Intelligent Mail Barcode, Onecode, USPS-B-3200, CODABAR, CODE 11, PHARMACODE, PHARMACODE TWO-TRACKS, Datamatrix, QR-Code, PDF417;</li>
85 * <li>JPEG and PNG ICC profiles, Grayscale, RGB, CMYK, Spot Colors and Transparencies;</li>
86 * <li>automatic page header and footer management;</li>
87 * <li>document encryption up to 256 bit and digital signature certifications;</li>
88 * <li>transactions to UNDO commands;</li>
89 * <li>PDF annotations, including links, text and file attachments;</li>
90 * <li>text rendering modes (fill, stroke and clipping);</li>
91 * <li>multiple columns mode;</li>
92 * <li>no-write page regions;</li>
93 * <li>bookmarks, named destinations and table of content;</li>
94 * <li>text hyphenation;</li>
95 * <li>text stretching and spacing (tracking);</li>
96 * <li>automatic page break, line break and text alignments including justification;</li>
97 * <li>automatic page numbering and page groups;</li>
98 * <li>move and delete pages;</li>
99 * <li>page compression (requires php-zlib extension);</li>
100 * <li>XOBject Templates;</li>
101 * <li>Layers and object visibility;</li>
102 * <li>PDF/A-1b support.</li>
103 * </ul>
104 * Tools to encode your unicode fonts are on fonts/utils directory.</p>
105 * @package com.tecnick.tcpdf
106 * @author Nicola Asuni
107 * @version 6.0.093
108 */
109
110// TCPDF configuration
111require_once(dirname(__FILE__).'/tcpdf_autoconfig.php');
112// TCPDF static font methods and data
113require_once(dirname(__FILE__).'/include/tcpdf_font_data.php');
114// TCPDF static font methods and data
115require_once(dirname(__FILE__).'/include/tcpdf_fonts.php');
116// TCPDF static color methods and data
117require_once(dirname(__FILE__).'/include/tcpdf_colors.php');
118// TCPDF static image methods and data
119require_once(dirname(__FILE__).'/include/tcpdf_images.php');
120// TCPDF static methods and data
121require_once(dirname(__FILE__).'/include/tcpdf_static.php');
122
123// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
124
125/**
126 * @class TCPDF
127 * PHP class for generating PDF documents without requiring external extensions.
128 * TCPDF project (http://www.tcpdf.org) has been originally derived in 2002 from the Public Domain FPDF class by Olivier Plathey (http://www.fpdf.org), but now is almost entirely rewritten.<br>
129 * @package com.tecnick.tcpdf
130 * @brief PHP class for generating PDF documents without requiring external extensions.
131 * @version 6.0.093
132 * @author Nicola Asuni - info@tecnick.com
133 */
134class TCPDF {
135
136 // Protected properties
137
138 /**
139 * Current page number.
140 * @protected
141 */
142 protected $page;
143
144 /**
145 * Current object number.
146 * @protected
147 */
148 protected $n;
149
150 /**
151 * Array of object offsets.
152 * @protected
153 */
154 protected $offsets = array();
155
156 /**
157 * Array of object IDs for each page.
158 * @protected
159 */
160 protected $pageobjects = array();
161
162 /**
163 * Buffer holding in-memory PDF.
164 * @protected
165 */
166 protected $buffer;
167
168 /**
169 * Array containing pages.
170 * @protected
171 */
172 protected $pages = array();
173
174 /**
175 * Current document state.
176 * @protected
177 */
178 protected $state;
179
180 /**
181 * Compression flag.
182 * @protected
183 */
184 protected $compress;
185
186 /**
187 * Current page orientation (P = Portrait, L = Landscape).
188 * @protected
189 */
190 protected $CurOrientation;
191
192 /**
193 * Page dimensions.
194 * @protected
195 */
196 protected $pagedim = array();
197
198 /**
199 * Scale factor (number of points in user unit).
200 * @protected
201 */
202 protected $k;
203
204 /**
205 * Width of page format in points.
206 * @protected
207 */
208 protected $fwPt;
209
210 /**
211 * Height of page format in points.
212 * @protected
213 */
214 protected $fhPt;
215
216 /**
217 * Current width of page in points.
218 * @protected
219 */
220 protected $wPt;
221
222 /**
223 * Current height of page in points.
224 * @protected
225 */
226 protected $hPt;
227
228 /**
229 * Current width of page in user unit.
230 * @protected
231 */
232 protected $w;
233
234 /**
235 * Current height of page in user unit.
236 * @protected
237 */
238 protected $h;
239
240 /**
241 * Left margin.
242 * @protected
243 */
244 protected $lMargin;
245
246 /**
247 * Right margin.
248 * @protected
249 */
250 protected $rMargin;
251
252 /**
253 * Cell left margin (used by regions).
254 * @protected
255 */
256 protected $clMargin;
257
258 /**
259 * Cell right margin (used by regions).
260 * @protected
261 */
262 protected $crMargin;
263
264 /**
265 * Top margin.
266 * @protected
267 */
268 protected $tMargin;
269
270 /**
271 * Page break margin.
272 * @protected
273 */
274 protected $bMargin;
275
276 /**
277 * Array of cell internal paddings ('T' => top, 'R' => right, 'B' => bottom, 'L' => left).
278 * @since 5.9.000 (2010-10-03)
279 * @protected
280 */
281 protected $cell_padding = array('T' => 0, 'R' => 0, 'B' => 0, 'L' => 0);
282
283 /**
284 * Array of cell margins ('T' => top, 'R' => right, 'B' => bottom, 'L' => left).
285 * @since 5.9.000 (2010-10-04)
286 * @protected
287 */
288 protected $cell_margin = array('T' => 0, 'R' => 0, 'B' => 0, 'L' => 0);
289
290 /**
291 * Current horizontal position in user unit for cell positioning.
292 * @protected
293 */
294 protected $x;
295
296 /**
297 * Current vertical position in user unit for cell positioning.
298 * @protected
299 */
300 protected $y;
301
302 /**
303 * Height of last cell printed.
304 * @protected
305 */
306 protected $lasth;
307
308 /**
309 * Line width in user unit.
310 * @protected
311 */
312 protected $LineWidth;
313
314 /**
315 * Array of standard font names.
316 * @protected
317 */
318 protected $CoreFonts;
319
320 /**
321 * Array of used fonts.
322 * @protected
323 */
324 protected $fonts = array();
325
326 /**
327 * Array of font files.
328 * @protected
329 */
330 protected $FontFiles = array();
331
332 /**
333 * Array of encoding differences.
334 * @protected
335 */
336 protected $diffs = array();
337
338 /**
339 * Array of used images.
340 * @protected
341 */
342 protected $images = array();
343
344 /**
345 * Array of cached files.
346 * @protected
347 */
348 protected $cached_files = array();
349
350 /**
351 * Array of Annotations in pages.
352 * @protected
353 */
354 protected $PageAnnots = array();
355
356 /**
357 * Array of internal links.
358 * @protected
359 */
360 protected $links = array();
361
362 /**
363 * Current font family.
364 * @protected
365 */
366 protected $FontFamily;
367
368 /**
369 * Current font style.
370 * @protected
371 */
372 protected $FontStyle;
373
374 /**
375 * Current font ascent (distance between font top and baseline).
376 * @protected
377 * @since 2.8.000 (2007-03-29)
378 */
379 protected $FontAscent;
380
381 /**
382 * Current font descent (distance between font bottom and baseline).
383 * @protected
384 * @since 2.8.000 (2007-03-29)
385 */
386 protected $FontDescent;
387
388 /**
389 * Underlining flag.
390 * @protected
391 */
392 protected $underline;
393
394 /**
395 * Overlining flag.
396 * @protected
397 */
398 protected $overline;
399
400 /**
401 * Current font info.
402 * @protected
403 */
404 protected $CurrentFont;
405
406 /**
407 * Current font size in points.
408 * @protected
409 */
410 protected $FontSizePt;
411
412 /**
413 * Current font size in user unit.
414 * @protected
415 */
416 protected $FontSize;
417
418 /**
419 * Commands for drawing color.
420 * @protected
421 */
422 protected $DrawColor;
423
424 /**
425 * Commands for filling color.
426 * @protected
427 */
428 protected $FillColor;
429
430 /**
431 * Commands for text color.
432 * @protected
433 */
434 protected $TextColor;
435
436 /**
437 * Indicates whether fill and text colors are different.
438 * @protected
439 */
440 protected $ColorFlag;
441
442 /**
443 * Automatic page breaking.
444 * @protected
445 */
446 protected $AutoPageBreak;
447
448 /**
449 * Threshold used to trigger page breaks.
450 * @protected
451 */
452 protected $PageBreakTrigger;
453
454 /**
455 * Flag set when processing page header.
456 * @protected
457 */
458 protected $InHeader = false;
459
460 /**
461 * Flag set when processing page footer.
462 * @protected
463 */
464 protected $InFooter = false;
465
466 /**
467 * Zoom display mode.
468 * @protected
469 */
470 protected $ZoomMode;
471
472 /**
473 * Layout display mode.
474 * @protected
475 */
476 protected $LayoutMode;
477
478 /**
479 * If true set the document information dictionary in Unicode.
480 * @protected
481 */
482 protected $docinfounicode = true;
483
484 /**
485 * Document title.
486 * @protected
487 */
488 protected $title = '';
489
490 /**
491 * Document subject.
492 * @protected
493 */
494 protected $subject = '';
495
496 /**
497 * Document author.
498 * @protected
499 */
500 protected $author = '';
501
502 /**
503 * Document keywords.
504 * @protected
505 */
506 protected $keywords = '';
507
508 /**
509 * Document creator.
510 * @protected
511 */
512 protected $creator = '';
513
514 /**
515 * Starting page number.
516 * @protected
517 */
518 protected $starting_page_number = 1;
519
520 /**
521 * The right-bottom (or left-bottom for RTL) corner X coordinate of last inserted image.
522 * @since 2002-07-31
523 * @author Nicola Asuni
524 * @protected
525 */
526 protected $img_rb_x;
527
528 /**
529 * The right-bottom corner Y coordinate of last inserted image.
530 * @since 2002-07-31
531 * @author Nicola Asuni
532 * @protected
533 */
534 protected $img_rb_y;
535
536 /**
537 * Adjusting factor to convert pixels to user units.
538 * @since 2004-06-14
539 * @author Nicola Asuni
540 * @protected
541 */
542 protected $imgscale = 1;
543
544 /**
545 * Boolean flag set to true when the input text is unicode (require unicode fonts).
546 * @since 2005-01-02
547 * @author Nicola Asuni
548 * @protected
549 */
550 protected $isunicode = false;
551
552 /**
553 * PDF version.
554 * @since 1.5.3
555 * @protected
556 */
557 protected $PDFVersion = '1.7';
558
559 /**
560 * ID of the stored default header template (-1 = not set).
561 * @protected
562 */
563 protected $header_xobjid = false;
564
565 /**
566 * If true reset the Header Xobject template at each page
567 * @protected
568 */
569 protected $header_xobj_autoreset = false;
570
571 /**
572 * Minimum distance between header and top page margin.
573 * @protected
574 */
575 protected $header_margin;
576
577 /**
578 * Minimum distance between footer and bottom page margin.
579 * @protected
580 */
581 protected $footer_margin;
582
583 /**
584 * Original left margin value.
585 * @protected
586 * @since 1.53.0.TC013
587 */
588 protected $original_lMargin;
589
590 /**
591 * Original right margin value.
592 * @protected
593 * @since 1.53.0.TC013
594 */
595 protected $original_rMargin;
596
597 /**
598 * Default font used on page header.
599 * @protected
600 */
601 protected $header_font;
602
603 /**
604 * Default font used on page footer.
605 * @protected
606 */
607 protected $footer_font;
608
609 /**
610 * Language templates.
611 * @protected
612 */
613 protected $l;
614
615 /**
616 * Barcode to print on page footer (only if set).
617 * @protected
618 */
619 protected $barcode = false;
620
621 /**
622 * Boolean flag to print/hide page header.
623 * @protected
624 */
625 protected $print_header = true;
626
627 /**
628 * Boolean flag to print/hide page footer.
629 * @protected
630 */
631 protected $print_footer = true;
632
633 /**
634 * Header image logo.
635 * @protected
636 */
637 protected $header_logo = '';
638
639 /**
640 * Width of header image logo in user units.
641 * @protected
642 */
643 protected $header_logo_width = 30;
644
645 /**
646 * Title to be printed on default page header.
647 * @protected
648 */
649 protected $header_title = '';
650
651 /**
652 * String to pring on page header after title.
653 * @protected
654 */
655 protected $header_string = '';
656
657 /**
658 * Color for header text (RGB array).
659 * @since 5.9.174 (2012-07-25)
660 * @protected
661 */
662 protected $header_text_color = array(0,0,0);
663
664 /**
665 * Color for header line (RGB array).
666 * @since 5.9.174 (2012-07-25)
667 * @protected
668 */
669 protected $header_line_color = array(0,0,0);
670
671 /**
672 * Color for footer text (RGB array).
673 * @since 5.9.174 (2012-07-25)
674 * @protected
675 */
676 protected $footer_text_color = array(0,0,0);
677
678 /**
679 * Color for footer line (RGB array).
680 * @since 5.9.174 (2012-07-25)
681 * @protected
682 */
683 protected $footer_line_color = array(0,0,0);
684
685 /**
686 * Text shadow data array.
687 * @since 5.9.174 (2012-07-25)
688 * @protected
689 */
690 protected $txtshadow = array('enabled'=>false, 'depth_w'=>0, 'depth_h'=>0, 'color'=>false, 'opacity'=>1, 'blend_mode'=>'Normal');
691
692 /**
693 * Default number of columns for html table.
694 * @protected
695 */
696 protected $default_table_columns = 4;
697
698 // variables for html parser
699
700 /**
701 * HTML PARSER: array to store current link and rendering styles.
702 * @protected
703 */
704 protected $HREF = array();
705
706 /**
707 * List of available fonts on filesystem.
708 * @protected
709 */
710 protected $fontlist = array();
711
712 /**
713 * Current foreground color.
714 * @protected
715 */
716 protected $fgcolor;
717
718 /**
719 * HTML PARSER: array of boolean values, true in case of ordered list (OL), false otherwise.
720 * @protected
721 */
722 protected $listordered = array();
723
724 /**
725 * HTML PARSER: array count list items on nested lists.
726 * @protected
727 */
728 protected $listcount = array();
729
730 /**
731 * HTML PARSER: current list nesting level.
732 * @protected
733 */
734 protected $listnum = 0;
735
736 /**
737 * HTML PARSER: indent amount for lists.
738 * @protected
739 */
740 protected $listindent = 0;
741
742 /**
743 * HTML PARSER: current list indententation level.
744 * @protected
745 */
746 protected $listindentlevel = 0;
747
748 /**
749 * Current background color.
750 * @protected
751 */
752 protected $bgcolor;
753
754 /**
755 * Temporary font size in points.
756 * @protected
757 */
758 protected $tempfontsize = 10;
759
760 /**
761 * Spacer string for LI tags.
762 * @protected
763 */
764 protected $lispacer = '';
765
766 /**
767 * Default encoding.
768 * @protected
769 * @since 1.53.0.TC010
770 */
771 protected $encoding = 'UTF-8';
772
773 /**
774 * PHP internal encoding.
775 * @protected
776 * @since 1.53.0.TC016
777 */
778 protected $internal_encoding;
779
780 /**
781 * Boolean flag to indicate if the document language is Right-To-Left.
782 * @protected
783 * @since 2.0.000
784 */
785 protected $rtl = false;
786
787 /**
788 * Boolean flag used to force RTL or LTR string direction.
789 * @protected
790 * @since 2.0.000
791 */
792 protected $tmprtl = false;
793
794 // --- Variables used for document encryption:
795
796 /**
797 * IBoolean flag indicating whether document is protected.
798 * @protected
799 * @since 2.0.000 (2008-01-02)
800 */
801 protected $encrypted;
802
803 /**
804 * Array containing encryption settings.
805 * @protected
806 * @since 5.0.005 (2010-05-11)
807 */
808 protected $encryptdata = array();
809
810 /**
811 * Last RC4 key encrypted (cached for optimisation).
812 * @protected
813 * @since 2.0.000 (2008-01-02)
814 */
815 protected $last_enc_key;
816
817 /**
818 * Last RC4 computed key.
819 * @protected
820 * @since 2.0.000 (2008-01-02)
821 */
822 protected $last_enc_key_c;
823
824 /**
825 * File ID (used on document trailer).
826 * @protected
827 * @since 5.0.005 (2010-05-12)
828 */
829 protected $file_id;
830
831 // --- bookmark ---
832
833 /**
834 * Outlines for bookmark.
835 * @protected
836 * @since 2.1.002 (2008-02-12)
837 */
838 protected $outlines = array();
839
840 /**
841 * Outline root for bookmark.
842 * @protected
843 * @since 2.1.002 (2008-02-12)
844 */
845 protected $OutlineRoot;
846
847 // --- javascript and form ---
848
849 /**
850 * Javascript code.
851 * @protected
852 * @since 2.1.002 (2008-02-12)
853 */
854 protected $javascript = '';
855
856 /**
857 * Javascript counter.
858 * @protected
859 * @since 2.1.002 (2008-02-12)
860 */
861 protected $n_js;
862
863 /**
864 * line through state
865 * @protected
866 * @since 2.8.000 (2008-03-19)
867 */
868 protected $linethrough;
869
870 /**
871 * Array with additional document-wide usage rights for the document.
872 * @protected
873 * @since 5.8.014 (2010-08-23)
874 */
875 protected $ur = array();
876
877 /**
878 * DPI (Dot Per Inch) Document Resolution (do not change).
879 * @protected
880 * @since 3.0.000 (2008-03-27)
881 */
882 protected $dpi = 72;
883
884 /**
885 * Array of page numbers were a new page group was started (the page numbers are the keys of the array).
886 * @protected
887 * @since 3.0.000 (2008-03-27)
888 */
889 protected $newpagegroup = array();
890
891 /**
892 * Array that contains the number of pages in each page group.
893 * @protected
894 * @since 3.0.000 (2008-03-27)
895 */
896 protected $pagegroups = array();
897
898 /**
899 * Current page group number.
900 * @protected
901 * @since 3.0.000 (2008-03-27)
902 */
903 protected $currpagegroup = 0;
904
905 /**
906 * Array of transparency objects and parameters.
907 * @protected
908 * @since 3.0.000 (2008-03-27)
909 */
910 protected $extgstates;
911
912 /**
913 * Set the default JPEG compression quality (1-100).
914 * @protected
915 * @since 3.0.000 (2008-03-27)
916 */
917 protected $jpeg_quality;
918
919 /**
920 * Default cell height ratio.
921 * @protected
922 * @since 3.0.014 (2008-05-23)
923 */
924 protected $cell_height_ratio = K_CELL_HEIGHT_RATIO;
925
926 /**
927 * PDF viewer preferences.
928 * @protected
929 * @since 3.1.000 (2008-06-09)
930 */
931 protected $viewer_preferences;
932
933 /**
934 * A name object specifying how the document should be displayed when opened.
935 * @protected
936 * @since 3.1.000 (2008-06-09)
937 */
938 protected $PageMode;
939
940 /**
941 * Array for storing gradient information.
942 * @protected
943 * @since 3.1.000 (2008-06-09)
944 */
945 protected $gradients = array();
946
947 /**
948 * Array used to store positions inside the pages buffer (keys are the page numbers).
949 * @protected
950 * @since 3.2.000 (2008-06-26)
951 */
952 protected $intmrk = array();
953
954 /**
955 * Array used to store positions inside the pages buffer (keys are the page numbers).
956 * @protected
957 * @since 5.7.000 (2010-08-03)
958 */
959 protected $bordermrk = array();
960
961 /**
962 * Array used to store page positions to track empty pages (keys are the page numbers).
963 * @protected
964 * @since 5.8.007 (2010-08-18)
965 */
966 protected $emptypagemrk = array();
967
968 /**
969 * Array used to store content positions inside the pages buffer (keys are the page numbers).
970 * @protected
971 * @since 4.6.021 (2009-07-20)
972 */
973 protected $cntmrk = array();
974
975 /**
976 * Array used to store footer positions of each page.
977 * @protected
978 * @since 3.2.000 (2008-07-01)
979 */
980 protected $footerpos = array();
981
982 /**
983 * Array used to store footer length of each page.
984 * @protected
985 * @since 4.0.014 (2008-07-29)
986 */
987 protected $footerlen = array();
988
989 /**
990 * Boolean flag to indicate if a new line is created.
991 * @protected
992 * @since 3.2.000 (2008-07-01)
993 */
994 protected $newline = true;
995
996 /**
997 * End position of the latest inserted line.
998 * @protected
999 * @since 3.2.000 (2008-07-01)
1000 */
1001 protected $endlinex = 0;
1002
1003 /**
1004 * PDF string for width value of the last line.
1005 * @protected
1006 * @since 4.0.006 (2008-07-16)
1007 */
1008 protected $linestyleWidth = '';
1009
1010 /**
1011 * PDF string for CAP value of the last line.
1012 * @protected
1013 * @since 4.0.006 (2008-07-16)
1014 */
1015 protected $linestyleCap = '0 J';
1016
1017 /**
1018 * PDF string for join value of the last line.
1019 * @protected
1020 * @since 4.0.006 (2008-07-16)
1021 */
1022 protected $linestyleJoin = '0 j';
1023
1024 /**
1025 * PDF string for dash value of the last line.
1026 * @protected
1027 * @since 4.0.006 (2008-07-16)
1028 */
1029 protected $linestyleDash = '[] 0 d';
1030
1031 /**
1032 * Boolean flag to indicate if marked-content sequence is open.
1033 * @protected
1034 * @since 4.0.013 (2008-07-28)
1035 */
1036 protected $openMarkedContent = false;
1037
1038 /**
1039 * Count the latest inserted vertical spaces on HTML.
1040 * @protected
1041 * @since 4.0.021 (2008-08-24)
1042 */
1043 protected $htmlvspace = 0;
1044
1045 /**
1046 * Array of Spot colors.
1047 * @protected
1048 * @since 4.0.024 (2008-09-12)
1049 */
1050 protected $spot_colors = array();
1051
1052 /**
1053 * Symbol used for HTML unordered list items.
1054 * @protected
1055 * @since 4.0.028 (2008-09-26)
1056 */
1057 protected $lisymbol = '';
1058
1059 /**
1060 * String used to mark the beginning and end of EPS image blocks.
1061 * @protected
1062 * @since 4.1.000 (2008-10-18)
1063 */
1064 protected $epsmarker = 'x#!#EPS#!#x';
1065
1066 /**
1067 * Array of transformation matrix.
1068 * @protected
1069 * @since 4.2.000 (2008-10-29)
1070 */
1071 protected $transfmatrix = array();
1072
1073 /**
1074 * Current key for transformation matrix.
1075 * @protected
1076 * @since 4.8.005 (2009-09-17)
1077 */
1078 protected $transfmatrix_key = 0;
1079
1080 /**
1081 * Booklet mode for double-sided pages.
1082 * @protected
1083 * @since 4.2.000 (2008-10-29)
1084 */
1085 protected $booklet = false;
1086
1087 /**
1088 * Epsilon value used for float calculations.
1089 * @protected
1090 * @since 4.2.000 (2008-10-29)
1091 */
1092 protected $feps = 0.005;
1093
1094 /**
1095 * Array used for custom vertical spaces for HTML tags.
1096 * @protected
1097 * @since 4.2.001 (2008-10-30)
1098 */
1099 protected $tagvspaces = array();
1100
1101 /**
1102 * HTML PARSER: custom indent amount for lists. Negative value means disabled.
1103 * @protected
1104 * @since 4.2.007 (2008-11-12)
1105 */
1106 protected $customlistindent = -1;
1107
1108 /**
1109 * Boolean flag to indicate if the border of the cell sides that cross the page should be removed.
1110 * @protected
1111 * @since 4.2.010 (2008-11-14)
1112 */
1113 protected $opencell = true;
1114
1115 /**
1116 * Array of files to embedd.
1117 * @protected
1118 * @since 4.4.000 (2008-12-07)
1119 */
1120 protected $embeddedfiles = array();
1121
1122 /**
1123 * Boolean flag to indicate if we are inside a PRE tag.
1124 * @protected
1125 * @since 4.4.001 (2008-12-08)
1126 */
1127 protected $premode = false;
1128
1129 /**
1130 * Array used to store positions of graphics transformation blocks inside the page buffer.
1131 * keys are the page numbers
1132 * @protected
1133 * @since 4.4.002 (2008-12-09)
1134 */
1135 protected $transfmrk = array();
1136
1137 /**
1138 * Default color for html links.
1139 * @protected
1140 * @since 4.4.003 (2008-12-09)
1141 */
1142 protected $htmlLinkColorArray = array(0, 0, 255);
1143
1144 /**
1145 * Default font style to add to html links.
1146 * @protected
1147 * @since 4.4.003 (2008-12-09)
1148 */
1149 protected $htmlLinkFontStyle = 'U';
1150
1151 /**
1152 * Counts the number of pages.
1153 * @protected
1154 * @since 4.5.000 (2008-12-31)
1155 */
1156 protected $numpages = 0;
1157
1158 /**
1159 * Array containing page lengths in bytes.
1160 * @protected
1161 * @since 4.5.000 (2008-12-31)
1162 */
1163 protected $pagelen = array();
1164
1165 /**
1166 * Counts the number of pages.
1167 * @protected
1168 * @since 4.5.000 (2008-12-31)
1169 */
1170 protected $numimages = 0;
1171
1172 /**
1173 * Store the image keys.
1174 * @protected
1175 * @since 4.5.000 (2008-12-31)
1176 */
1177 protected $imagekeys = array();
1178
1179 /**
1180 * Length of the buffer in bytes.
1181 * @protected
1182 * @since 4.5.000 (2008-12-31)
1183 */
1184 protected $bufferlen = 0;
1185
1186 /**
1187 * If true enables disk caching.
1188 * @protected
1189 * @since 4.5.000 (2008-12-31)
1190 */
1191 protected $diskcache = false;
1192
1193 /**
1194 * Counts the number of fonts.
1195 * @protected
1196 * @since 4.5.000 (2009-01-02)
1197 */
1198 protected $numfonts = 0;
1199
1200 /**
1201 * Store the font keys.
1202 * @protected
1203 * @since 4.5.000 (2009-01-02)
1204 */
1205 protected $fontkeys = array();
1206
1207 /**
1208 * Store the font object IDs.
1209 * @protected
1210 * @since 4.8.001 (2009-09-09)
1211 */
1212 protected $font_obj_ids = array();
1213
1214 /**
1215 * Store the fage status (true when opened, false when closed).
1216 * @protected
1217 * @since 4.5.000 (2009-01-02)
1218 */
1219 protected $pageopen = array();
1220
1221 /**
1222 * Default monospace font.
1223 * @protected
1224 * @since 4.5.025 (2009-03-10)
1225 */
1226 protected $default_monospaced_font = 'courier';
1227
1228 /**
1229 * Cloned copy of the current class object.
1230 * @protected
1231 * @since 4.5.029 (2009-03-19)
1232 */
1233 protected $objcopy;
1234
1235 /**
1236 * Array used to store the lengths of cache files.
1237 * @protected
1238 * @since 4.5.029 (2009-03-19)
1239 */
1240 protected $cache_file_length = array();
1241
1242 /**
1243 * Table header content to be repeated on each new page.
1244 * @protected
1245 * @since 4.5.030 (2009-03-20)
1246 */
1247 protected $thead = '';
1248
1249 /**
1250 * Margins used for table header.
1251 * @protected
1252 * @since 4.5.030 (2009-03-20)
1253 */
1254 protected $theadMargins = array();
1255
1256 /**
1257 * Boolean flag to enable document digital signature.
1258 * @protected
1259 * @since 4.6.005 (2009-04-24)
1260 */
1261 protected $sign = false;
1262
1263 /**
1264 * Digital signature data.
1265 * @protected
1266 * @since 4.6.005 (2009-04-24)
1267 */
1268 protected $signature_data = array();
1269
1270 /**
1271 * Digital signature max length.
1272 * @protected
1273 * @since 4.6.005 (2009-04-24)
1274 */
1275 protected $signature_max_length = 11742;
1276
1277 /**
1278 * Data for digital signature appearance.
1279 * @protected
1280 * @since 5.3.011 (2010-06-16)
1281 */
1282 protected $signature_appearance = array('page' => 1, 'rect' => '0 0 0 0');
1283
1284 /**
1285 * Array of empty digital signature appearances.
1286 * @protected
1287 * @since 5.9.101 (2011-07-06)
1288 */
1289 protected $empty_signature_appearance = array();
1290
1291 /**
1292 * Boolean flag to enable document timestamping with TSA.
1293 * @protected
1294 * @since 6.0.085 (2014-06-19)
1295 */
1296 protected $tsa_timestamp = false;
1297
1298 /**
1299 * Timestamping data.
1300 * @protected
1301 * @since 6.0.085 (2014-06-19)
1302 */
1303 protected $tsa_data = array();
1304
1305 /**
1306 * Regular expression used to find blank characters (required for word-wrapping).
1307 * @protected
1308 * @since 4.6.006 (2009-04-28)
1309 */
1310 protected $re_spaces = '/[^\S\xa0]/';
1311
1312 /**
1313 * Array of $re_spaces parts.
1314 * @protected
1315 * @since 5.5.011 (2010-07-09)
1316 */
1317 protected $re_space = array('p' => '[^\S\xa0]', 'm' => '');
1318
1319 /**
1320 * Digital signature object ID.
1321 * @protected
1322 * @since 4.6.022 (2009-06-23)
1323 */
1324 protected $sig_obj_id = 0;
1325
1326 /**
1327 * ID of page objects.
1328 * @protected
1329 * @since 4.7.000 (2009-08-29)
1330 */
1331 protected $page_obj_id = array();
1332
1333 /**
1334 * List of form annotations IDs.
1335 * @protected
1336 * @since 4.8.000 (2009-09-07)
1337 */
1338 protected $form_obj_id = array();
1339
1340 /**
1341 * Deafult Javascript field properties. Possible values are described on official Javascript for Acrobat API reference. Annotation options can be directly specified using the 'aopt' entry.
1342 * @protected
1343 * @since 4.8.000 (2009-09-07)
1344 */
1345 protected $default_form_prop = array('lineWidth'=>1, 'borderStyle'=>'solid', 'fillColor'=>array(255, 255, 255), 'strokeColor'=>array(128, 128, 128));
1346
1347 /**
1348 * Javascript objects array.
1349 * @protected
1350 * @since 4.8.000 (2009-09-07)
1351 */
1352 protected $js_objects = array();
1353
1354 /**
1355 * Current form action (used during XHTML rendering).
1356 * @protected
1357 * @since 4.8.000 (2009-09-07)
1358 */
1359 protected $form_action = '';
1360
1361 /**
1362 * Current form encryption type (used during XHTML rendering).
1363 * @protected
1364 * @since 4.8.000 (2009-09-07)
1365 */
1366 protected $form_enctype = 'application/x-www-form-urlencoded';
1367
1368 /**
1369 * Current method to submit forms.
1370 * @protected
1371 * @since 4.8.000 (2009-09-07)
1372 */
1373 protected $form_mode = 'post';
1374
1375 /**
1376 * List of fonts used on form fields (fontname => fontkey).
1377 * @protected
1378 * @since 4.8.001 (2009-09-09)
1379 */
1380 protected $annotation_fonts = array();
1381
1382 /**
1383 * List of radio buttons parent objects.
1384 * @protected
1385 * @since 4.8.001 (2009-09-09)
1386 */
1387 protected $radiobutton_groups = array();
1388
1389 /**
1390 * List of radio group objects IDs.
1391 * @protected
1392 * @since 4.8.001 (2009-09-09)
1393 */
1394 protected $radio_groups = array();
1395
1396 /**
1397 * Text indentation value (used for text-indent CSS attribute).
1398 * @protected
1399 * @since 4.8.006 (2009-09-23)
1400 */
1401 protected $textindent = 0;
1402
1403 /**
1404 * Store page number when startTransaction() is called.
1405 * @protected
1406 * @since 4.8.006 (2009-09-23)
1407 */
1408 protected $start_transaction_page = 0;
1409
1410 /**
1411 * Store Y position when startTransaction() is called.
1412 * @protected
1413 * @since 4.9.001 (2010-03-28)
1414 */
1415 protected $start_transaction_y = 0;
1416
1417 /**
1418 * True when we are printing the thead section on a new page.
1419 * @protected
1420 * @since 4.8.027 (2010-01-25)
1421 */
1422 protected $inthead = false;
1423
1424 /**
1425 * Array of column measures (width, space, starting Y position).
1426 * @protected
1427 * @since 4.9.001 (2010-03-28)
1428 */
1429 protected $columns = array();
1430
1431 /**
1432 * Number of colums.
1433 * @protected
1434 * @since 4.9.001 (2010-03-28)
1435 */
1436 protected $num_columns = 1;
1437
1438 /**
1439 * Current column number.
1440 * @protected
1441 * @since 4.9.001 (2010-03-28)
1442 */
1443 protected $current_column = 0;
1444
1445 /**
1446 * Starting page for columns.
1447 * @protected
1448 * @since 4.9.001 (2010-03-28)
1449 */
1450 protected $column_start_page = 0;
1451
1452 /**
1453 * Maximum page and column selected.
1454 * @protected
1455 * @since 5.8.000 (2010-08-11)
1456 */
1457 protected $maxselcol = array('page' => 0, 'column' => 0);
1458
1459 /**
1460 * Array of: X difference between table cell x start and starting page margin, cellspacing, cellpadding.
1461 * @protected
1462 * @since 5.8.000 (2010-08-11)
1463 */
1464 protected $colxshift = array('x' => 0, 's' => array('H' => 0, 'V' => 0), 'p' => array('L' => 0, 'T' => 0, 'R' => 0, 'B' => 0));
1465
1466 /**
1467 * Text rendering mode: 0 = Fill text; 1 = Stroke text; 2 = Fill, then stroke text; 3 = Neither fill nor stroke text (invisible); 4 = Fill text and add to path for clipping; 5 = Stroke text and add to path for clipping; 6 = Fill, then stroke text and add to path for clipping; 7 = Add text to path for clipping.
1468 * @protected
1469 * @since 4.9.008 (2010-04-03)
1470 */
1471 protected $textrendermode = 0;
1472
1473 /**
1474 * Text stroke width in doc units.
1475 * @protected
1476 * @since 4.9.008 (2010-04-03)
1477 */
1478 protected $textstrokewidth = 0;
1479
1480 /**
1481 * Current stroke color.
1482 * @protected
1483 * @since 4.9.008 (2010-04-03)
1484 */
1485 protected $strokecolor;
1486
1487 /**
1488 * Default unit of measure for document.
1489 * @protected
1490 * @since 5.0.000 (2010-04-22)
1491 */
1492 protected $pdfunit = 'mm';
1493
1494 /**
1495 * Boolean flag true when we are on TOC (Table Of Content) page.
1496 * @protected
1497 */
1498 protected $tocpage = false;
1499
1500 /**
1501 * Boolean flag: if true convert vector images (SVG, EPS) to raster image using GD or ImageMagick library.
1502 * @protected
1503 * @since 5.0.000 (2010-04-26)
1504 */
1505 protected $rasterize_vector_images = false;
1506
1507 /**
1508 * Boolean flag: if true enables font subsetting by default.
1509 * @protected
1510 * @since 5.3.002 (2010-06-07)
1511 */
1512 protected $font_subsetting = true;
1513
1514 /**
1515 * Array of default graphic settings.
1516 * @protected
1517 * @since 5.5.008 (2010-07-02)
1518 */
1519 protected $default_graphic_vars = array();
1520
1521 /**
1522 * Array of XObjects.
1523 * @protected
1524 * @since 5.8.014 (2010-08-23)
1525 */
1526 protected $xobjects = array();
1527
1528 /**
1529 * Boolean value true when we are inside an XObject.
1530 * @protected
1531 * @since 5.8.017 (2010-08-24)
1532 */
1533 protected $inxobj = false;
1534
1535 /**
1536 * Current XObject ID.
1537 * @protected
1538 * @since 5.8.017 (2010-08-24)
1539 */
1540 protected $xobjid = '';
1541
1542 /**
1543 * Percentage of character stretching.
1544 * @protected
1545 * @since 5.9.000 (2010-09-29)
1546 */
1547 protected $font_stretching = 100;
1548
1549 /**
1550 * Increases or decreases the space between characters in a text by the specified amount (tracking).
1551 * @protected
1552 * @since 5.9.000 (2010-09-29)
1553 */
1554 protected $font_spacing = 0;
1555
1556 /**
1557 * Array of no-write regions.
1558 * ('page' => page number or empy for current page, 'xt' => X top, 'yt' => Y top, 'xb' => X bottom, 'yb' => Y bottom, 'side' => page side 'L' = left or 'R' = right)
1559 * @protected
1560 * @since 5.9.003 (2010-10-14)
1561 */
1562 protected $page_regions = array();
1563
1564 /**
1565 * Boolean value true when page region check is active.
1566 * @protected
1567 */
1568 protected $check_page_regions = true;
1569
1570 /**
1571 * Array of PDF layers data.
1572 * @protected
1573 * @since 5.9.102 (2011-07-13)
1574 */
1575 protected $pdflayers = array();
1576
1577 /**
1578 * A dictionary of names and corresponding destinations (Dests key on document Catalog).
1579 * @protected
1580 * @since 5.9.097 (2011-06-23)
1581 */
1582 protected $dests = array();
1583
1584 /**
1585 * Object ID for Named Destinations
1586 * @protected
1587 * @since 5.9.097 (2011-06-23)
1588 */
1589 protected $n_dests;
1590
1591 /**
1592 * Embedded Files Names
1593 * @protected
1594 * @since 5.9.204 (2013-01-23)
1595 */
1596 protected $efnames = array();
1597
1598 /**
1599 * Directory used for the last SVG image.
1600 * @protected
1601 * @since 5.0.000 (2010-05-05)
1602 */
1603 protected $svgdir = '';
1604
1605 /**
1606 * Deafult unit of measure for SVG.
1607 * @protected
1608 * @since 5.0.000 (2010-05-02)
1609 */
1610 protected $svgunit = 'px';
1611
1612 /**
1613 * Array of SVG gradients.
1614 * @protected
1615 * @since 5.0.000 (2010-05-02)
1616 */
1617 protected $svggradients = array();
1618
1619 /**
1620 * ID of last SVG gradient.
1621 * @protected
1622 * @since 5.0.000 (2010-05-02)
1623 */
1624 protected $svggradientid = 0;
1625
1626 /**
1627 * Boolean value true when in SVG defs group.
1628 * @protected
1629 * @since 5.0.000 (2010-05-02)
1630 */
1631 protected $svgdefsmode = false;
1632
1633 /**
1634 * Array of SVG defs.
1635 * @protected
1636 * @since 5.0.000 (2010-05-02)
1637 */
1638 protected $svgdefs = array();
1639
1640 /**
1641 * Boolean value true when in SVG clipPath tag.
1642 * @protected
1643 * @since 5.0.000 (2010-04-26)
1644 */
1645 protected $svgclipmode = false;
1646
1647 /**
1648 * Array of SVG clipPath commands.
1649 * @protected
1650 * @since 5.0.000 (2010-05-02)
1651 */
1652 protected $svgclippaths = array();
1653
1654 /**
1655 * Array of SVG clipPath tranformation matrix.
1656 * @protected
1657 * @since 5.8.022 (2010-08-31)
1658 */
1659 protected $svgcliptm = array();
1660
1661 /**
1662 * ID of last SVG clipPath.
1663 * @protected
1664 * @since 5.0.000 (2010-05-02)
1665 */
1666 protected $svgclipid = 0;
1667
1668 /**
1669 * SVG text.
1670 * @protected
1671 * @since 5.0.000 (2010-05-02)
1672 */
1673 protected $svgtext = '';
1674
1675 /**
1676 * SVG text properties.
1677 * @protected
1678 * @since 5.8.013 (2010-08-23)
1679 */
1680 protected $svgtextmode = array();
1681
1682 /**
1683 * Array of SVG properties.
1684 * @protected
1685 * @since 5.0.000 (2010-05-02)
1686 */
1687 protected $svgstyles = array(array(
1688 'alignment-baseline' => 'auto',
1689 'baseline-shift' => 'baseline',
1690 'clip' => 'auto',
1691 'clip-path' => 'none',
1692 'clip-rule' => 'nonzero',
1693 'color' => 'black',
1694 'color-interpolation' => 'sRGB',
1695 'color-interpolation-filters' => 'linearRGB',
1696 'color-profile' => 'auto',
1697 'color-rendering' => 'auto',
1698 'cursor' => 'auto',
1699 'direction' => 'ltr',
1700 'display' => 'inline',
1701 'dominant-baseline' => 'auto',
1702 'enable-background' => 'accumulate',
1703 'fill' => 'black',
1704 'fill-opacity' => 1,
1705 'fill-rule' => 'nonzero',
1706 'filter' => 'none',
1707 'flood-color' => 'black',
1708 'flood-opacity' => 1,
1709 'font' => '',
1710 'font-family' => 'helvetica',
1711 'font-size' => 'medium',
1712 'font-size-adjust' => 'none',
1713 'font-stretch' => 'normal',
1714 'font-style' => 'normal',
1715 'font-variant' => 'normal',
1716 'font-weight' => 'normal',
1717 'glyph-orientation-horizontal' => '0deg',
1718 'glyph-orientation-vertical' => 'auto',
1719 'image-rendering' => 'auto',
1720 'kerning' => 'auto',
1721 'letter-spacing' => 'normal',
1722 'lighting-color' => 'white',
1723 'marker' => '',
1724 'marker-end' => 'none',
1725 'marker-mid' => 'none',
1726 'marker-start' => 'none',
1727 'mask' => 'none',
1728 'opacity' => 1,
1729 'overflow' => 'auto',
1730 'pointer-events' => 'visiblePainted',
1731 'shape-rendering' => 'auto',
1732 'stop-color' => 'black',
1733 'stop-opacity' => 1,
1734 'stroke' => 'none',
1735 'stroke-dasharray' => 'none',
1736 'stroke-dashoffset' => 0,
1737 'stroke-linecap' => 'butt',
1738 'stroke-linejoin' => 'miter',
1739 'stroke-miterlimit' => 4,
1740 'stroke-opacity' => 1,
1741 'stroke-width' => 1,
1742 'text-anchor' => 'start',
1743 'text-decoration' => 'none',
1744 'text-rendering' => 'auto',
1745 'unicode-bidi' => 'normal',
1746 'visibility' => 'visible',
1747 'word-spacing' => 'normal',
1748 'writing-mode' => 'lr-tb',
1749 'text-color' => 'black',
1750 'transfmatrix' => array(1, 0, 0, 1, 0, 0)
1751 ));
1752
1753 /**
1754 * If true force sRGB color profile for all document.
1755 * @protected
1756 * @since 5.9.121 (2011-09-28)
1757 */
1758 protected $force_srgb = false;
1759
1760 /**
1761 * If true set the document to PDF/A mode.
1762 * @protected
1763 * @since 5.9.121 (2011-09-27)
1764 */
1765 protected $pdfa_mode = false;
1766
1767 /**
1768 * Document creation date-time
1769 * @protected
1770 * @since 5.9.152 (2012-03-22)
1771 */
1772 protected $doc_creation_timestamp;
1773
1774 /**
1775 * Document modification date-time
1776 * @protected
1777 * @since 5.9.152 (2012-03-22)
1778 */
1779 protected $doc_modification_timestamp;
1780
1781 /**
1782 * Custom XMP data.
1783 * @protected
1784 * @since 5.9.128 (2011-10-06)
1785 */
1786 protected $custom_xmp = '';
1787
1788 /**
1789 * Overprint mode array.
1790 * (Check the "Entries in a Graphics State Parameter Dictionary" on PDF 32000-1:2008).
1791 * @protected
1792 * @since 5.9.152 (2012-03-23)
1793 */
1794 protected $overprint = array('OP' => false, 'op' => false, 'OPM' => 0);
1795
1796 /**
1797 * Alpha mode array.
1798 * (Check the "Entries in a Graphics State Parameter Dictionary" on PDF 32000-1:2008).
1799 * @protected
1800 * @since 5.9.152 (2012-03-23)
1801 */
1802 protected $alpha = array('CA' => 1, 'ca' => 1, 'BM' => '/Normal', 'AIS' => false);
1803
1804 /**
1805 * Define the page boundaries boxes to be set on document.
1806 * @protected
1807 * @since 5.9.152 (2012-03-23)
1808 */
1809 protected $page_boxes = array('MediaBox', 'CropBox', 'BleedBox', 'TrimBox', 'ArtBox');
1810
1811 /**
1812 * If true print TCPDF meta link.
1813 * @protected
1814 * @since 5.9.152 (2012-03-23)
1815 */
1816 protected $tcpdflink = true;
1817
1818 /**
1819 * Cache array for computed GD gamma values.
1820 * @protected
1821 * @since 5.9.1632 (2012-06-05)
1822 */
1823 protected $gdgammacache = array();
1824
1825 //------------------------------------------------------------
1826 // METHODS
1827 //------------------------------------------------------------
1828
1829 /**
1830 * This is the class constructor.
1831 * It allows to set up the page format, the orientation and the measure unit used in all the methods (except for the font sizes).
1832 *
1833 * IMPORTANT: Please note that this method sets the mb_internal_encoding to ASCII, so if you are using the mbstring module functions with TCPDF you need to correctly set/unset the mb_internal_encoding when needed.
1834 *
1835 * @param $orientation (string) page orientation. Possible values are (case insensitive):<ul><li>P or Portrait (default)</li><li>L or Landscape</li><li>'' (empty string) for automatic orientation</li></ul>
1836 * @param $unit (string) User measure unit. Possible values are:<ul><li>pt: point</li><li>mm: millimeter (default)</li><li>cm: centimeter</li><li>in: inch</li></ul><br />A point equals 1/72 of inch, that is to say about 0.35 mm (an inch being 2.54 cm). This is a very common unit in typography; font sizes are expressed in that unit.
1837 * @param $format (mixed) The format used for pages. It can be either: one of the string values specified at getPageSizeFromFormat() or an array of parameters specified at setPageFormat().
1838 * @param $unicode (boolean) TRUE means that the input text is unicode (default = true)
1839 * @param $encoding (string) Charset encoding (used only when converting back html entities); default is UTF-8.
1840 * @param $diskcache (boolean) If TRUE reduce the RAM memory usage by caching temporary data on filesystem (slower).
1841 * @param $pdfa (boolean) If TRUE set the document to PDF/A mode.
1842 * @public
1843 * @see getPageSizeFromFormat(), setPageFormat()
1844 */
1845 public function __construct($orientation='P', $unit='mm', $format='A4', $unicode=true, $encoding='UTF-8', $diskcache=false, $pdfa=false) {
1846 /* Set internal character encoding to ASCII */
1847 if (function_exists('mb_internal_encoding') AND mb_internal_encoding()) {
1848 $this->internal_encoding = mb_internal_encoding();
1849 mb_internal_encoding('ASCII');
1850 }
1851 // set file ID for trailer
1852 $serformat = (is_array($format) ? json_encode($format) : $format);
1853 $this->file_id = md5(TCPDF_STATIC::getRandomSeed('TCPDF'.$orientation.$unit.$serformat.$encoding));
1854 $this->font_obj_ids = array();
1855 $this->page_obj_id = array();
1856 $this->form_obj_id = array();
1857 // set pdf/a mode
1858 $this->pdfa_mode = $pdfa;
1859 $this->force_srgb = false;
1860 // set disk caching
1861 $this->diskcache = $diskcache ? true : false;
1862 // set language direction
1863 $this->rtl = false;
1864 $this->tmprtl = false;
1865 // some checks
1866 $this->_dochecks();
1867 // initialization of properties
1868 $this->isunicode = $unicode;
1869 $this->page = 0;
1870 $this->transfmrk[0] = array();
1871 $this->pagedim = array();
1872 $this->n = 2;
1873 $this->buffer = '';
1874 $this->pages = array();
1875 $this->state = 0;
1876 $this->fonts = array();
1877 $this->FontFiles = array();
1878 $this->diffs = array();
1879 $this->images = array();
1880 $this->links = array();
1881 $this->gradients = array();
1882 $this->InFooter = false;
1883 $this->lasth = 0;
1884 $this->FontFamily = defined('PDF_FONT_NAME_MAIN')?PDF_FONT_NAME_MAIN:'helvetica';
1885 $this->FontStyle = '';
1886 $this->FontSizePt = 12;
1887 $this->underline = false;
1888 $this->overline = false;
1889 $this->linethrough = false;
1890 $this->DrawColor = '0 G';
1891 $this->FillColor = '0 g';
1892 $this->TextColor = '0 g';
1893 $this->ColorFlag = false;
1894 $this->pdflayers = array();
1895 // encryption values
1896 $this->encrypted = false;
1897 $this->last_enc_key = '';
1898 // standard Unicode fonts
1899 $this->CoreFonts = array(
1900 'courier'=>'Courier',
1901 'courierB'=>'Courier-Bold',
1902 'courierI'=>'Courier-Oblique',
1903 'courierBI'=>'Courier-BoldOblique',
1904 'helvetica'=>'Helvetica',
1905 'helveticaB'=>'Helvetica-Bold',
1906 'helveticaI'=>'Helvetica-Oblique',
1907 'helveticaBI'=>'Helvetica-BoldOblique',
1908 'times'=>'Times-Roman',
1909 'timesB'=>'Times-Bold',
1910 'timesI'=>'Times-Italic',
1911 'timesBI'=>'Times-BoldItalic',
1912 'symbol'=>'Symbol',
1913 'zapfdingbats'=>'ZapfDingbats'
1914 );
1915 // set scale factor
1916 $this->setPageUnit($unit);
1917 // set page format and orientation
1918 $this->setPageFormat($format, $orientation);
1919 // page margins (1 cm)
1920 $margin = 28.35 / $this->k;
1921 $this->SetMargins($margin, $margin);
1922 $this->clMargin = $this->lMargin;
1923 $this->crMargin = $this->rMargin;
1924 // internal cell padding
1925 $cpadding = $margin / 10;
1926 $this->setCellPaddings($cpadding, 0, $cpadding, 0);
1927 // cell margins
1928 $this->setCellMargins(0, 0, 0, 0);
1929 // line width (0.2 mm)
1930 $this->LineWidth = 0.57 / $this->k;
1931 $this->linestyleWidth = sprintf('%F w', ($this->LineWidth * $this->k));
1932 $this->linestyleCap = '0 J';
1933 $this->linestyleJoin = '0 j';
1934 $this->linestyleDash = '[] 0 d';
1935 // automatic page break
1936 $this->SetAutoPageBreak(true, (2 * $margin));
1937 // full width display mode
1938 $this->SetDisplayMode('fullwidth');
1939 // compression
1940 $this->SetCompression();
1941 // set default PDF version number
1942 $this->setPDFVersion();
1943 $this->tcpdflink = true;
1944 $this->encoding = $encoding;
1945 $this->HREF = array();
1946 $this->getFontsList();
1947 $this->fgcolor = array('R' => 0, 'G' => 0, 'B' => 0);
1948 $this->strokecolor = array('R' => 0, 'G' => 0, 'B' => 0);
1949 $this->bgcolor = array('R' => 255, 'G' => 255, 'B' => 255);
1950 $this->extgstates = array();
1951 $this->setTextShadow();
1952 // signature
1953 $this->sign = false;
1954 $this->tsa_timestamp = false;
1955 $this->tsa_data = array();
1956 $this->signature_appearance = array('page' => 1, 'rect' => '0 0 0 0', 'name' => 'Signature');
1957 $this->empty_signature_appearance = array();
1958 // user's rights
1959 $this->ur['enabled'] = false;
1960 $this->ur['document'] = '/FullSave';
1961 $this->ur['annots'] = '/Create/Delete/Modify/Copy/Import/Export';
1962 $this->ur['form'] = '/Add/Delete/FillIn/Import/Export/SubmitStandalone/SpawnTemplate';
1963 $this->ur['signature'] = '/Modify';
1964 $this->ur['ef'] = '/Create/Delete/Modify/Import';
1965 $this->ur['formex'] = '';
1966 // set default JPEG quality
1967 $this->jpeg_quality = 75;
1968 // initialize some settings
1969 TCPDF_FONTS::utf8Bidi(array(''), '', false, $this->isunicode, $this->CurrentFont);
1970 // set default font
1971 $this->SetFont($this->FontFamily, $this->FontStyle, $this->FontSizePt);
1972 $this->setHeaderFont(array($this->FontFamily, $this->FontStyle, $this->FontSizePt));
1973 $this->setFooterFont(array($this->FontFamily, $this->FontStyle, $this->FontSizePt));
1974 // check if PCRE Unicode support is enabled
1975 if ($this->isunicode AND (@preg_match('/\pL/u', 'a') == 1)) {
1976 // PCRE unicode support is turned ON
1977 // \s : any whitespace character
1978 // \p{Z} : any separator
1979 // \p{Lo} : Unicode letter or ideograph that does not have lowercase and uppercase variants. Is used to chunk chinese words.
1980 // \xa0 : Unicode Character 'NO-BREAK SPACE' (U+00A0)
1981 //$this->setSpacesRE('/(?!\xa0)[\s\p{Z}\p{Lo}]/u');
1982 $this->setSpacesRE('/(?!\xa0)[\s\p{Z}]/u');
1983 } else {
1984 // PCRE unicode support is turned OFF
1985 $this->setSpacesRE('/[^\S\xa0]/');
1986 }
1987 $this->default_form_prop = array('lineWidth'=>1, 'borderStyle'=>'solid', 'fillColor'=>array(255, 255, 255), 'strokeColor'=>array(128, 128, 128));
1988 // set document creation and modification timestamp
1989 $this->doc_creation_timestamp = time();
1990 $this->doc_modification_timestamp = $this->doc_creation_timestamp;
1991 // get default graphic vars
1992 $this->default_graphic_vars = $this->getGraphicVars();
1993 $this->header_xobj_autoreset = false;
1994 $this->custom_xmp = '';
1995 }
1996
1997 /**
1998 * Default destructor.
1999 * @public
2000 * @since 1.53.0.TC016
2001 */
2002 public function __destruct() {
2003 // restore internal encoding
2004 if (isset($this->internal_encoding) AND !empty($this->internal_encoding)) {
2005 mb_internal_encoding($this->internal_encoding);
2006 }
2007 // unset all class variables
2008 $this->_destroy(true);
2009 }
2010
2011 /**
2012 * Set the units of measure for the document.
2013 * @param $unit (string) User measure unit. Possible values are:<ul><li>pt: point</li><li>mm: millimeter (default)</li><li>cm: centimeter</li><li>in: inch</li></ul><br />A point equals 1/72 of inch, that is to say about 0.35 mm (an inch being 2.54 cm). This is a very common unit in typography; font sizes are expressed in that unit.
2014 * @public
2015 * @since 3.0.015 (2008-06-06)
2016 */
2017 public function setPageUnit($unit) {
2018 $unit = strtolower($unit);
2019 //Set scale factor
2020 switch ($unit) {
2021 // points
2022 case 'px':
2023 case 'pt': {
2024 $this->k = 1;
2025 break;
2026 }
2027 // millimeters
2028 case 'mm': {
2029 $this->k = $this->dpi / 25.4;
2030 break;
2031 }
2032 // centimeters
2033 case 'cm': {
2034 $this->k = $this->dpi / 2.54;
2035 break;
2036 }
2037 // inches
2038 case 'in': {
2039 $this->k = $this->dpi;
2040 break;
2041 }
2042 // unsupported unit
2043 default : {
2044 $this->Error('Incorrect unit: '.$unit);
2045 break;
2046 }
2047 }
2048 $this->pdfunit = $unit;
2049 if (isset($this->CurOrientation)) {
2050 $this->setPageOrientation($this->CurOrientation);
2051 }
2052 }
2053
2054 /**
2055 * Change the format of the current page
2056 * @param $format (mixed) The format used for pages. It can be either: one of the string values specified at getPageSizeFromFormat() documentation or an array of two numbers (width, height) or an array containing the following measures and options:<ul>
2057 * <li>['format'] = page format name (one of the above);</li>
2058 * <li>['Rotate'] : The number of degrees by which the page shall be rotated clockwise when displayed or printed. The value shall be a multiple of 90.</li>
2059 * <li>['PZ'] : The page's preferred zoom (magnification) factor.</li>
2060 * <li>['MediaBox'] : the boundaries of the physical medium on which the page shall be displayed or printed:</li>
2061 * <li>['MediaBox']['llx'] : lower-left x coordinate</li>
2062 * <li>['MediaBox']['lly'] : lower-left y coordinate</li>
2063 * <li>['MediaBox']['urx'] : upper-right x coordinate</li>
2064 * <li>['MediaBox']['ury'] : upper-right y coordinate</li>
2065 * <li>['CropBox'] : the visible region of default user space:</li>
2066 * <li>['CropBox']['llx'] : lower-left x coordinate</li>
2067 * <li>['CropBox']['lly'] : lower-left y coordinate</li>
2068 * <li>['CropBox']['urx'] : upper-right x coordinate</li>
2069 * <li>['CropBox']['ury'] : upper-right y coordinate</li>
2070 * <li>['BleedBox'] : the region to which the contents of the page shall be clipped when output in a production environment:</li>
2071 * <li>['BleedBox']['llx'] : lower-left x coordinate</li>
2072 * <li>['BleedBox']['lly'] : lower-left y coordinate</li>
2073 * <li>['BleedBox']['urx'] : upper-right x coordinate</li>
2074 * <li>['BleedBox']['ury'] : upper-right y coordinate</li>
2075 * <li>['TrimBox'] : the intended dimensions of the finished page after trimming:</li>
2076 * <li>['TrimBox']['llx'] : lower-left x coordinate</li>
2077 * <li>['TrimBox']['lly'] : lower-left y coordinate</li>
2078 * <li>['TrimBox']['urx'] : upper-right x coordinate</li>
2079 * <li>['TrimBox']['ury'] : upper-right y coordinate</li>
2080 * <li>['ArtBox'] : the extent of the page's meaningful content:</li>
2081 * <li>['ArtBox']['llx'] : lower-left x coordinate</li>
2082 * <li>['ArtBox']['lly'] : lower-left y coordinate</li>
2083 * <li>['ArtBox']['urx'] : upper-right x coordinate</li>
2084 * <li>['ArtBox']['ury'] : upper-right y coordinate</li>
2085 * <li>['BoxColorInfo'] :specify the colours and other visual characteristics that should be used in displaying guidelines on the screen for each of the possible page boundaries other than the MediaBox:</li>
2086 * <li>['BoxColorInfo'][BOXTYPE]['C'] : an array of three numbers in the range 0-255, representing the components in the DeviceRGB colour space.</li>
2087 * <li>['BoxColorInfo'][BOXTYPE]['W'] : the guideline width in default user units</li>
2088 * <li>['BoxColorInfo'][BOXTYPE]['S'] : the guideline style: S = Solid; D = Dashed</li>
2089 * <li>['BoxColorInfo'][BOXTYPE]['D'] : dash array defining a pattern of dashes and gaps to be used in drawing dashed guidelines</li>
2090 * <li>['trans'] : the style and duration of the visual transition to use when moving from another page to the given page during a presentation</li>
2091 * <li>['trans']['Dur'] : The page's display duration (also called its advance timing): the maximum length of time, in seconds, that the page shall be displayed during presentations before the viewer application shall automatically advance to the next page.</li>
2092 * <li>['trans']['S'] : transition style : Split, Blinds, Box, Wipe, Dissolve, Glitter, R, Fly, Push, Cover, Uncover, Fade</li>
2093 * <li>['trans']['D'] : The duration of the transition effect, in seconds.</li>
2094 * <li>['trans']['Dm'] : (Split and Blinds transition styles only) The dimension in which the specified transition effect shall occur: H = Horizontal, V = Vertical. Default value: H.</li>
2095 * <li>['trans']['M'] : (Split, Box and Fly transition styles only) The direction of motion for the specified transition effect: I = Inward from the edges of the page, O = Outward from the center of the pageDefault value: I.</li>
2096 * <li>['trans']['Di'] : (Wipe, Glitter, Fly, Cover, Uncover and Push transition styles only) The direction in which the specified transition effect shall moves, expressed in degrees counterclockwise starting from a left-to-right direction. If the value is a number, it shall be one of: 0 = Left to right, 90 = Bottom to top (Wipe only), 180 = Right to left (Wipe only), 270 = Top to bottom, 315 = Top-left to bottom-right (Glitter only). If the value is a name, it shall be None, which is relevant only for the Fly transition when the value of SS is not 1.0. Default value: 0.</li>
2097 * <li>['trans']['SS'] : (Fly transition style only) The starting or ending scale at which the changes shall be drawn. If M specifies an inward transition, the scale of the changes drawn shall progress from SS to 1.0 over the course of the transition. If M specifies an outward transition, the scale of the changes drawn shall progress from 1.0 to SS over the course of the transition. Default: 1.0.</li>
2098 * <li>['trans']['B'] : (Fly transition style only) If true, the area that shall be flown in is rectangular and opaque. Default: false.</li>
2099 * </ul>
2100 * @param $orientation (string) page orientation. Possible values are (case insensitive):<ul>
2101 * <li>P or Portrait (default)</li>
2102 * <li>L or Landscape</li>
2103 * <li>'' (empty string) for automatic orientation</li>
2104 * </ul>
2105 * @protected
2106 * @since 3.0.015 (2008-06-06)
2107 * @see getPageSizeFromFormat()
2108 */
2109 protected function setPageFormat($format, $orientation='P') {
2110 if (!empty($format) AND isset($this->pagedim[$this->page])) {
2111 // remove inherited values
2112 unset($this->pagedim[$this->page]);
2113 }
2114 if (is_string($format)) {
2115 // get page measures from format name
2116 $pf = TCPDF_STATIC::getPageSizeFromFormat($format);
2117 $this->fwPt = $pf[0];
2118 $this->fhPt = $pf[1];
2119 } else {
2120 // the boundaries of the physical medium on which the page shall be displayed or printed
2121 if (isset($format['MediaBox'])) {
2122 $this->pagedim = TCPDF_STATIC::setPageBoxes($this->page, 'MediaBox', $format['MediaBox']['llx'], $format['MediaBox']['lly'], $format['MediaBox']['urx'], $format['MediaBox']['ury'], false, $this->k, $this->pagedim);
2123 $this->fwPt = (($format['MediaBox']['urx'] - $format['MediaBox']['llx']) * $this->k);
2124 $this->fhPt = (($format['MediaBox']['ury'] - $format['MediaBox']['lly']) * $this->k);
2125 } else {
2126 if (isset($format[0]) AND is_numeric($format[0]) AND isset($format[1]) AND is_numeric($format[1])) {
2127 $pf = array(($format[0] * $this->k), ($format[1] * $this->k));
2128 } else {
2129 if (!isset($format['format'])) {
2130 // default value
2131 $format['format'] = 'A4';
2132 }
2133 $pf = TCPDF_STATIC::getPageSizeFromFormat($format['format']);
2134 }
2135 $this->fwPt = $pf[0];
2136 $this->fhPt = $pf[1];
2137 $this->pagedim = TCPDF_STATIC::setPageBoxes($this->page, 'MediaBox', 0, 0, $this->fwPt, $this->fhPt, true, $this->k, $this->pagedim);
2138 }
2139 // the visible region of default user space
2140 if (isset($format['CropBox'])) {
2141 $this->pagedim = TCPDF_STATIC::setPageBoxes($this->page, 'CropBox', $format['CropBox']['llx'], $format['CropBox']['lly'], $format['CropBox']['urx'], $format['CropBox']['ury'], false, $this->k, $this->pagedim);
2142 }
2143 // the region to which the contents of the page shall be clipped when output in a production environment
2144 if (isset($format['BleedBox'])) {
2145 $this->pagedim = TCPDF_STATIC::setPageBoxes($this->page, 'BleedBox', $format['BleedBox']['llx'], $format['BleedBox']['lly'], $format['BleedBox']['urx'], $format['BleedBox']['ury'], false, $this->k, $this->pagedim);
2146 }
2147 // the intended dimensions of the finished page after trimming
2148 if (isset($format['TrimBox'])) {
2149 $this->pagedim = TCPDF_STATIC::setPageBoxes($this->page, 'TrimBox', $format['TrimBox']['llx'], $format['TrimBox']['lly'], $format['TrimBox']['urx'], $format['TrimBox']['ury'], false, $this->k, $this->pagedim);
2150 }
2151 // the page's meaningful content (including potential white space)
2152 if (isset($format['ArtBox'])) {
2153 $this->pagedim = TCPDF_STATIC::setPageBoxes($this->page, 'ArtBox', $format['ArtBox']['llx'], $format['ArtBox']['lly'], $format['ArtBox']['urx'], $format['ArtBox']['ury'], false, $this->k, $this->pagedim);
2154 }
2155 // specify the colours and other visual characteristics that should be used in displaying guidelines on the screen for the various page boundaries
2156 if (isset($format['BoxColorInfo'])) {
2157 $this->pagedim[$this->page]['BoxColorInfo'] = $format['BoxColorInfo'];
2158 }
2159 if (isset($format['Rotate']) AND (($format['Rotate'] % 90) == 0)) {
2160 // The number of degrees by which the page shall be rotated clockwise when displayed or printed. The value shall be a multiple of 90.
2161 $this->pagedim[$this->page]['Rotate'] = intval($format['Rotate']);
2162 }
2163 if (isset($format['PZ'])) {
2164 // The page's preferred zoom (magnification) factor
2165 $this->pagedim[$this->page]['PZ'] = floatval($format['PZ']);
2166 }
2167 if (isset($format['trans'])) {
2168 // The style and duration of the visual transition to use when moving from another page to the given page during a presentation
2169 if (isset($format['trans']['Dur'])) {
2170 // The page's display duration
2171 $this->pagedim[$this->page]['trans']['Dur'] = floatval($format['trans']['Dur']);
2172 }
2173 $stansition_styles = array('Split', 'Blinds', 'Box', 'Wipe', 'Dissolve', 'Glitter', 'R', 'Fly', 'Push', 'Cover', 'Uncover', 'Fade');
2174 if (isset($format['trans']['S']) AND in_array($format['trans']['S'], $stansition_styles)) {
2175 // The transition style that shall be used when moving to this page from another during a presentation
2176 $this->pagedim[$this->page]['trans']['S'] = $format['trans']['S'];
2177 $valid_effect = array('Split', 'Blinds');
2178 $valid_vals = array('H', 'V');
2179 if (isset($format['trans']['Dm']) AND in_array($format['trans']['S'], $valid_effect) AND in_array($format['trans']['Dm'], $valid_vals)) {
2180 $this->pagedim[$this->page]['trans']['Dm'] = $format['trans']['Dm'];
2181 }
2182 $valid_effect = array('Split', 'Box', 'Fly');
2183 $valid_vals = array('I', 'O');
2184 if (isset($format['trans']['M']) AND in_array($format['trans']['S'], $valid_effect) AND in_array($format['trans']['M'], $valid_vals)) {
2185 $this->pagedim[$this->page]['trans']['M'] = $format['trans']['M'];
2186 }
2187 $valid_effect = array('Wipe', 'Glitter', 'Fly', 'Cover', 'Uncover', 'Push');
2188 if (isset($format['trans']['Di']) AND in_array($format['trans']['S'], $valid_effect)) {
2189 if (((($format['trans']['Di'] == 90) OR ($format['trans']['Di'] == 180)) AND ($format['trans']['S'] == 'Wipe'))
2190 OR (($format['trans']['Di'] == 315) AND ($format['trans']['S'] == 'Glitter'))
2191 OR (($format['trans']['Di'] == 0) OR ($format['trans']['Di'] == 270))) {
2192 $this->pagedim[$this->page]['trans']['Di'] = intval($format['trans']['Di']);
2193 }
2194 }
2195 if (isset($format['trans']['SS']) AND ($format['trans']['S'] == 'Fly')) {
2196 $this->pagedim[$this->page]['trans']['SS'] = floatval($format['trans']['SS']);
2197 }
2198 if (isset($format['trans']['B']) AND ($format['trans']['B'] === true) AND ($format['trans']['S'] == 'Fly')) {
2199 $this->pagedim[$this->page]['trans']['B'] = 'true';
2200 }
2201 } else {
2202 $this->pagedim[$this->page]['trans']['S'] = 'R';
2203 }
2204 if (isset($format['trans']['D'])) {
2205 // The duration of the transition effect, in seconds
2206 $this->pagedim[$this->page]['trans']['D'] = floatval($format['trans']['D']);
2207 } else {
2208 $this->pagedim[$this->page]['trans']['D'] = 1;
2209 }
2210 }
2211 }
2212 $this->setPageOrientation($orientation);
2213 }
2214
2215 /**
2216 * Set page orientation.
2217 * @param $orientation (string) page orientation. Possible values are (case insensitive):<ul><li>P or Portrait (default)</li><li>L or Landscape</li><li>'' (empty string) for automatic orientation</li></ul>
2218 * @param $autopagebreak (boolean) Boolean indicating if auto-page-break mode should be on or off.
2219 * @param $bottommargin (float) bottom margin of the page.
2220 * @public
2221 * @since 3.0.015 (2008-06-06)
2222 */
2223 public function setPageOrientation($orientation, $autopagebreak='', $bottommargin='') {
2224 if (!isset($this->pagedim[$this->page]['MediaBox'])) {
2225 // the boundaries of the physical medium on which the page shall be displayed or printed
2226 $this->pagedim = TCPDF_STATIC::setPageBoxes($this->page, 'MediaBox', 0, 0, $this->fwPt, $this->fhPt, true, $this->k, $this->pagedim);
2227 }
2228 if (!isset($this->pagedim[$this->page]['CropBox'])) {
2229 // the visible region of default user space
2230 $this->pagedim = TCPDF_STATIC::setPageBoxes($this->page, 'CropBox', $this->pagedim[$this->page]['MediaBox']['llx'], $this->pagedim[$this->page]['MediaBox']['lly'], $this->pagedim[$this->page]['MediaBox']['urx'], $this->pagedim[$this->page]['MediaBox']['ury'], true, $this->k, $this->pagedim);
2231 }
2232 if (!isset($this->pagedim[$this->page]['BleedBox'])) {
2233 // the region to which the contents of the page shall be clipped when output in a production environment
2234 $this->pagedim = TCPDF_STATIC::setPageBoxes($this->page, 'BleedBox', $this->pagedim[$this->page]['CropBox']['llx'], $this->pagedim[$this->page]['CropBox']['lly'], $this->pagedim[$this->page]['CropBox']['urx'], $this->pagedim[$this->page]['CropBox']['ury'], true, $this->k, $this->pagedim);
2235 }
2236 if (!isset($this->pagedim[$this->page]['TrimBox'])) {
2237 // the intended dimensions of the finished page after trimming
2238 $this->pagedim = TCPDF_STATIC::setPageBoxes($this->page, 'TrimBox', $this->pagedim[$this->page]['CropBox']['llx'], $this->pagedim[$this->page]['CropBox']['lly'], $this->pagedim[$this->page]['CropBox']['urx'], $this->pagedim[$this->page]['CropBox']['ury'], true, $this->k, $this->pagedim);
2239 }
2240 if (!isset($this->pagedim[$this->page]['ArtBox'])) {
2241 // the page's meaningful content (including potential white space)
2242 $this->pagedim = TCPDF_STATIC::setPageBoxes($this->page, 'ArtBox', $this->pagedim[$this->page]['CropBox']['llx'], $this->pagedim[$this->page]['CropBox']['lly'], $this->pagedim[$this->page]['CropBox']['urx'], $this->pagedim[$this->page]['CropBox']['ury'], true, $this->k, $this->pagedim);
2243 }
2244 if (!isset($this->pagedim[$this->page]['Rotate'])) {
2245 // The number of degrees by which the page shall be rotated clockwise when displayed or printed. The value shall be a multiple of 90.
2246 $this->pagedim[$this->page]['Rotate'] = 0;
2247 }
2248 if (!isset($this->pagedim[$this->page]['PZ'])) {
2249 // The page's preferred zoom (magnification) factor
2250 $this->pagedim[$this->page]['PZ'] = 1;
2251 }
2252 if ($this->fwPt > $this->fhPt) {
2253 // landscape
2254 $default_orientation = 'L';
2255 } else {
2256 // portrait
2257 $default_orientation = 'P';
2258 }
2259 $valid_orientations = array('P', 'L');
2260 if (empty($orientation)) {
2261 $orientation = $default_orientation;
2262 } else {
2263 $orientation = strtoupper($orientation[0]);
2264 }
2265 if (in_array($orientation, $valid_orientations) AND ($orientation != $default_orientation)) {
2266 $this->CurOrientation = $orientation;
2267 $this->wPt = $this->fhPt;
2268 $this->hPt = $this->fwPt;
2269 } else {
2270 $this->CurOrientation = $default_orientation;
2271 $this->wPt = $this->fwPt;
2272 $this->hPt = $this->fhPt;
2273 }
2274 if ((abs($this->pagedim[$this->page]['MediaBox']['urx'] - $this->hPt) < $this->feps) AND (abs($this->pagedim[$this->page]['MediaBox']['ury'] - $this->wPt) < $this->feps)){
2275 // swap X and Y coordinates (change page orientation)
2276 $this->pagedim = TCPDF_STATIC::swapPageBoxCoordinates($this->page, $this->pagedim);
2277 }
2278 $this->w = ($this->wPt / $this->k);
2279 $this->h = ($this->hPt / $this->k);
2280 if (TCPDF_STATIC::empty_string($autopagebreak)) {
2281 if (isset($this->AutoPageBreak)) {
2282 $autopagebreak = $this->AutoPageBreak;
2283 } else {
2284 $autopagebreak = true;
2285 }
2286 }
2287 if (TCPDF_STATIC::empty_string($bottommargin)) {
2288 if (isset($this->bMargin)) {
2289 $bottommargin = $this->bMargin;
2290 } else {
2291 // default value = 2 cm
2292 $bottommargin = 2 * 28.35 / $this->k;
2293 }
2294 }
2295 $this->SetAutoPageBreak($autopagebreak, $bottommargin);
2296 // store page dimensions
2297 $this->pagedim[$this->page]['w'] = $this->wPt;
2298 $this->pagedim[$this->page]['h'] = $this->hPt;
2299 $this->pagedim[$this->page]['wk'] = $this->w;
2300 $this->pagedim[$this->page]['hk'] = $this->h;
2301 $this->pagedim[$this->page]['tm'] = $this->tMargin;
2302 $this->pagedim[$this->page]['bm'] = $bottommargin;
2303 $this->pagedim[$this->page]['lm'] = $this->lMargin;
2304 $this->pagedim[$this->page]['rm'] = $this->rMargin;
2305 $this->pagedim[$this->page]['pb'] = $autopagebreak;
2306 $this->pagedim[$this->page]['or'] = $this->CurOrientation;
2307 $this->pagedim[$this->page]['olm'] = $this->original_lMargin;
2308 $this->pagedim[$this->page]['orm'] = $this->original_rMargin;
2309 }
2310
2311 /**
2312 * Set regular expression to detect withespaces or word separators.
2313 * The pattern delimiter must be the forward-slash character "/".
2314 * Some example patterns are:
2315 * <pre>
2316 * Non-Unicode or missing PCRE unicode support: "/[^\S\xa0]/"
2317 * Unicode and PCRE unicode support: "/(?!\xa0)[\s\p{Z}]/u"
2318 * Unicode and PCRE unicode support in Chinese mode: "/(?!\xa0)[\s\p{Z}\p{Lo}]/u"
2319 * if PCRE unicode support is turned ON ("\P" is the negate class of "\p"):
2320 * \s : any whitespace character
2321 * \p{Z} : any separator
2322 * \p{Lo} : Unicode letter or ideograph that does not have lowercase and uppercase variants. Is used to chunk chinese words.
2323 * \xa0 : Unicode Character 'NO-BREAK SPACE' (U+00A0)
2324 * </pre>
2325 * @param $re (string) regular expression (leave empty for default).
2326 * @public
2327 * @since 4.6.016 (2009-06-15)
2328 */
2329 public function setSpacesRE($re='/[^\S\xa0]/') {
2330 $this->re_spaces = $re;
2331 $re_parts = explode('/', $re);
2332 // get pattern parts
2333 $this->re_space = array();
2334 if (isset($re_parts[1]) AND !empty($re_parts[1])) {
2335 $this->re_space['p'] = $re_parts[1];
2336 } else {
2337 $this->re_space['p'] = '[\s]';
2338 }
2339 // set pattern modifiers
2340 if (isset($re_parts[2]) AND !empty($re_parts[2])) {
2341 $this->re_space['m'] = $re_parts[2];
2342 } else {
2343 $this->re_space['m'] = '';
2344 }
2345 }
2346
2347 /**
2348 * Enable or disable Right-To-Left language mode
2349 * @param $enable (Boolean) if true enable Right-To-Left language mode.
2350 * @param $resetx (Boolean) if true reset the X position on direction change.
2351 * @public
2352 * @since 2.0.000 (2008-01-03)
2353 */
2354 public function setRTL($enable, $resetx=true) {
2355 $enable = $enable ? true : false;
2356 $resetx = ($resetx AND ($enable != $this->rtl));
2357 $this->rtl = $enable;
2358 $this->tmprtl = false;
2359 if ($resetx) {
2360 $this->Ln(0);
2361 }
2362 }
2363
2364 /**
2365 * Return the RTL status
2366 * @return boolean
2367 * @public
2368 * @since 4.0.012 (2008-07-24)
2369 */
2370 public function getRTL() {
2371 return $this->rtl;
2372 }
2373
2374 /**
2375 * Force temporary RTL language direction
2376 * @param $mode (mixed) can be false, 'L' for LTR or 'R' for RTL
2377 * @public
2378 * @since 2.1.000 (2008-01-09)
2379 */
2380 public function setTempRTL($mode) {
2381 $newmode = false;
2382 switch (strtoupper($mode)) {
2383 case 'LTR':
2384 case 'L': {
2385 if ($this->rtl) {
2386 $newmode = 'L';
2387 }
2388 break;
2389 }
2390 case 'RTL':
2391 case 'R': {
2392 if (!$this->rtl) {
2393 $newmode = 'R';
2394 }
2395 break;
2396 }
2397 case false:
2398 default: {
2399 $newmode = false;
2400 break;
2401 }
2402 }
2403 $this->tmprtl = $newmode;
2404 }
2405
2406 /**
2407 * Return the current temporary RTL status
2408 * @return boolean
2409 * @public
2410 * @since 4.8.014 (2009-11-04)
2411 */
2412 public function isRTLTextDir() {
2413 return ($this->rtl OR ($this->tmprtl == 'R'));
2414 }
2415
2416 /**
2417 * Set the last cell height.
2418 * @param $h (float) cell height.
2419 * @author Nicola Asuni
2420 * @public
2421 * @since 1.53.0.TC034
2422 */
2423 public function setLastH($h) {
2424 $this->lasth = $h;
2425 }
2426
2427 /**
2428 * Return the cell height
2429 * @param $fontsize (int) Font size in internal units
2430 * @param $padding (boolean) If true add cell padding
2431 * @public
2432 */
2433 public function getCellHeight($fontsize, $padding=TRUE) {
2434 $height = ($fontsize * $this->cell_height_ratio);
2435 if ($padding) {
2436 $height += ($this->cell_padding['T'] + $this->cell_padding['B']);
2437 }
2438 return round($height, 6);
2439 }
2440
2441 /**
2442 * Reset the last cell height.
2443 * @public
2444 * @since 5.9.000 (2010-10-03)
2445 */
2446 public function resetLastH() {
2447 $this->lasth = $this->getCellHeight($this->FontSize);
2448 }
2449
2450 /**
2451 * Get the last cell height.
2452 * @return last cell height
2453 * @public
2454 * @since 4.0.017 (2008-08-05)
2455 */
2456 public function getLastH() {
2457 return $this->lasth;
2458 }
2459
2460 /**
2461 * Set the adjusting factor to convert pixels to user units.
2462 * @param $scale (float) adjusting factor to convert pixels to user units.
2463 * @author Nicola Asuni
2464 * @public
2465 * @since 1.5.2
2466 */
2467 public function setImageScale($scale) {
2468 $this->imgscale = $scale;
2469 }
2470
2471 /**
2472 * Returns the adjusting factor to convert pixels to user units.
2473 * @return float adjusting factor to convert pixels to user units.
2474 * @author Nicola Asuni
2475 * @public
2476 * @since 1.5.2
2477 */
2478 public function getImageScale() {
2479 return $this->imgscale;
2480 }
2481
2482 /**
2483 * Returns an array of page dimensions:
2484 * <ul><li>$this->pagedim[$this->page]['w'] = page width in points</li><li>$this->pagedim[$this->page]['h'] = height in points</li><li>$this->pagedim[$this->page]['wk'] = page width in user units</li><li>$this->pagedim[$this->page]['hk'] = page height in user units</li><li>$this->pagedim[$this->page]['tm'] = top margin</li><li>$this->pagedim[$this->page]['bm'] = bottom margin</li><li>$this->pagedim[$this->page]['lm'] = left margin</li><li>$this->pagedim[$this->page]['rm'] = right margin</li><li>$this->pagedim[$this->page]['pb'] = auto page break</li><li>$this->pagedim[$this->page]['or'] = page orientation</li><li>$this->pagedim[$this->page]['olm'] = original left margin</li><li>$this->pagedim[$this->page]['orm'] = original right margin</li><li>$this->pagedim[$this->page]['Rotate'] = The number of degrees by which the page shall be rotated clockwise when displayed or printed. The value shall be a multiple of 90.</li><li>$this->pagedim[$this->page]['PZ'] = The page's preferred zoom (magnification) factor.</li><li>$this->pagedim[$this->page]['trans'] : the style and duration of the visual transition to use when moving from another page to the given page during a presentation<ul><li>$this->pagedim[$this->page]['trans']['Dur'] = The page's display duration (also called its advance timing): the maximum length of time, in seconds, that the page shall be displayed during presentations before the viewer application shall automatically advance to the next page.</li><li>$this->pagedim[$this->page]['trans']['S'] = transition style : Split, Blinds, Box, Wipe, Dissolve, Glitter, R, Fly, Push, Cover, Uncover, Fade</li><li>$this->pagedim[$this->page]['trans']['D'] = The duration of the transition effect, in seconds.</li><li>$this->pagedim[$this->page]['trans']['Dm'] = (Split and Blinds transition styles only) The dimension in which the specified transition effect shall occur: H = Horizontal, V = Vertical. Default value: H.</li><li>$this->pagedim[$this->page]['trans']['M'] = (Split, Box and Fly transition styles only) The direction of motion for the specified transition effect: I = Inward from the edges of the page, O = Outward from the center of the pageDefault value: I.</li><li>$this->pagedim[$this->page]['trans']['Di'] = (Wipe, Glitter, Fly, Cover, Uncover and Push transition styles only) The direction in which the specified transition effect shall moves, expressed in degrees counterclockwise starting from a left-to-right direction. If the value is a number, it shall be one of: 0 = Left to right, 90 = Bottom to top (Wipe only), 180 = Right to left (Wipe only), 270 = Top to bottom, 315 = Top-left to bottom-right (Glitter only). If the value is a name, it shall be None, which is relevant only for the Fly transition when the value of SS is not 1.0. Default value: 0.</li><li>$this->pagedim[$this->page]['trans']['SS'] = (Fly transition style only) The starting or ending scale at which the changes shall be drawn. If M specifies an inward transition, the scale of the changes drawn shall progress from SS to 1.0 over the course of the transition. If M specifies an outward transition, the scale of the changes drawn shall progress from 1.0 to SS over the course of the transition. Default: 1.0. </li><li>$this->pagedim[$this->page]['trans']['B'] = (Fly transition style only) If true, the area that shall be flown in is rectangular and opaque. Default: false.</li></ul></li><li>$this->pagedim[$this->page]['MediaBox'] : the boundaries of the physical medium on which the page shall be displayed or printed<ul><li>$this->pagedim[$this->page]['MediaBox']['llx'] = lower-left x coordinate in points</li><li>$this->pagedim[$this->page]['MediaBox']['lly'] = lower-left y coordinate in points</li><li>$this->pagedim[$this->page]['MediaBox']['urx'] = upper-right x coordinate in points</li><li>$this->pagedim[$this->page]['MediaBox']['ury'] = upper-right y coordinate in points</li></ul></li><li>$this->pagedim[$this->page]['CropBox'] : the visible region of default user space<ul><li>$this->pagedim[$this->page]['CropBox']['llx'] = lower-left x coordinate in points</li><li>$this->pagedim[$this->page]['CropBox']['lly'] = lower-left y coordinate in points</li><li>$this->pagedim[$this->page]['CropBox']['urx'] = upper-right x coordinate in points</li><li>$this->pagedim[$this->page]['CropBox']['ury'] = upper-right y coordinate in points</li></ul></li><li>$this->pagedim[$this->page]['BleedBox'] : the region to which the contents of the page shall be clipped when output in a production environment<ul><li>$this->pagedim[$this->page]['BleedBox']['llx'] = lower-left x coordinate in points</li><li>$this->pagedim[$this->page]['BleedBox']['lly'] = lower-left y coordinate in points</li><li>$this->pagedim[$this->page]['BleedBox']['urx'] = upper-right x coordinate in points</li><li>$this->pagedim[$this->page]['BleedBox']['ury'] = upper-right y coordinate in points</li></ul></li><li>$this->pagedim[$this->page]['TrimBox'] : the intended dimensions of the finished page after trimming<ul><li>$this->pagedim[$this->page]['TrimBox']['llx'] = lower-left x coordinate in points</li><li>$this->pagedim[$this->page]['TrimBox']['lly'] = lower-left y coordinate in points</li><li>$this->pagedim[$this->page]['TrimBox']['urx'] = upper-right x coordinate in points</li><li>$this->pagedim[$this->page]['TrimBox']['ury'] = upper-right y coordinate in points</li></ul></li><li>$this->pagedim[$this->page]['ArtBox'] : the extent of the page's meaningful content<ul><li>$this->pagedim[$this->page]['ArtBox']['llx'] = lower-left x coordinate in points</li><li>$this->pagedim[$this->page]['ArtBox']['lly'] = lower-left y coordinate in points</li><li>$this->pagedim[$this->page]['ArtBox']['urx'] = upper-right x coordinate in points</li><li>$this->pagedim[$this->page]['ArtBox']['ury'] = upper-right y coordinate in points</li></ul></li></ul>
2485 * @param $pagenum (int) page number (empty = current page)
2486 * @return array of page dimensions.
2487 * @author Nicola Asuni
2488 * @public
2489 * @since 4.5.027 (2009-03-16)
2490 */
2491 public function getPageDimensions($pagenum='') {
2492 if (empty($pagenum)) {
2493 $pagenum = $this->page;
2494 }
2495 return $this->pagedim[$pagenum];
2496 }
2497
2498 /**
2499 * Returns the page width in units.
2500 * @param $pagenum (int) page number (empty = current page)
2501 * @return int page width.
2502 * @author Nicola Asuni
2503 * @public
2504 * @since 1.5.2
2505 * @see getPageDimensions()
2506 */
2507 public function getPageWidth($pagenum='') {
2508 if (empty($pagenum)) {
2509 return $this->w;
2510 }
2511 return $this->pagedim[$pagenum]['w'];
2512 }
2513
2514 /**
2515 * Returns the page height in units.
2516 * @param $pagenum (int) page number (empty = current page)
2517 * @return int page height.
2518 * @author Nicola Asuni
2519 * @public
2520 * @since 1.5.2
2521 * @see getPageDimensions()
2522 */
2523 public function getPageHeight($pagenum='') {
2524 if (empty($pagenum)) {
2525 return $this->h;
2526 }
2527 return $this->pagedim[$pagenum]['h'];
2528 }
2529
2530 /**
2531 * Returns the page break margin.
2532 * @param $pagenum (int) page number (empty = current page)
2533 * @return int page break margin.
2534 * @author Nicola Asuni
2535 * @public
2536 * @since 1.5.2
2537 * @see getPageDimensions()
2538 */
2539 public function getBreakMargin($pagenum='') {
2540 if (empty($pagenum)) {
2541 return $this->bMargin;
2542 }
2543 return $this->pagedim[$pagenum]['bm'];
2544 }
2545
2546 /**
2547 * Returns the scale factor (number of points in user unit).
2548 * @return int scale factor.
2549 * @author Nicola Asuni
2550 * @public
2551 * @since 1.5.2
2552 */
2553 public function getScaleFactor() {
2554 return $this->k;
2555 }
2556
2557 /**
2558 * Defines the left, top and right margins.
2559 * @param $left (float) Left margin.
2560 * @param $top (float) Top margin.
2561 * @param $right (float) Right margin. Default value is the left one.
2562 * @param $keepmargins (boolean) if true overwrites the default page margins
2563 * @public
2564 * @since 1.0
2565 * @see SetLeftMargin(), SetTopMargin(), SetRightMargin(), SetAutoPageBreak()
2566 */
2567 public function SetMargins($left, $top, $right=-1, $keepmargins=false) {
2568 //Set left, top and right margins
2569 $this->lMargin = $left;
2570 $this->tMargin = $top;
2571 if ($right == -1) {
2572 $right = $left;
2573 }
2574 $this->rMargin = $right;
2575 if ($keepmargins) {
2576 // overwrite original values
2577 $this->original_lMargin = $this->lMargin;
2578 $this->original_rMargin = $this->rMargin;
2579 }
2580 }
2581
2582 /**
2583 * Defines the left margin. The method can be called before creating the first page. If the current abscissa gets out of page, it is brought back to the margin.
2584 * @param $margin (float) The margin.
2585 * @public
2586 * @since 1.4
2587 * @see SetTopMargin(), SetRightMargin(), SetAutoPageBreak(), SetMargins()
2588 */
2589 public function SetLeftMargin($margin) {
2590 //Set left margin
2591 $this->lMargin = $margin;
2592 if (($this->page > 0) AND ($this->x < $margin)) {
2593 $this->x = $margin;
2594 }
2595 }
2596
2597 /**
2598 * Defines the top margin. The method can be called before creating the first page.
2599 * @param $margin (float) The margin.
2600 * @public
2601 * @since 1.5
2602 * @see SetLeftMargin(), SetRightMargin(), SetAutoPageBreak(), SetMargins()
2603 */
2604 public function SetTopMargin($margin) {
2605 //Set top margin
2606 $this->tMargin = $margin;
2607 if (($this->page > 0) AND ($this->y < $margin)) {
2608 $this->y = $margin;
2609 }
2610 }
2611
2612 /**
2613 * Defines the right margin. The method can be called before creating the first page.
2614 * @param $margin (float) The margin.
2615 * @public
2616 * @since 1.5
2617 * @see SetLeftMargin(), SetTopMargin(), SetAutoPageBreak(), SetMargins()
2618 */
2619 public function SetRightMargin($margin) {
2620 $this->rMargin = $margin;
2621 if (($this->page > 0) AND ($this->x > ($this->w - $margin))) {
2622 $this->x = $this->w - $margin;
2623 }
2624 }
2625
2626 /**
2627 * Set the same internal Cell padding for top, right, bottom, left-
2628 * @param $pad (float) internal padding.
2629 * @public
2630 * @since 2.1.000 (2008-01-09)
2631 * @see getCellPaddings(), setCellPaddings()
2632 */
2633 public function SetCellPadding($pad) {
2634 if ($pad >= 0) {
2635 $this->cell_padding['L'] = $pad;
2636 $this->cell_padding['T'] = $pad;
2637 $this->cell_padding['R'] = $pad;
2638 $this->cell_padding['B'] = $pad;
2639 }
2640 }
2641
2642 /**
2643 * Set the internal Cell paddings.
2644 * @param $left (float) left padding
2645 * @param $top (float) top padding
2646 * @param $right (float) right padding
2647 * @param $bottom (float) bottom padding
2648 * @public
2649 * @since 5.9.000 (2010-10-03)
2650 * @see getCellPaddings(), SetCellPadding()
2651 */
2652 public function setCellPaddings($left='', $top='', $right='', $bottom='') {
2653 if (($left !== '') AND ($left >= 0)) {
2654 $this->cell_padding['L'] = $left;
2655 }
2656 if (($top !== '') AND ($top >= 0)) {
2657 $this->cell_padding['T'] = $top;
2658 }
2659 if (($right !== '') AND ($right >= 0)) {
2660 $this->cell_padding['R'] = $right;
2661 }
2662 if (($bottom !== '') AND ($bottom >= 0)) {
2663 $this->cell_padding['B'] = $bottom;
2664 }
2665 }
2666
2667 /**
2668 * Get the internal Cell padding array.
2669 * @return array of padding values
2670 * @public
2671 * @since 5.9.000 (2010-10-03)
2672 * @see setCellPaddings(), SetCellPadding()
2673 */
2674 public function getCellPaddings() {
2675 return $this->cell_padding;
2676 }
2677
2678 /**
2679 * Set the internal Cell margins.
2680 * @param $left (float) left margin
2681 * @param $top (float) top margin
2682 * @param $right (float) right margin
2683 * @param $bottom (float) bottom margin
2684 * @public
2685 * @since 5.9.000 (2010-10-03)
2686 * @see getCellMargins()
2687 */
2688 public function setCellMargins($left='', $top='', $right='', $bottom='') {
2689 if (($left !== '') AND ($left >= 0)) {
2690 $this->cell_margin['L'] = $left;
2691 }
2692 if (($top !== '') AND ($top >= 0)) {
2693 $this->cell_margin['T'] = $top;
2694 }
2695 if (($right !== '') AND ($right >= 0)) {
2696 $this->cell_margin['R'] = $right;
2697 }
2698 if (($bottom !== '') AND ($bottom >= 0)) {
2699 $this->cell_margin['B'] = $bottom;
2700 }
2701 }
2702
2703 /**
2704 * Get the internal Cell margin array.
2705 * @return array of margin values
2706 * @public
2707 * @since 5.9.000 (2010-10-03)
2708 * @see setCellMargins()
2709 */
2710 public function getCellMargins() {
2711 return $this->cell_margin;
2712 }
2713
2714 /**
2715 * Adjust the internal Cell padding array to take account of the line width.
2716 * @param $brd (mixed) Indicates if borders must be drawn around the cell. 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 - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0)))
2717 * @return array of adjustments
2718 * @public
2719 * @since 5.9.000 (2010-10-03)
2720 */
2721 protected function adjustCellPadding($brd=0) {
2722 if (empty($brd)) {
2723 return;
2724 }
2725 if (is_string($brd)) {
2726 // convert string to array
2727 $slen = strlen($brd);
2728 $newbrd = array();
2729 for ($i = 0; $i < $slen; ++$i) {
2730 $newbrd[$brd[$i]] = true;
2731 }
2732 $brd = $newbrd;
2733 } elseif (($brd === 1) OR ($brd === true) OR (is_numeric($brd) AND (intval($brd) > 0))) {
2734 $brd = array('LRTB' => true);
2735 }
2736 if (!is_array($brd)) {
2737 return;
2738 }
2739 // store current cell padding
2740 $cp = $this->cell_padding;
2741 // select border mode
2742 if (isset($brd['mode'])) {
2743 $mode = $brd['mode'];
2744 unset($brd['mode']);
2745 } else {
2746 $mode = 'normal';
2747 }
2748 // process borders
2749 foreach ($brd as $border => $style) {
2750 $line_width = $this->LineWidth;
2751 if (is_array($style) AND isset($style['width'])) {
2752 // get border width
2753 $line_width = $style['width'];
2754 }
2755 $adj = 0; // line width inside the cell
2756 switch ($mode) {
2757 case 'ext': {
2758 $adj = 0;
2759 break;
2760 }
2761 case 'int': {
2762 $adj = $line_width;
2763 break;
2764 }
2765 case 'normal':
2766 default: {
2767 $adj = ($line_width / 2);
2768 break;
2769 }
2770 }
2771 // correct internal cell padding if required to avoid overlap between text and lines
2772 if ((strpos($border,'T') !== false) AND ($this->cell_padding['T'] < $adj)) {
2773 $this->cell_padding['T'] = $adj;
2774 }
2775 if ((strpos($border,'R') !== false) AND ($this->cell_padding['R'] < $adj)) {
2776 $this->cell_padding['R'] = $adj;
2777 }
2778 if ((strpos($border,'B') !== false) AND ($this->cell_padding['B'] < $adj)) {
2779 $this->cell_padding['B'] = $adj;
2780 }
2781 if ((strpos($border,'L') !== false) AND ($this->cell_padding['L'] < $adj)) {
2782 $this->cell_padding['L'] = $adj;
2783 }
2784 }
2785 return array('T' => ($this->cell_padding['T'] - $cp['T']), 'R' => ($this->cell_padding['R'] - $cp['R']), 'B' => ($this->cell_padding['B'] - $cp['B']), 'L' => ($this->cell_padding['L'] - $cp['L']));
2786 }
2787
2788 /**
2789 * Enables or disables the automatic page breaking mode. When enabling, the second parameter is the distance from the bottom of the page that defines the triggering limit. By default, the mode is on and the margin is 2 cm.
2790 * @param $auto (boolean) Boolean indicating if mode should be on or off.
2791 * @param $margin (float) Distance from the bottom of the page.
2792 * @public
2793 * @since 1.0
2794 * @see Cell(), MultiCell(), AcceptPageBreak()
2795 */
2796 public function SetAutoPageBreak($auto, $margin=0) {
2797 $this->AutoPageBreak = $auto ? true : false;
2798 $this->bMargin = $margin;
2799 $this->PageBreakTrigger = $this->h - $margin;
2800 }
2801
2802 /**
2803 * Return the auto-page-break mode (true or false).
2804 * @return boolean auto-page-break mode
2805 * @public
2806 * @since 5.9.088
2807 */
2808 public function getAutoPageBreak() {
2809 return $this->AutoPageBreak;
2810 }
2811
2812 /**
2813 * Defines the way the document is to be displayed by the viewer.
2814 * @param $zoom (mixed) The zoom to use. It can be one of the following string values or a number indicating the zooming factor to use. <ul><li>fullpage: displays the entire page on screen </li><li>fullwidth: uses maximum width of window</li><li>real: uses real size (equivalent to 100% zoom)</li><li>default: uses viewer default mode</li></ul>
2815 * @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>
2816 * @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>
2817 * @public
2818 * @since 1.2
2819 */
2820 public function SetDisplayMode($zoom, $layout='SinglePage', $mode='UseNone') {
2821 if (($zoom == 'fullpage') OR ($zoom == 'fullwidth') OR ($zoom == 'real') OR ($zoom == 'default') OR (!is_string($zoom))) {
2822 $this->ZoomMode = $zoom;
2823 } else {
2824 $this->Error('Incorrect zoom display mode: '.$zoom);
2825 }
2826 $this->LayoutMode = TCPDF_STATIC::getPageLayoutMode($layout);
2827 $this->PageMode = TCPDF_STATIC::getPageMode($mode);
2828 }
2829
2830 /**
2831 * Activates or deactivates page compression. When activated, the internal representation of each page is compressed, which leads to a compression ratio of about 2 for the resulting document. Compression is on by default.
2832 * Note: the Zlib extension is required for this feature. If not present, compression will be turned off.
2833 * @param $compress (boolean) Boolean indicating if compression must be enabled.
2834 * @public
2835 * @since 1.4
2836 */
2837 public function SetCompression($compress=true) {
2838 if (function_exists('gzcompress')) {
2839 $this->compress = $compress ? true : false;
2840 } else {
2841 $this->compress = false;
2842 }
2843 }
2844
2845 /**
2846 * Set flag to force sRGB_IEC61966-2.1 black scaled ICC color profile for the whole document.
2847 * @param $mode (boolean) If true force sRGB output intent.
2848 * @public
2849 * @since 5.9.121 (2011-09-28)
2850 */
2851 public function setSRGBmode($mode=false) {
2852 $this->force_srgb = $mode ? true : false;
2853 }
2854
2855 /**
2856 * Turn on/off Unicode mode for document information dictionary (meta tags).
2857 * This has effect only when unicode mode is set to false.
2858 * @param $unicode (boolean) if true set the meta information in Unicode
2859 * @since 5.9.027 (2010-12-01)
2860 * @public
2861 */
2862 public function SetDocInfoUnicode($unicode=true) {
2863 $this->docinfounicode = $unicode ? true : false;
2864 }
2865
2866 /**
2867 * Defines the title of the document.
2868 * @param $title (string) The title.
2869 * @public
2870 * @since 1.2
2871 * @see SetAuthor(), SetCreator(), SetKeywords(), SetSubject()
2872 */
2873 public function SetTitle($title) {
2874 $this->title = $title;
2875 }
2876
2877 /**
2878 * Defines the subject of the document.
2879 * @param $subject (string) The subject.
2880 * @public
2881 * @since 1.2
2882 * @see SetAuthor(), SetCreator(), SetKeywords(), SetTitle()
2883 */
2884 public function SetSubject($subject) {
2885 $this->subject = $subject;
2886 }
2887
2888 /**
2889 * Defines the author of the document.
2890 * @param $author (string) The name of the author.
2891 * @public
2892 * @since 1.2
2893 * @see SetCreator(), SetKeywords(), SetSubject(), SetTitle()
2894 */
2895 public function SetAuthor($author) {
2896 $this->author = $author;
2897 }
2898
2899 /**
2900 * Associates keywords with the document, generally in the form 'keyword1 keyword2 ...'.
2901 * @param $keywords (string) The list of keywords.
2902 * @public
2903 * @since 1.2
2904 * @see SetAuthor(), SetCreator(), SetSubject(), SetTitle()
2905 */
2906 public function SetKeywords($keywords) {
2907 $this->keywords = $keywords;
2908 }
2909
2910 /**
2911 * Defines the creator of the document. This is typically the name of the application that generates the PDF.
2912 * @param $creator (string) The name of the creator.
2913 * @public
2914 * @since 1.2
2915 * @see SetAuthor(), SetKeywords(), SetSubject(), SetTitle()
2916 */
2917 public function SetCreator($creator) {
2918 $this->creator = $creator;
2919 }
2920
2921 /**
2922 * Throw an exception or print an error message and die if the K_TCPDF_PARSER_THROW_EXCEPTION_ERROR constant is set to true.
2923 * @param $msg (string) The error message
2924 * @public
2925 * @since 1.0
2926 */
2927 public function Error($msg) {
2928 // unset all class variables
2929 $this->_destroy(true);
2930 throw new Exception('TCPDF ERROR: '.$msg);
2931 /*
2932
2933 I had problems with the constants for some reason, so here we force
2934
2935 $this->_destroy(true);
2936 if (defined('K_TCPDF_THROW_EXCEPTION_ERROR') AND !K_TCPDF_THROW_EXCEPTION_ERROR) {
2937 die('<strong>TCPDF ERROR: </strong>'.$msg);
2938 } else {
2939 throw new Exception('TCPDF ERROR: '.$msg);
2940 }*/
2941 }
2942
2943 /**
2944 * This method begins the generation of the PDF document.
2945 * It is not necessary to call it explicitly because AddPage() does it automatically.
2946 * Note: no page is created by this method
2947 * @public
2948 * @since 1.0
2949 * @see AddPage(), Close()
2950 */
2951 public function Open() {
2952 $this->state = 1;
2953 }
2954
2955 /**
2956 * Terminates the PDF document.
2957 * It is not necessary to call this method explicitly because Output() does it automatically.
2958 * If the document contains no page, AddPage() is called to prevent from getting an invalid document.
2959 * @public
2960 * @since 1.0
2961 * @see Open(), Output()
2962 */
2963 public function Close() {
2964 if ($this->state == 3) {
2965 return;
2966 }
2967 if ($this->page == 0) {
2968 $this->AddPage();
2969 }
2970 $this->endLayer();
2971 if ($this->tcpdflink) {
2972 // save current graphic settings
2973 $gvars = $this->getGraphicVars();
2974 $this->setEqualColumns();
2975 $this->lastpage(true);
2976 $this->SetAutoPageBreak(false);
2977 $this->x = 0;
2978 $this->y = $this->h - (1 / $this->k);
2979 $this->lMargin = 0;
2980 $this->_outSaveGraphicsState();
2981 $font = defined('PDF_FONT_NAME_MAIN')?PDF_FONT_NAME_MAIN:'helvetica';
2982 $this->SetFont($font, '', 1);
2983 $this->setTextRenderingMode(0, false, false);
2984 $msg = "\x50\x6f\x77\x65\x72\x65\x64\x20\x62\x79\x20\x54\x43\x50\x44\x46\x20\x28\x77\x77\x77\x2e\x74\x63\x70\x64\x66\x2e\x6f\x72\x67\x29";
2985 $lnk = "\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x74\x63\x70\x64\x66\x2e\x6f\x72\x67";
2986 $this->Cell(0, 0, $msg, 0, 0, 'L', 0, $lnk, 0, false, 'D', 'B');
2987 $this->_outRestoreGraphicsState();
2988 // restore graphic settings
2989 $this->setGraphicVars($gvars);
2990 }
2991 // close page
2992 $this->endPage();
2993 // close document
2994 $this->_enddoc();
2995 // unset all class variables (except critical ones)
2996 $this->_destroy(false);
2997 }
2998
2999 /**
3000 * Move pointer at the specified document page and update page dimensions.
3001 * @param $pnum (int) page number (1 ... numpages)
3002 * @param $resetmargins (boolean) if true reset left, right, top margins and Y position.
3003 * @public
3004 * @since 2.1.000 (2008-01-07)
3005 * @see getPage(), lastpage(), getNumPages()
3006 */
3007 public function setPage($pnum, $resetmargins=false) {
3008 if (($pnum == $this->page) AND ($this->state == 2)) {
3009 return;
3010 }
3011 if (($pnum > 0) AND ($pnum <= $this->numpages)) {
3012 $this->state = 2;
3013 // save current graphic settings
3014 //$gvars = $this->getGraphicVars();
3015 $oldpage = $this->page;
3016 $this->page = $pnum;
3017 $this->wPt = $this->pagedim[$this->page]['w'];
3018 $this->hPt = $this->pagedim[$this->page]['h'];
3019 $this->w = $this->pagedim[$this->page]['wk'];
3020 $this->h = $this->pagedim[$this->page]['hk'];
3021 $this->tMargin = $this->pagedim[$this->page]['tm'];
3022 $this->bMargin = $this->pagedim[$this->page]['bm'];
3023 $this->original_lMargin = $this->pagedim[$this->page]['olm'];
3024 $this->original_rMargin = $this->pagedim[$this->page]['orm'];
3025 $this->AutoPageBreak = $this->pagedim[$this->page]['pb'];
3026 $this->CurOrientation = $this->pagedim[$this->page]['or'];
3027 $this->SetAutoPageBreak($this->AutoPageBreak, $this->bMargin);
3028 // restore graphic settings
3029 //$this->setGraphicVars($gvars);
3030 if ($resetmargins) {
3031 $this->lMargin = $this->pagedim[$this->page]['olm'];
3032 $this->rMargin = $this->pagedim[$this->page]['orm'];
3033 $this->SetY($this->tMargin);
3034 } else {
3035 // account for booklet mode
3036 if ($this->pagedim[$this->page]['olm'] != $this->pagedim[$oldpage]['olm']) {
3037 $deltam = $this->pagedim[$this->page]['olm'] - $this->pagedim[$this->page]['orm'];
3038 $this->lMargin += $deltam;
3039 $this->rMargin -= $deltam;
3040 }
3041 }
3042 } else {
3043 $this->Error('Wrong page number on setPage() function: '.$pnum);
3044 }
3045 }
3046
3047 /**
3048 * Reset pointer to the last document page.
3049 * @param $resetmargins (boolean) if true reset left, right, top margins and Y position.
3050 * @public
3051 * @since 2.0.000 (2008-01-04)
3052 * @see setPage(), getPage(), getNumPages()
3053 */
3054 public function lastPage($resetmargins=false) {
3055 $this->setPage($this->getNumPages(), $resetmargins);
3056 }
3057
3058 /**
3059 * Get current document page number.
3060 * @return int page number
3061 * @public
3062 * @since 2.1.000 (2008-01-07)
3063 * @see setPage(), lastpage(), getNumPages()
3064 */
3065 public function getPage() {
3066 return $this->page;
3067 }
3068
3069 /**
3070 * Get the total number of insered pages.
3071 * @return int number of pages
3072 * @public
3073 * @since 2.1.000 (2008-01-07)
3074 * @see setPage(), getPage(), lastpage()
3075 */
3076 public function getNumPages() {
3077 return $this->numpages;
3078 }
3079
3080 /**
3081 * Adds a new TOC (Table Of Content) page to the document.
3082 * @param $orientation (string) page orientation.
3083 * @param $format (mixed) The format used for pages. It can be either: one of the string values specified at getPageSizeFromFormat() or an array of parameters specified at setPageFormat().
3084 * @param $keepmargins (boolean) if true overwrites the default page margins with the current margins
3085 * @public
3086 * @since 5.0.001 (2010-05-06)
3087 * @see AddPage(), startPage(), endPage(), endTOCPage()
3088 */
3089 public function addTOCPage($orientation='', $format='', $keepmargins=false) {
3090 $this->AddPage($orientation, $format, $keepmargins, true);
3091 }
3092
3093 /**
3094 * Terminate the current TOC (Table Of Content) page
3095 * @public
3096 * @since 5.0.001 (2010-05-06)
3097 * @see AddPage(), startPage(), endPage(), addTOCPage()
3098 */
3099 public function endTOCPage() {
3100 $this->endPage(true);
3101 }
3102
3103 /**
3104 * Adds a new page to the document. If a page is already present, the Footer() method is called first to output the footer (if enabled). Then the page is added, the current position set to the top-left corner according to the left and top margins (or top-right if in RTL mode), and Header() is called to display the header (if enabled).
3105 * The origin of the coordinate system is at the top-left corner (or top-right for RTL) and increasing ordinates go downwards.
3106 * @param $orientation (string) page orientation. Possible values are (case insensitive):<ul><li>P or PORTRAIT (default)</li><li>L or LANDSCAPE</li></ul>
3107 * @param $format (mixed) The format used for pages. It can be either: one of the string values specified at getPageSizeFromFormat() or an array of parameters specified at setPageFormat().
3108 * @param $keepmargins (boolean) if true overwrites the default page margins with the current margins
3109 * @param $tocpage (boolean) if true set the tocpage state to true (the added page will be used to display Table Of Content).
3110 * @public
3111 * @since 1.0
3112 * @see startPage(), endPage(), addTOCPage(), endTOCPage(), getPageSizeFromFormat(), setPageFormat()
3113 */
3114 public function AddPage($orientation='', $format='', $keepmargins=false, $tocpage=false) {
3115 if ($this->inxobj) {
3116 // we are inside an XObject template
3117 return;
3118 }
3119 if (!isset($this->original_lMargin) OR $keepmargins) {
3120 $this->original_lMargin = $this->lMargin;
3121 }
3122 if (!isset($this->original_rMargin) OR $keepmargins) {
3123 $this->original_rMargin = $this->rMargin;
3124 }
3125 // terminate previous page
3126 $this->endPage();
3127 // start new page
3128 $this->startPage($orientation, $format, $tocpage);
3129 }
3130
3131 /**
3132 * Terminate the current page
3133 * @param $tocpage (boolean) if true set the tocpage state to false (end the page used to display Table Of Content).
3134 * @public
3135 * @since 4.2.010 (2008-11-14)
3136 * @see AddPage(), startPage(), addTOCPage(), endTOCPage()
3137 */
3138 public function endPage($tocpage=false) {
3139 // check if page is already closed
3140 if (($this->page == 0) OR ($this->numpages > $this->page) OR (!$this->pageopen[$this->page])) {
3141 return;
3142 }
3143 // print page footer
3144 $this->setFooter();
3145 // close page
3146 $this->_endpage();
3147 // mark page as closed
3148 $this->pageopen[$this->page] = false;
3149 if ($tocpage) {
3150 $this->tocpage = false;
3151 }
3152 }
3153
3154 /**
3155 * Starts a new page to the document. The page must be closed using the endPage() function.
3156 * The origin of the coordinate system is at the top-left corner and increasing ordinates go downwards.
3157 * @param $orientation (string) page orientation. Possible values are (case insensitive):<ul><li>P or PORTRAIT (default)</li><li>L or LANDSCAPE</li></ul>
3158 * @param $format (mixed) The format used for pages. It can be either: one of the string values specified at getPageSizeFromFormat() or an array of parameters specified at setPageFormat().
3159 * @param $tocpage (boolean) if true the page is designated to contain the Table-Of-Content.
3160 * @since 4.2.010 (2008-11-14)
3161 * @see AddPage(), endPage(), addTOCPage(), endTOCPage(), getPageSizeFromFormat(), setPageFormat()
3162 * @public
3163 */
3164 public function startPage($orientation='', $format='', $tocpage=false) {
3165 if ($tocpage) {
3166 $this->tocpage = true;
3167 }
3168 // move page numbers of documents to be attached
3169 if ($this->tocpage) {
3170 // move reference to unexistent pages (used for page attachments)
3171 // adjust outlines
3172 $tmpoutlines = $this->outlines;
3173 foreach ($tmpoutlines as $key => $outline) {
3174 if (!$outline['f'] AND ($outline['p'] > $this->numpages)) {
3175 $this->outlines[$key]['p'] = ($outline['p'] + 1);
3176 }
3177 }
3178 // adjust dests
3179 $tmpdests = $this->dests;
3180 foreach ($tmpdests as $key => $dest) {
3181 if (!$dest['f'] AND ($dest['p'] > $this->numpages)) {
3182 $this->dests[$key]['p'] = ($dest['p'] + 1);
3183 }
3184 }
3185 // adjust links
3186 $tmplinks = $this->links;
3187 foreach ($tmplinks as $key => $link) {
3188 if (!$link['f'] AND ($link['p'] > $this->numpages)) {
3189 $this->links[$key]['p'] = ($link['p'] + 1);
3190 }
3191 }
3192 }
3193 if ($this->numpages > $this->page) {
3194 // this page has been already added
3195 $this->setPage($this->page + 1);
3196 $this->SetY($this->tMargin);
3197 return;
3198 }
3199 // start a new page
3200 if ($this->state == 0) {
3201 $this->Open();
3202 }
3203 ++$this->numpages;
3204 $this->swapMargins($this->booklet);
3205 // save current graphic settings
3206 $gvars = $this->getGraphicVars();
3207 // start new page
3208 $this->_beginpage($orientation, $format);
3209 // mark page as open
3210 $this->pageopen[$this->page] = true;
3211 // restore graphic settings
3212 $this->setGraphicVars($gvars);
3213 // mark this point
3214 $this->setPageMark();
3215 // print page header
3216 $this->setHeader();
3217 // restore graphic settings
3218 $this->setGraphicVars($gvars);
3219 // mark this point
3220 $this->setPageMark();
3221 // print table header (if any)
3222 $this->setTableHeader();
3223 // set mark for empty page check
3224 $this->emptypagemrk[$this->page]= $this->pagelen[$this->page];
3225 }
3226
3227 /**
3228 * Set start-writing mark on current page stream used to put borders and fills.
3229 * Borders and fills are always created after content and inserted on the position marked by this method.
3230 * This function must be called after calling Image() function for a background image.
3231 * Background images must be always inserted before calling Multicell() or WriteHTMLCell() or WriteHTML() functions.
3232 * @public
3233 * @since 4.0.016 (2008-07-30)
3234 */
3235 public function setPageMark() {
3236 $this->intmrk[$this->page] = $this->pagelen[$this->page];
3237 $this->bordermrk[$this->page] = $this->intmrk[$this->page];
3238 $this->setContentMark();
3239 }
3240
3241 /**
3242 * Set start-writing mark on selected page.
3243 * Borders and fills are always created after content and inserted on the position marked by this method.
3244 * @param $page (int) page number (default is the current page)
3245 * @protected
3246 * @since 4.6.021 (2009-07-20)
3247 */
3248 protected function setContentMark($page=0) {
3249 if ($page <= 0) {
3250 $page = $this->page;
3251 }
3252 if (isset($this->footerlen[$page])) {
3253 $this->cntmrk[$page] = $this->pagelen[$page] - $this->footerlen[$page];
3254 } else {
3255 $this->cntmrk[$page] = $this->pagelen[$page];
3256 }
3257 }
3258
3259 /**
3260 * Set header data.
3261 * @param $ln (string) header image logo
3262 * @param $lw (string) header image logo width in mm
3263 * @param $ht (string) string to print as title on document header
3264 * @param $hs (string) string to print on document header
3265 * @param $tc (array) RGB array color for text.
3266 * @param $lc (array) RGB array color for line.
3267 * @public
3268 */
3269 public function setHeaderData($ln='', $lw=0, $ht='', $hs='', $tc=array(0,0,0), $lc=array(0,0,0)) {
3270 $this->header_logo = $ln;
3271 $this->header_logo_width = $lw;
3272 $this->header_title = $ht;
3273 $this->header_string = $hs;
3274 $this->header_text_color = $tc;
3275 $this->header_line_color = $lc;
3276 }
3277
3278 /**
3279 * Set footer data.
3280 * @param $tc (array) RGB array color for text.
3281 * @param $lc (array) RGB array color for line.
3282 * @public
3283 */
3284 public function setFooterData($tc=array(0,0,0), $lc=array(0,0,0)) {
3285 $this->footer_text_color = $tc;
3286 $this->footer_line_color = $lc;
3287 }
3288
3289 /**
3290 * Returns header data:
3291 * <ul><li>$ret['logo'] = logo image</li><li>$ret['logo_width'] = width of the image logo in user units</li><li>$ret['title'] = header title</li><li>$ret['string'] = header description string</li></ul>
3292 * @return array()
3293 * @public
3294 * @since 4.0.012 (2008-07-24)
3295 */
3296 public function getHeaderData() {
3297 $ret = array();
3298 $ret['logo'] = $this->header_logo;
3299 $ret['logo_width'] = $this->header_logo_width;
3300 $ret['title'] = $this->header_title;
3301 $ret['string'] = $this->header_string;
3302 $ret['text_color'] = $this->header_text_color;
3303 $ret['line_color'] = $this->header_line_color;
3304 return $ret;
3305 }
3306
3307 /**
3308 * Set header margin.
3309 * (minimum distance between header and top page margin)
3310 * @param $hm (int) distance in user units
3311 * @public
3312 */
3313 public function setHeaderMargin($hm=10) {
3314 $this->header_margin = $hm;
3315 }
3316
3317 /**
3318 * Returns header margin in user units.
3319 * @return float
3320 * @since 4.0.012 (2008-07-24)
3321 * @public
3322 */
3323 public function getHeaderMargin() {
3324 return $this->header_margin;
3325 }
3326
3327 /**
3328 * Set footer margin.
3329 * (minimum distance between footer and bottom page margin)
3330 * @param $fm (int) distance in user units
3331 * @public
3332 */
3333 public function setFooterMargin($fm=10) {
3334 $this->footer_margin = $fm;
3335 }
3336
3337 /**
3338 * Returns footer margin in user units.
3339 * @return float
3340 * @since 4.0.012 (2008-07-24)
3341 * @public
3342 */
3343 public function getFooterMargin() {
3344 return $this->footer_margin;
3345 }
3346 /**
3347 * Set a flag to print page header.
3348 * @param $val (boolean) set to true to print the page header (default), false otherwise.
3349 * @public
3350 */
3351 public function setPrintHeader($val=true) {
3352 $this->print_header = $val ? true : false;
3353 }
3354
3355 /**
3356 * Set a flag to print page footer.
3357 * @param $val (boolean) set to true to print the page footer (default), false otherwise.
3358 * @public
3359 */
3360 public function setPrintFooter($val=true) {
3361 $this->print_footer = $val ? true : false;
3362 }
3363
3364 /**
3365 * Return the right-bottom (or left-bottom for RTL) corner X coordinate of last inserted image
3366 * @return float
3367 * @public
3368 */
3369 public function getImageRBX() {
3370 return $this->img_rb_x;
3371 }
3372
3373 /**
3374 * Return the right-bottom (or left-bottom for RTL) corner Y coordinate of last inserted image
3375 * @return float
3376 * @public
3377 */
3378 public function getImageRBY() {
3379 return $this->img_rb_y;
3380 }
3381
3382 /**
3383 * Reset the xobject template used by Header() method.
3384 * @public
3385 */
3386 public function resetHeaderTemplate() {
3387 $this->header_xobjid = false;
3388 }
3389
3390 /**
3391 * Set a flag to automatically reset the xobject template used by Header() method at each page.
3392 * @param $val (boolean) set to true to reset Header xobject template at each page, false otherwise.
3393 * @public
3394 */
3395 public function setHeaderTemplateAutoreset($val=true) {
3396 $this->header_xobj_autoreset = $val ? true : false;
3397 }
3398
3399 /**
3400 * This method is used to render the page header.
3401 * It is automatically called by AddPage() and could be overwritten in your own inherited class.
3402 * @public
3403 */
3404 public function Header() {
3405 if ($this->header_xobjid === false) {
3406 // start a new XObject Template
3407 $this->header_xobjid = $this->startTemplate($this->w, $this->tMargin);
3408 $headerfont = $this->getHeaderFont();
3409 $headerdata = $this->getHeaderData();
3410 $this->y = $this->header_margin;
3411 if ($this->rtl) {
3412 $this->x = $this->w - $this->original_rMargin;
3413 } else {
3414 $this->x = $this->original_lMargin;
3415 }
3416 if (($headerdata['logo']) AND ($headerdata['logo'] != K_BLANK_IMAGE)) {
3417 $imgtype = TCPDF_IMAGES::getImageFileType(K_PATH_IMAGES.$headerdata['logo']);
3418 if (($imgtype == 'eps') OR ($imgtype == 'ai')) {
3419 $this->ImageEps(K_PATH_IMAGES.$headerdata['logo'], '', '', $headerdata['logo_width']);
3420 } elseif ($imgtype == 'svg') {
3421 $this->ImageSVG(K_PATH_IMAGES.$headerdata['logo'], '', '', $headerdata['logo_width']);
3422 } else {
3423 $this->Image(K_PATH_IMAGES.$headerdata['logo'], '', '', $headerdata['logo_width']);
3424 }
3425 $imgy = $this->getImageRBY();
3426 } else {
3427 $imgy = $this->y;
3428 }
3429 $cell_height = $this->getCellHeight($headerfont[2] / $this->k);
3430 // set starting margin for text data cell
3431 if ($this->getRTL()) {
3432 $header_x = $this->original_rMargin + ($headerdata['logo_width'] * 1.1);
3433 } else {
3434 $header_x = $this->original_lMargin + ($headerdata['logo_width'] * 1.1);
3435 }
3436 $cw = $this->w - $this->original_lMargin - $this->original_rMargin - ($headerdata['logo_width'] * 1.1);
3437 $this->SetTextColorArray($this->header_text_color);
3438 // header title
3439 $this->SetFont($headerfont[0], 'B', $headerfont[2] + 1);
3440 $this->SetX($header_x);
3441 $this->Cell($cw, $cell_height, $headerdata['title'], 0, 1, '', 0, '', 0);
3442 // header string
3443 $this->SetFont($headerfont[0], $headerfont[1], $headerfont[2]);
3444 $this->SetX($header_x);
3445 $this->MultiCell($cw, $cell_height, $headerdata['string'], 0, '', 0, 1, '', '', true, 0, false, true, 0, 'T', false);
3446 // print an ending header line
3447 $this->SetLineStyle(array('width' => 0.85 / $this->k, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => $headerdata['line_color']));
3448 $this->SetY((2.835 / $this->k) + max($imgy, $this->y));
3449 if ($this->rtl) {
3450 $this->SetX($this->original_rMargin);
3451 } else {
3452 $this->SetX($this->original_lMargin);
3453 }
3454 $this->Cell(($this->w - $this->original_lMargin - $this->original_rMargin), 0, '', 'T', 0, 'C');
3455 $this->endTemplate();
3456 }
3457 // print header template
3458 $x = 0;
3459 $dx = 0;
3460 if (!$this->header_xobj_autoreset AND $this->booklet AND (($this->page % 2) == 0)) {
3461 // adjust margins for booklet mode
3462 $dx = ($this->original_lMargin - $this->original_rMargin);
3463 }
3464 if ($this->rtl) {
3465 $x = $this->w + $dx;
3466 } else {
3467 $x = 0 + $dx;
3468 }
3469 $this->printTemplate($this->header_xobjid, $x, 0, 0, 0, '', '', false);
3470 if ($this->header_xobj_autoreset) {
3471 // reset header xobject template at each page
3472 $this->header_xobjid = false;
3473 }
3474 }
3475
3476 /**
3477 * This method is used to render the page footer.
3478 * It is automatically called by AddPage() and could be overwritten in your own inherited class.
3479 * @public
3480 */
3481 public function Footer() {
3482 $cur_y = $this->y;
3483 $this->SetTextColorArray($this->footer_text_color);
3484 //set style for cell border
3485 $line_width = (0.85 / $this->k);
3486 $this->SetLineStyle(array('width' => $line_width, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => $this->footer_line_color));
3487 //print document barcode
3488 $barcode = $this->getBarcode();
3489 if (!empty($barcode)) {
3490 $this->Ln($line_width);
3491 $barcode_width = round(($this->w - $this->original_lMargin - $this->original_rMargin) / 3);
3492 $style = array(
3493 'position' => $this->rtl?'R':'L',
3494 'align' => $this->rtl?'R':'L',
3495 'stretch' => false,
3496 'fitwidth' => true,
3497 'cellfitalign' => '',
3498 'border' => false,
3499 'padding' => 0,
3500 'fgcolor' => array(0,0,0),
3501 'bgcolor' => false,
3502 'text' => false
3503 );
3504 $this->write1DBarcode($barcode, 'C128', '', $cur_y + $line_width, '', (($this->footer_margin / 3) - $line_width), 0.3, $style, '');
3505 }
3506 $w_page = isset($this->l['w_page']) ? $this->l['w_page'].' ' : '';
3507 if (empty($this->pagegroups)) {
3508 $pagenumtxt = $w_page.$this->getAliasNumPage().' / '.$this->getAliasNbPages();
3509 } else {
3510 $pagenumtxt = $w_page.$this->getPageNumGroupAlias().' / '.$this->getPageGroupAlias();
3511 }
3512 $this->SetY($cur_y);
3513 //Print page number
3514 if ($this->getRTL()) {
3515 $this->SetX($this->original_rMargin);
3516 $this->Cell(0, 0, $pagenumtxt, 'T', 0, 'L');
3517 } else {
3518 $this->SetX($this->original_lMargin);
3519 $this->Cell(0, 0, $this->getAliasRightShift().$pagenumtxt, 'T', 0, 'R');
3520 }
3521 }
3522
3523 /**
3524 * This method is used to render the page header.
3525 * @protected
3526 * @since 4.0.012 (2008-07-24)
3527 */
3528 protected function setHeader() {
3529 if (!$this->print_header OR ($this->state != 2)) {
3530 return;
3531 }
3532 $this->InHeader = true;
3533 $this->setGraphicVars($this->default_graphic_vars);
3534 $temp_thead = $this->thead;
3535 $temp_theadMargins = $this->theadMargins;
3536 $lasth = $this->lasth;
3537 $newline = $this->newline;
3538 $this->_outSaveGraphicsState();
3539 $this->rMargin = $this->original_rMargin;
3540 $this->lMargin = $this->original_lMargin;
3541 $this->SetCellPadding(0);
3542 //set current position
3543 if ($this->rtl) {
3544 $this->SetXY($this->original_rMargin, $this->header_margin);
3545 } else {
3546 $this->SetXY($this->original_lMargin, $this->header_margin);
3547 }
3548 $this->SetFont($this->header_font[0], $this->header_font[1], $this->header_font[2]);
3549 $this->Header();
3550 //restore position
3551 if ($this->rtl) {
3552 $this->SetXY($this->original_rMargin, $this->tMargin);
3553 } else {
3554 $this->SetXY($this->original_lMargin, $this->tMargin);
3555 }
3556 $this->_outRestoreGraphicsState();
3557 $this->lasth = $lasth;
3558 $this->thead = $temp_thead;
3559 $this->theadMargins = $temp_theadMargins;
3560 $this->newline = $newline;
3561 $this->InHeader = false;
3562 }
3563
3564 /**
3565 * This method is used to render the page footer.
3566 * @protected
3567 * @since 4.0.012 (2008-07-24)
3568 */
3569 protected function setFooter() {
3570 if ($this->state != 2) {
3571 return;
3572 }
3573 $this->InFooter = true;
3574 // save current graphic settings
3575 $gvars = $this->getGraphicVars();
3576 // mark this point
3577 $this->footerpos[$this->page] = $this->pagelen[$this->page];
3578 $this->_out("\n");
3579 if ($this->print_footer) {
3580 $this->setGraphicVars($this->default_graphic_vars);
3581 $this->current_column = 0;
3582 $this->num_columns = 1;
3583 $temp_thead = $this->thead;
3584 $temp_theadMargins = $this->theadMargins;
3585 $lasth = $this->lasth;
3586 $this->_outSaveGraphicsState();
3587 $this->rMargin = $this->original_rMargin;
3588 $this->lMargin = $this->original_lMargin;
3589 $this->SetCellPadding(0);
3590 //set current position
3591 $footer_y = $this->h - $this->footer_margin;
3592 if ($this->rtl) {
3593 $this->SetXY($this->original_rMargin, $footer_y);
3594 } else {
3595 $this->SetXY($this->original_lMargin, $footer_y);
3596 }
3597 $this->SetFont($this->footer_font[0], $this->footer_font[1], $this->footer_font[2]);
3598 $this->Footer();
3599 //restore position
3600 if ($this->rtl) {
3601 $this->SetXY($this->original_rMargin, $this->tMargin);
3602 } else {
3603 $this->SetXY($this->original_lMargin, $this->tMargin);
3604 }
3605 $this->_outRestoreGraphicsState();
3606 $this->lasth = $lasth;
3607 $this->thead = $temp_thead;
3608 $this->theadMargins = $temp_theadMargins;
3609 }
3610 // restore graphic settings
3611 $this->setGraphicVars($gvars);
3612 $this->current_column = $gvars['current_column'];
3613 $this->num_columns = $gvars['num_columns'];
3614 // calculate footer length
3615 $this->footerlen[$this->page] = $this->pagelen[$this->page] - $this->footerpos[$this->page] + 1;
3616 $this->InFooter = false;
3617 }
3618
3619 /**
3620 * Check if we are on the page body (excluding page header and footer).
3621 * @return true if we are not in page header nor in page footer, false otherwise.
3622 * @protected
3623 * @since 5.9.091 (2011-06-15)
3624 */
3625 protected function inPageBody() {
3626 return (($this->InHeader === false) AND ($this->InFooter === false));
3627 }
3628
3629 /**
3630 * This method is used to render the table header on new page (if any).
3631 * @protected
3632 * @since 4.5.030 (2009-03-25)
3633 */
3634 protected function setTableHeader() {
3635 if ($this->num_columns > 1) {
3636 // multi column mode
3637 return;
3638 }
3639 if (isset($this->theadMargins['top'])) {
3640 // restore the original top-margin
3641 $this->tMargin = $this->theadMargins['top'];
3642 $this->pagedim[$this->page]['tm'] = $this->tMargin;
3643 $this->y = $this->tMargin;
3644 }
3645 if (!TCPDF_STATIC::empty_string($this->thead) AND (!$this->inthead)) {
3646 // set margins
3647 $prev_lMargin = $this->lMargin;
3648 $prev_rMargin = $this->rMargin;
3649 $prev_cell_padding = $this->cell_padding;
3650 $this->lMargin = $this->theadMargins['lmargin'] + ($this->pagedim[$this->page]['olm'] - $this->pagedim[$this->theadMargins['page']]['olm']);
3651 $this->rMargin = $this->theadMargins['rmargin'] + ($this->pagedim[$this->page]['orm'] - $this->pagedim[$this->theadMargins['page']]['orm']);
3652 $this->cell_padding = $this->theadMargins['cell_padding'];
3653 if ($this->rtl) {
3654 $this->x = $this->w - $this->rMargin;
3655 } else {
3656 $this->x = $this->lMargin;
3657 }
3658 // account for special "cell" mode
3659 if ($this->theadMargins['cell']) {
3660 if ($this->rtl) {
3661 $this->x -= $this->cell_padding['R'];
3662 } else {
3663 $this->x += $this->cell_padding['L'];
3664 }
3665 }
3666 $gvars = $this->getGraphicVars();
3667 if (!empty($this->theadMargins['gvars'])) {
3668 // set the correct graphic style
3669 $this->setGraphicVars($this->theadMargins['gvars']);
3670 $this->rMargin = $gvars['rMargin'];
3671 $this->lMargin = $gvars['lMargin'];
3672 }
3673 // print table header
3674 $this->writeHTML($this->thead, false, false, false, false, '');
3675 $this->setGraphicVars($gvars);
3676 // set new top margin to skip the table headers
3677 if (!isset($this->theadMargins['top'])) {
3678 $this->theadMargins['top'] = $this->tMargin;
3679 }
3680 // store end of header position
3681 if (!isset($this->columns[0]['th'])) {
3682 $this->columns[0]['th'] = array();
3683 }
3684 $this->columns[0]['th']['\''.$this->page.'\''] = $this->y;
3685 $this->tMargin = $this->y;
3686 $this->pagedim[$this->page]['tm'] = $this->tMargin;
3687 $this->lasth = 0;
3688 $this->lMargin = $prev_lMargin;
3689 $this->rMargin = $prev_rMargin;
3690 $this->cell_padding = $prev_cell_padding;
3691 }
3692 }
3693
3694 /**
3695 * Returns the current page number.
3696 * @return int page number
3697 * @public
3698 * @since 1.0
3699 * @see getAliasNbPages()
3700 */
3701 public function PageNo() {
3702 return $this->page;
3703 }
3704
3705 /**
3706 * Returns the array of spot colors.
3707 * @return (array) Spot colors array.
3708 * @public
3709 * @since 6.0.038 (2013-09-30)
3710 */
3711 public function getAllSpotColors() {
3712 return $this->spot_colors;
3713 }
3714
3715 /**
3716 * Defines a new spot color.
3717 * It can be expressed in RGB components or gray scale.
3718 * The method can be called before the first page is created and the value is retained from page to page.
3719 * @param $name (string) Full name of the spot color.
3720 * @param $c (float) Cyan color for CMYK. Value between 0 and 100.
3721 * @param $m (float) Magenta color for CMYK. Value between 0 and 100.
3722 * @param $y (float) Yellow color for CMYK. Value between 0 and 100.
3723 * @param $k (float) Key (Black) color for CMYK. Value between 0 and 100.
3724 * @public
3725 * @since 4.0.024 (2008-09-12)
3726 * @see SetDrawSpotColor(), SetFillSpotColor(), SetTextSpotColor()
3727 */
3728 public function AddSpotColor($name, $c, $m, $y, $k) {
3729 if (!isset($this->spot_colors[$name])) {
3730 $i = (1 + count($this->spot_colors));
3731 $this->spot_colors[$name] = array('C' => $c, 'M' => $m, 'Y' => $y, 'K' => $k, 'name' => $name, 'i' => $i);
3732 }
3733 }
3734
3735 /**
3736 * Set the spot color for the specified type ('draw', 'fill', 'text').
3737 * @param $type (string) Type of object affected by this color: ('draw', 'fill', 'text').
3738 * @param $name (string) Name of the spot color.
3739 * @param $tint (float) Intensity of the color (from 0 to 100 ; 100 = full intensity by default).
3740 * @return (string) PDF color command.
3741 * @public
3742 * @since 5.9.125 (2011-10-03)
3743 */
3744 public function setSpotColor($type, $name, $tint=100) {
3745 $spotcolor = TCPDF_COLORS::getSpotColor($name, $this->spot_colors);
3746 if ($spotcolor === false) {
3747 $this->Error('Undefined spot color: '.$name.', you must add it using the AddSpotColor() method.');
3748 }
3749 $tint = (max(0, min(100, $tint)) / 100);
3750 $pdfcolor = sprintf('/CS%d ', $this->spot_colors[$name]['i']);
3751 switch ($type) {
3752 case 'draw': {
3753 $pdfcolor .= sprintf('CS %F SCN', $tint);
3754 $this->DrawColor = $pdfcolor;
3755 $this->strokecolor = $spotcolor;
3756 break;
3757 }
3758 case 'fill': {
3759 $pdfcolor .= sprintf('cs %F scn', $tint);
3760 $this->FillColor = $pdfcolor;
3761 $this->bgcolor = $spotcolor;
3762 break;
3763 }
3764 case 'text': {
3765 $pdfcolor .= sprintf('cs %F scn', $tint);
3766 $this->TextColor = $pdfcolor;
3767 $this->fgcolor = $spotcolor;
3768 break;
3769 }
3770 }
3771 $this->ColorFlag = ($this->FillColor != $this->TextColor);
3772 if ($this->state == 2) {
3773 $this->_out($pdfcolor);
3774 }
3775 if ($this->inxobj) {
3776 // we are inside an XObject template
3777 $this->xobjects[$this->xobjid]['spot_colors'][$name] = $this->spot_colors[$name];
3778 }
3779 return $pdfcolor;
3780 }
3781
3782 /**
3783 * Defines the spot color used for all drawing operations (lines, rectangles and cell borders).
3784 * @param $name (string) Name of the spot color.
3785 * @param $tint (float) Intensity of the color (from 0 to 100 ; 100 = full intensity by default).
3786 * @public
3787 * @since 4.0.024 (2008-09-12)
3788 * @see AddSpotColor(), SetFillSpotColor(), SetTextSpotColor()
3789 */
3790 public function SetDrawSpotColor($name, $tint=100) {
3791 $this->setSpotColor('draw', $name, $tint);
3792 }
3793
3794 /**
3795 * Defines the spot color used for all filling operations (filled rectangles and cell backgrounds).
3796 * @param $name (string) Name of the spot color.
3797 * @param $tint (float) Intensity of the color (from 0 to 100 ; 100 = full intensity by default).
3798 * @public
3799 * @since 4.0.024 (2008-09-12)
3800 * @see AddSpotColor(), SetDrawSpotColor(), SetTextSpotColor()
3801 */
3802 public function SetFillSpotColor($name, $tint=100) {
3803 $this->setSpotColor('fill', $name, $tint);
3804 }
3805
3806 /**
3807 * Defines the spot color used for text.
3808 * @param $name (string) Name of the spot color.
3809 * @param $tint (int) Intensity of the color (from 0 to 100 ; 100 = full intensity by default).
3810 * @public
3811 * @since 4.0.024 (2008-09-12)
3812 * @see AddSpotColor(), SetDrawSpotColor(), SetFillSpotColor()
3813 */
3814 public function SetTextSpotColor($name, $tint=100) {
3815 $this->setSpotColor('text', $name, $tint);
3816 }
3817
3818 /**
3819 * Set the color array for the specified type ('draw', 'fill', 'text').
3820 * It can be expressed in RGB, CMYK or GRAY SCALE components.
3821 * The method can be called before the first page is created and the value is retained from page to page.
3822 * @param $type (string) Type of object affected by this color: ('draw', 'fill', 'text').
3823 * @param $color (array) Array of colors (1=gray, 3=RGB, 4=CMYK or 5=spotcolor=CMYK+name values).
3824 * @param $ret (boolean) If true do not send the PDF command.
3825 * @return (string) The PDF command or empty string.
3826 * @public
3827 * @since 3.1.000 (2008-06-11)
3828 */
3829 public function setColorArray($type, $color, $ret=false) {
3830 if (is_array($color)) {
3831 $color = array_values($color);
3832 // component: grey, RGB red or CMYK cyan
3833 $c = isset($color[0]) ? $color[0] : -1;
3834 // component: RGB green or CMYK magenta
3835 $m = isset($color[1]) ? $color[1] : -1;
3836 // component: RGB blue or CMYK yellow
3837 $y = isset($color[2]) ? $color[2] : -1;
3838 // component: CMYK black
3839 $k = isset($color[3]) ? $color[3] : -1;
3840 // color name
3841 $name = isset($color[4]) ? $color[4] : '';
3842 if ($c >= 0) {
3843 return $this->setColor($type, $c, $m, $y, $k, $ret, $name);
3844 }
3845 }
3846 return '';
3847 }
3848
3849 /**
3850 * Defines the color used for all drawing operations (lines, rectangles and cell borders).
3851 * It can be expressed in RGB, CMYK or GRAY SCALE components.
3852 * The method can be called before the first page is created and the value is retained from page to page.
3853 * @param $color (array) Array of colors (1, 3 or 4 values).
3854 * @param $ret (boolean) If true do not send the PDF command.
3855 * @return string the PDF command
3856 * @public
3857 * @since 3.1.000 (2008-06-11)
3858 * @see SetDrawColor()
3859 */
3860 public function SetDrawColorArray($color, $ret=false) {
3861 return $this->setColorArray('draw', $color, $ret);
3862 }
3863
3864 /**
3865 * Defines the color used for all filling operations (filled rectangles and cell backgrounds).
3866 * It can be expressed in RGB, CMYK or GRAY SCALE components.
3867 * The method can be called before the first page is created and the value is retained from page to page.
3868 * @param $color (array) Array of colors (1, 3 or 4 values).
3869 * @param $ret (boolean) If true do not send the PDF command.
3870 * @public
3871 * @since 3.1.000 (2008-6-11)
3872 * @see SetFillColor()
3873 */
3874 public function SetFillColorArray($color, $ret=false) {
3875 return $this->setColorArray('fill', $color, $ret);
3876 }
3877
3878 /**
3879 * Defines the color used for text. It can be expressed in RGB components or gray scale.
3880 * The method can be called before the first page is created and the value is retained from page to page.
3881 * @param $color (array) Array of colors (1, 3 or 4 values).
3882 * @param $ret (boolean) If true do not send the PDF command.
3883 * @public
3884 * @since 3.1.000 (2008-6-11)
3885 * @see SetFillColor()
3886 */
3887 public function SetTextColorArray($color, $ret=false) {
3888 return $this->setColorArray('text', $color, $ret);
3889 }
3890
3891 /**
3892 * Defines the color used by the specified type ('draw', 'fill', 'text').
3893 * @param $type (string) Type of object affected by this color: ('draw', 'fill', 'text').
3894 * @param $col1 (float) GRAY level for single color, or Red color for RGB (0-255), or CYAN color for CMYK (0-100).
3895 * @param $col2 (float) GREEN color for RGB (0-255), or MAGENTA color for CMYK (0-100).
3896 * @param $col3 (float) BLUE color for RGB (0-255), or YELLOW color for CMYK (0-100).
3897 * @param $col4 (float) KEY (BLACK) color for CMYK (0-100).
3898 * @param $ret (boolean) If true do not send the command.
3899 * @param $name (string) spot color name (if any)
3900 * @return (string) The PDF command or empty string.
3901 * @public
3902 * @since 5.9.125 (2011-10-03)
3903 */
3904 public function setColor($type, $col1=0, $col2=-1, $col3=-1, $col4=-1, $ret=false, $name='') {
3905 // set default values
3906 if (!is_numeric($col1)) {
3907 $col1 = 0;
3908 }
3909 if (!is_numeric($col2)) {
3910 $col2 = -1;
3911 }
3912 if (!is_numeric($col3)) {
3913 $col3 = -1;
3914 }
3915 if (!is_numeric($col4)) {
3916 $col4 = -1;
3917 }
3918 // set color by case
3919 $suffix = '';
3920 if (($col2 == -1) AND ($col3 == -1) AND ($col4 == -1)) {
3921 // Grey scale
3922 $col1 = max(0, min(255, $col1));
3923 $intcolor = array('G' => $col1);
3924 $pdfcolor = sprintf('%F ', ($col1 / 255));
3925 $suffix = 'g';
3926 } elseif ($col4 == -1) {
3927 // RGB
3928 $col1 = max(0, min(255, $col1));
3929 $col2 = max(0, min(255, $col2));
3930 $col3 = max(0, min(255, $col3));
3931 $intcolor = array('R' => $col1, 'G' => $col2, 'B' => $col3);
3932 $pdfcolor = sprintf('%F %F %F ', ($col1 / 255), ($col2 / 255), ($col3 / 255));
3933 $suffix = 'rg';
3934 } else {
3935 $col1 = max(0, min(100, $col1));
3936 $col2 = max(0, min(100, $col2));
3937 $col3 = max(0, min(100, $col3));
3938 $col4 = max(0, min(100, $col4));
3939 if (empty($name)) {
3940 // CMYK
3941 $intcolor = array('C' => $col1, 'M' => $col2, 'Y' => $col3, 'K' => $col4);
3942 $pdfcolor = sprintf('%F %F %F %F ', ($col1 / 100), ($col2 / 100), ($col3 / 100), ($col4 / 100));
3943 $suffix = 'k';
3944 } else {
3945 // SPOT COLOR
3946 $intcolor = array('C' => $col1, 'M' => $col2, 'Y' => $col3, 'K' => $col4, 'name' => $name);
3947 $this->AddSpotColor($name, $col1, $col2, $col3, $col4);
3948 $pdfcolor = $this->setSpotColor($type, $name, 100);
3949 }
3950 }
3951 switch ($type) {
3952 case 'draw': {
3953 $pdfcolor .= strtoupper($suffix);
3954 $this->DrawColor = $pdfcolor;
3955 $this->strokecolor = $intcolor;
3956 break;
3957 }
3958 case 'fill': {
3959 $pdfcolor .= $suffix;
3960 $this->FillColor = $pdfcolor;
3961 $this->bgcolor = $intcolor;
3962 break;
3963 }
3964 case 'text': {
3965 $pdfcolor .= $suffix;
3966 $this->TextColor = $pdfcolor;
3967 $this->fgcolor = $intcolor;
3968 break;
3969 }
3970 }
3971 $this->ColorFlag = ($this->FillColor != $this->TextColor);
3972 if (($type != 'text') AND ($this->state == 2)) {
3973 if (!$ret) {
3974 $this->_out($pdfcolor);
3975 }
3976 return $pdfcolor;
3977 }
3978 return '';
3979 }
3980
3981 /**
3982 * Defines the color used for all drawing operations (lines, rectangles and cell borders). It can be expressed in RGB components or gray scale. The method can be called before the first page is created and the value is retained from page to page.
3983 * @param $col1 (float) GRAY level for single color, or Red color for RGB (0-255), or CYAN color for CMYK (0-100).
3984 * @param $col2 (float) GREEN color for RGB (0-255), or MAGENTA color for CMYK (0-100).
3985 * @param $col3 (float) BLUE color for RGB (0-255), or YELLOW color for CMYK (0-100).
3986 * @param $col4 (float) KEY (BLACK) color for CMYK (0-100).
3987 * @param $ret (boolean) If true do not send the command.
3988 * @param $name (string) spot color name (if any)
3989 * @return string the PDF command
3990 * @public
3991 * @since 1.3
3992 * @see SetDrawColorArray(), SetFillColor(), SetTextColor(), Line(), Rect(), Cell(), MultiCell()
3993 */
3994 public function SetDrawColor($col1=0, $col2=-1, $col3=-1, $col4=-1, $ret=false, $name='') {
3995 return $this->setColor('draw', $col1, $col2, $col3, $col4, $ret, $name);
3996 }
3997
3998 /**
3999 * Defines the color used for all filling operations (filled rectangles and cell backgrounds). It can be expressed in RGB components or gray scale. The method can be called before the first page is created and the value is retained from page to page.
4000 * @param $col1 (float) GRAY level for single color, or Red color for RGB (0-255), or CYAN color for CMYK (0-100).
4001 * @param $col2 (float) GREEN color for RGB (0-255), or MAGENTA color for CMYK (0-100).
4002 * @param $col3 (float) BLUE color for RGB (0-255), or YELLOW color for CMYK (0-100).
4003 * @param $col4 (float) KEY (BLACK) color for CMYK (0-100).
4004 * @param $ret (boolean) If true do not send the command.
4005 * @param $name (string) Spot color name (if any).
4006 * @return (string) The PDF command.
4007 * @public
4008 * @since 1.3
4009 * @see SetFillColorArray(), SetDrawColor(), SetTextColor(), Rect(), Cell(), MultiCell()
4010 */
4011 public function SetFillColor($col1=0, $col2=-1, $col3=-1, $col4=-1, $ret=false, $name='') {
4012 return $this->setColor('fill', $col1, $col2, $col3, $col4, $ret, $name);
4013 }
4014
4015 /**
4016 * Defines the color used for text. It can be expressed in RGB components or gray scale. The method can be called before the first page is created and the value is retained from page to page.
4017 * @param $col1 (float) GRAY level for single color, or Red color for RGB (0-255), or CYAN color for CMYK (0-100).
4018 * @param $col2 (float) GREEN color for RGB (0-255), or MAGENTA color for CMYK (0-100).
4019 * @param $col3 (float) BLUE color for RGB (0-255), or YELLOW color for CMYK (0-100).
4020 * @param $col4 (float) KEY (BLACK) color for CMYK (0-100).
4021 * @param $ret (boolean) If true do not send the command.
4022 * @param $name (string) Spot color name (if any).
4023 * @return (string) Empty string.
4024 * @public
4025 * @since 1.3
4026 * @see SetTextColorArray(), SetDrawColor(), SetFillColor(), Text(), Cell(), MultiCell()
4027 */
4028 public function SetTextColor($col1=0, $col2=-1, $col3=-1, $col4=-1, $ret=false, $name='') {
4029 return $this->setColor('text', $col1, $col2, $col3, $col4, $ret, $name);
4030 }
4031
4032 /**
4033 * Returns the length of a string in user unit. A font must be selected.<br>
4034 * @param $s (string) The string whose length is to be computed
4035 * @param $fontname (string) Family font. It can be either a name defined by AddFont() or one of the standard families. It is also possible to pass an empty string, in that case, the current family is retained.
4036 * @param $fontstyle (string) Font style. Possible values are (case insensitive):<ul><li>empty string: regular</li><li>B: bold</li><li>I: italic</li><li>U: underline</li><li>D: line-through</li><li>O: overline</li></ul> or any combination. The default value is regular.
4037 * @param $fontsize (float) Font size in points. The default value is the current size.
4038 * @param $getarray (boolean) if true returns an array of characters widths, if false returns the total length.
4039 * @return mixed int total string length or array of characted widths
4040 * @author Nicola Asuni
4041 * @public
4042 * @since 1.2
4043 */
4044 public function GetStringWidth($s, $fontname='', $fontstyle='', $fontsize=0, $getarray=false) {
4045 return $this->GetArrStringWidth(TCPDF_FONTS::utf8Bidi(TCPDF_FONTS::UTF8StringToArray($s, $this->isunicode, $this->CurrentFont), $s, $this->tmprtl, $this->isunicode, $this->CurrentFont), $fontname, $fontstyle, $fontsize, $getarray);
4046 }
4047
4048 /**
4049 * Returns the string length of an array of chars in user unit or an array of characters widths. A font must be selected.<br>
4050 * @param $sa (string) The array of chars whose total length is to be computed
4051 * @param $fontname (string) Family font. It can be either a name defined by AddFont() or one of the standard families. It is also possible to pass an empty string, in that case, the current family is retained.
4052 * @param $fontstyle (string) Font style. Possible values are (case insensitive):<ul><li>empty string: regular</li><li>B: bold</li><li>I: italic</li><li>U: underline</li><li>D: line through</li><li>O: overline</li></ul> or any combination. The default value is regular.
4053 * @param $fontsize (float) Font size in points. The default value is the current size.
4054 * @param $getarray (boolean) if true returns an array of characters widths, if false returns the total length.
4055 * @return mixed int total string length or array of characted widths
4056 * @author Nicola Asuni
4057 * @public
4058 * @since 2.4.000 (2008-03-06)
4059 */
4060 public function GetArrStringWidth($sa, $fontname='', $fontstyle='', $fontsize=0, $getarray=false) {
4061 // store current values
4062 if (!TCPDF_STATIC::empty_string($fontname)) {
4063 $prev_FontFamily = $this->FontFamily;
4064 $prev_FontStyle = $this->FontStyle;
4065 $prev_FontSizePt = $this->FontSizePt;
4066 $this->SetFont($fontname, $fontstyle, $fontsize, '', 'default', false);
4067 }
4068 // convert UTF-8 array to Latin1 if required
4069 if ($this->isunicode AND (!$this->isUnicodeFont())) {
4070 $sa = TCPDF_FONTS::UTF8ArrToLatin1Arr($sa);
4071 }
4072 $w = 0; // total width
4073 $wa = array(); // array of characters widths
4074 foreach ($sa as $ck => $char) {
4075 // character width
4076 $cw = $this->GetCharWidth($char, isset($sa[($ck + 1)]));
4077 $wa[] = $cw;
4078 $w += $cw;
4079 }
4080 // restore previous values
4081 if (!TCPDF_STATIC::empty_string($fontname)) {
4082 $this->SetFont($prev_FontFamily, $prev_FontStyle, $prev_FontSizePt, '', 'default', false);
4083 }
4084 if ($getarray) {
4085 return $wa;
4086 }
4087 return $w;
4088 }
4089
4090 /**
4091 * Returns the length of the char in user unit for the current font considering current stretching and spacing (tracking).
4092 * @param $char (int) The char code whose length is to be returned
4093 * @param $notlast (boolean) If false ignore the font-spacing.
4094 * @return float char width
4095 * @author Nicola Asuni
4096 * @public
4097 * @since 2.4.000 (2008-03-06)
4098 */
4099 public function GetCharWidth($char, $notlast=true) {
4100 // get raw width
4101 $chw = $this->getRawCharWidth($char);
4102 if (($this->font_spacing < 0) OR (($this->font_spacing > 0) AND $notlast)) {
4103 // increase/decrease font spacing
4104 $chw += $this->font_spacing;
4105 }
4106 if ($this->font_stretching != 100) {
4107 // fixed stretching mode
4108 $chw *= ($this->font_stretching / 100);
4109 }
4110 return $chw;
4111 }
4112
4113 /**
4114 * Returns the length of the char in user unit for the current font.
4115 * @param $char (int) The char code whose length is to be returned
4116 * @return float char width
4117 * @author Nicola Asuni
4118 * @public
4119 * @since 5.9.000 (2010-09-28)
4120 */
4121 public function getRawCharWidth($char) {
4122 if ($char == 173) {
4123 // SHY character will not be printed
4124 return (0);
4125 }
4126 if (isset($this->CurrentFont['cw'][$char])) {
4127 $w = $this->CurrentFont['cw'][$char];
4128 } elseif (isset($this->CurrentFont['dw'])) {
4129 // default width
4130 $w = $this->CurrentFont['dw'];
4131 } elseif (isset($this->CurrentFont['cw'][32])) {
4132 // default width
4133 $w = $this->CurrentFont['cw'][32];
4134 } else {
4135 $w = 600;
4136 }
4137 return $this->getAbsFontMeasure($w);
4138 }
4139
4140 /**
4141 * Returns the numbero of characters in a string.
4142 * @param $s (string) The input string.
4143 * @return int number of characters
4144 * @public
4145 * @since 2.0.0001 (2008-01-07)
4146 */
4147 public function GetNumChars($s) {
4148 if ($this->isUnicodeFont()) {
4149 return count(TCPDF_FONTS::UTF8StringToArray($s, $this->isunicode, $this->CurrentFont));
4150 }
4151 return strlen($s);
4152 }
4153
4154 /**
4155 * Fill the list of available fonts ($this->fontlist).
4156 * @protected
4157 * @since 4.0.013 (2008-07-28)
4158 */
4159 protected function getFontsList() {
4160 if (($fontsdir = opendir(TCPDF_FONTS::_getfontpath())) !== false) {
4161 while (($file = readdir($fontsdir)) !== false) {
4162 if (substr($file, -4) == '.php') {
4163 array_push($this->fontlist, strtolower(basename($file, '.php')));
4164 }
4165 }
4166 closedir($fontsdir);
4167 }
4168 }
4169
4170 /**
4171 * Returns the unicode caracter specified by the value
4172 * @param $c (int) UTF-8 value
4173 * @return Returns the specified character.
4174 * @since 2.3.000 (2008-03-05)
4175 * @public
4176 * @deprecated
4177 */
4178 public function unichr($c) {
4179 return TCPDF_FONTS::unichr($c, $this->isunicode);
4180 }
4181
4182 /**
4183 * Convert and add the selected TrueType or Type1 font to the fonts folder (that must be writeable).
4184 * @param $fontfile (string) Font file (full path).
4185 * @param $fonttype (string) Font type. Leave empty for autodetect mode. Valid values are: TrueTypeUnicode, TrueType, Type1, CID0JP = CID-0 Japanese, CID0KR = CID-0 Korean, CID0CS = CID-0 Chinese Simplified, CID0CT = CID-0 Chinese Traditional.
4186 * @param $enc (string) Name of the encoding table to use. Leave empty for default mode. Omit this parameter for TrueType Unicode and symbolic fonts like Symbol or ZapfDingBats.
4187 * @param $flags (int) Unsigned 32-bit integer containing flags specifying various characteristics of the font (PDF32000:2008 - 9.8.2 Font Descriptor Flags): +1 for fixed font; +4 for symbol or +32 for non-symbol; +64 for italic. Fixed and Italic mode are generally autodetected so you have to set it to 32 = non-symbolic font (default) or 4 = symbolic font.
4188 * @param $outpath (string) Output path for generated font files (must be writeable by the web server). Leave empty for default font folder.
4189 * @param $platid (int) Platform ID for CMAP table to extract (when building a Unicode font for Windows this value should be 3, for Macintosh should be 1).
4190 * @param $encid (int) Encoding ID for CMAP table to extract (when building a Unicode font for Windows this value should be 1, for Macintosh should be 0). When Platform ID is 3, legal values for Encoding ID are: 0=Symbol, 1=Unicode, 2=ShiftJIS, 3=PRC, 4=Big5, 5=Wansung, 6=Johab, 7=Reserved, 8=Reserved, 9=Reserved, 10=UCS-4.
4191 * @param $addcbbox (boolean) If true includes the character bounding box information on the php font file.
4192 * @return (string) TCPDF font name.
4193 * @author Nicola Asuni
4194 * @since 5.9.123 (2010-09-30)
4195 * @public
4196 * @deprecated
4197 */
4198 public function addTTFfont($fontfile, $fonttype='', $enc='', $flags=32, $outpath='', $platid=3, $encid=1, $addcbbox=false) {
4199 return TCPDF_FONTS::addTTFfont($fontfile, $fonttype, $enc, $flags, $outpath, $platid, $encid, $addcbbox);
4200 }
4201
4202 /**
4203 * Imports a TrueType, Type1, core, or CID0 font and makes it available.
4204 * It is necessary to generate a font definition file first (read /fonts/utils/README.TXT).
4205 * The definition file (and the font file itself when embedding) must be present either in the current directory or in the one indicated by K_PATH_FONTS if the constant is defined. If it could not be found, the error "Could not include font definition file" is generated.
4206 * @param $family (string) Font family. The name can be chosen arbitrarily. If it is a standard family name, it will override the corresponding font.
4207 * @param $style (string) Font style. Possible values are (case insensitive):<ul><li>empty string: regular (default)</li><li>B: bold</li><li>I: italic</li><li>BI or IB: bold italic</li></ul>
4208 * @param $fontfile (string) The font definition file. By default, the name is built from the family and style, in lower case with no spaces.
4209 * @return array containing the font data, or false in case of error.
4210 * @param $subset (mixed) if true embedd only a subset of the font (stores only the information related to the used characters); if false embedd full font; if 'default' uses the default value set using setFontSubsetting(). This option is valid only for TrueTypeUnicode fonts. If you want to enable users to change the document, set this parameter to false. If you subset the font, the person who receives your PDF would need to have your same font in order to make changes to your PDF. The file size of the PDF would also be smaller because you are embedding only part of a font.
4211 * @public
4212 * @since 1.5
4213 * @see SetFont(), setFontSubsetting()
4214 */
4215 public function AddFont($family, $style='', $fontfile='', $subset='default') {
4216 if ($subset === 'default') {
4217 $subset = $this->font_subsetting;
4218 }
4219 if ($this->pdfa_mode) {
4220 $subset = false;
4221 }
4222 if (TCPDF_STATIC::empty_string($family)) {
4223 if (!TCPDF_STATIC::empty_string($this->FontFamily)) {
4224 $family = $this->FontFamily;
4225 } else {
4226 $this->Error('Empty font family');
4227 }
4228 }
4229 // move embedded styles on $style
4230 if (substr($family, -1) == 'I') {
4231 $style .= 'I';
4232 $family = substr($family, 0, -1);
4233 }
4234 if (substr($family, -1) == 'B') {
4235 $style .= 'B';
4236 $family = substr($family, 0, -1);
4237 }
4238 // normalize family name
4239 $family = strtolower($family);
4240 if ((!$this->isunicode) AND ($family == 'arial')) {
4241 $family = 'helvetica';
4242 }
4243 if (($family == 'symbol') OR ($family == 'zapfdingbats')) {
4244 $style = '';
4245 }
4246 if ($this->pdfa_mode AND (isset($this->CoreFonts[$family]))) {
4247 // all fonts must be embedded
4248 $family = 'pdfa'.$family;
4249 }
4250 $tempstyle = strtoupper($style);
4251 $style = '';
4252 // underline
4253 if (strpos($tempstyle, 'U') !== false) {
4254 $this->underline = true;
4255 } else {
4256 $this->underline = false;
4257 }
4258 // line-through (deleted)
4259 if (strpos($tempstyle, 'D') !== false) {
4260 $this->linethrough = true;
4261 } else {
4262 $this->linethrough = false;
4263 }
4264 // overline
4265 if (strpos($tempstyle, 'O') !== false) {
4266 $this->overline = true;
4267 } else {
4268 $this->overline = false;
4269 }
4270 // bold
4271 if (strpos($tempstyle, 'B') !== false) {
4272 $style .= 'B';
4273 }
4274 // oblique
4275 if (strpos($tempstyle, 'I') !== false) {
4276 $style .= 'I';
4277 }
4278 $bistyle = $style;
4279 $fontkey = $family.$style;
4280 $font_style = $style.($this->underline ? 'U' : '').($this->linethrough ? 'D' : '').($this->overline ? 'O' : '');
4281 $fontdata = array('fontkey' => $fontkey, 'family' => $family, 'style' => $font_style);
4282 // check if the font has been already added
4283 $fb = $this->getFontBuffer($fontkey);
4284 if ($fb !== false) {
4285 if ($this->inxobj) {
4286 // we are inside an XObject template
4287 $this->xobjects[$this->xobjid]['fonts'][$fontkey] = $fb['i'];
4288 }
4289 return $fontdata;
4290 }
4291 // get specified font directory (if any)
4292 $fontdir = false;
4293 if (!TCPDF_STATIC::empty_string($fontfile)) {
4294 $fontdir = dirname($fontfile);
4295 if (TCPDF_STATIC::empty_string($fontdir) OR ($fontdir == '.')) {
4296 $fontdir = '';
4297 } else {
4298 $fontdir .= '/';
4299 }
4300 }
4301 // true when the font style variation is missing
4302 $missing_style = false;
4303 // search and include font file
4304 if (TCPDF_STATIC::empty_string($fontfile) OR (!@file_exists($fontfile))) {
4305 // build a standard filenames for specified font
4306 $tmp_fontfile = str_replace(' ', '', $family).strtolower($style).'.php';
4307 $fontfile = TCPDF_FONTS::getFontFullPath($tmp_fontfile, $fontdir);
4308 if (TCPDF_STATIC::empty_string($fontfile)) {
4309 $missing_style = true;
4310 // try to remove the style part
4311 $tmp_fontfile = str_replace(' ', '', $family).'.php';
4312 $fontfile = TCPDF_FONTS::getFontFullPath($tmp_fontfile, $fontdir);
4313 }
4314 }
4315 // include font file
4316 if (!TCPDF_STATIC::empty_string($fontfile) AND (@file_exists($fontfile))) {
4317 include($fontfile);
4318 } else {
4319 $this->Error('Could not include font definition file: '.$family.'');
4320 }
4321 // check font parameters
4322 if ((!isset($type)) OR (!isset($cw))) {
4323 $this->Error('The font definition file has a bad format: '.$fontfile.'');
4324 }
4325 // SET default parameters
4326 if (!isset($file) OR TCPDF_STATIC::empty_string($file)) {
4327 $file = '';
4328 }
4329 if (!isset($enc) OR TCPDF_STATIC::empty_string($enc)) {
4330 $enc = '';
4331 }
4332 if (!isset($cidinfo) OR TCPDF_STATIC::empty_string($cidinfo)) {
4333 $cidinfo = array('Registry'=>'Adobe', 'Ordering'=>'Identity', 'Supplement'=>0);
4334 $cidinfo['uni2cid'] = array();
4335 }
4336 if (!isset($ctg) OR TCPDF_STATIC::empty_string($ctg)) {
4337 $ctg = '';
4338 }
4339 if (!isset($desc) OR TCPDF_STATIC::empty_string($desc)) {
4340 $desc = array();
4341 }
4342 if (!isset($up) OR TCPDF_STATIC::empty_string($up)) {
4343 $up = -100;
4344 }
4345 if (!isset($ut) OR TCPDF_STATIC::empty_string($ut)) {
4346 $ut = 50;
4347 }
4348 if (!isset($cw) OR TCPDF_STATIC::empty_string($cw)) {
4349 $cw = array();
4350 }
4351 if (!isset($dw) OR TCPDF_STATIC::empty_string($dw)) {
4352 // set default width
4353 if (isset($desc['MissingWidth']) AND ($desc['MissingWidth'] > 0)) {
4354 $dw = $desc['MissingWidth'];
4355 } elseif (isset($cw[32])) {
4356 $dw = $cw[32];
4357 } else {
4358 $dw = 600;
4359 }
4360 }
4361 ++$this->numfonts;
4362 if ($type == 'core') {
4363 $name = $this->CoreFonts[$fontkey];
4364 $subset = false;
4365 } elseif (($type == 'TrueType') OR ($type == 'Type1')) {
4366 $subset = false;
4367 } elseif ($type == 'TrueTypeUnicode') {
4368 $enc = 'Identity-H';
4369 } elseif ($type == 'cidfont0') {
4370 if ($this->pdfa_mode) {
4371 $this->Error('All fonts must be embedded in PDF/A mode!');
4372 }
4373 } else {
4374 $this->Error('Unknow font type: '.$type.'');
4375 }
4376 // set name if unset
4377 if (!isset($name) OR empty($name)) {
4378 $name = $fontkey;
4379 }
4380 // create artificial font style variations if missing (only works with non-embedded fonts)
4381 if (($type != 'core') AND $missing_style) {
4382 // style variations
4383 $styles = array('' => '', 'B' => ',Bold', 'I' => ',Italic', 'BI' => ',BoldItalic');
4384 $name .= $styles[$bistyle];
4385 // artificial bold
4386 if (strpos($bistyle, 'B') !== false) {
4387 if (isset($desc['StemV'])) {
4388 // from normal to bold
4389 $desc['StemV'] = round($desc['StemV'] * 1.75);
4390 } else {
4391 // bold
4392 $desc['StemV'] = 123;
4393 }
4394 }
4395 // artificial italic
4396 if (strpos($bistyle, 'I') !== false) {
4397 if (isset($desc['ItalicAngle'])) {
4398 $desc['ItalicAngle'] -= 11;
4399 } else {
4400 $desc['ItalicAngle'] = -11;
4401 }
4402 if (isset($desc['Flags'])) {
4403 $desc['Flags'] |= 64; //bit 7
4404 } else {
4405 $desc['Flags'] = 64;
4406 }
4407 }
4408 }
4409 // check if the array of characters bounding boxes is defined
4410 if (!isset($cbbox)) {
4411 $cbbox = array();
4412 }
4413 // initialize subsetchars
4414 $subsetchars = array_fill(0, 255, true);
4415 $this->setFontBuffer($fontkey, array('fontkey' => $fontkey, 'i' => $this->numfonts, 'type' => $type, 'name' => $name, 'desc' => $desc, 'up' => $up, 'ut' => $ut, 'cw' => $cw, 'cbbox' => $cbbox, 'dw' => $dw, 'enc' => $enc, 'cidinfo' => $cidinfo, 'file' => $file, 'ctg' => $ctg, 'subset' => $subset, 'subsetchars' => $subsetchars));
4416 if ($this->inxobj) {
4417 // we are inside an XObject template
4418 $this->xobjects[$this->xobjid]['fonts'][$fontkey] = $this->numfonts;
4419 }
4420 if (isset($diff) AND (!empty($diff))) {
4421 //Search existing encodings
4422 $d = 0;
4423 $nb = count($this->diffs);
4424 for ($i=1; $i <= $nb; ++$i) {
4425 if ($this->diffs[$i] == $diff) {
4426 $d = $i;
4427 break;
4428 }
4429 }
4430 if ($d == 0) {
4431 $d = $nb + 1;
4432 $this->diffs[$d] = $diff;
4433 }
4434 $this->setFontSubBuffer($fontkey, 'diff', $d);
4435 }
4436 if (!TCPDF_STATIC::empty_string($file)) {
4437 if (!isset($this->FontFiles[$file])) {
4438 if ((strcasecmp($type,'TrueType') == 0) OR (strcasecmp($type, 'TrueTypeUnicode') == 0)) {
4439 $this->FontFiles[$file] = array('length1' => $originalsize, 'fontdir' => $fontdir, 'subset' => $subset, 'fontkeys' => array($fontkey));
4440 } elseif ($type != 'core') {
4441 $this->FontFiles[$file] = array('length1' => $size1, 'length2' => $size2, 'fontdir' => $fontdir, 'subset' => $subset, 'fontkeys' => array($fontkey));
4442 }
4443 } else {
4444 // update fontkeys that are sharing this font file
4445 $this->FontFiles[$file]['subset'] = ($this->FontFiles[$file]['subset'] AND $subset);
4446 if (!in_array($fontkey, $this->FontFiles[$file]['fontkeys'])) {
4447 $this->FontFiles[$file]['fontkeys'][] = $fontkey;
4448 }
4449 }
4450 }
4451 return $fontdata;
4452 }
4453
4454 /**
4455 * Sets the font used to print character strings.
4456 * The font can be either a standard one or a font added via the AddFont() method. Standard fonts use Windows encoding cp1252 (Western Europe).
4457 * The method can be called before the first page is created and the font is retained from page to page.
4458 * If you just wish to change the current font size, it is simpler to call SetFontSize().
4459 * Note: for the standard fonts, the font metric files must be accessible. There are three possibilities for this:<ul><li>They are in the current directory (the one where the running script lies)</li><li>They are in one of the directories defined by the include_path parameter</li><li>They are in the directory defined by the K_PATH_FONTS constant</li></ul><br />
4460 * @param $family (string) Family font. It can be either a name defined by AddFont() or one of the standard Type1 families (case insensitive):<ul><li>times (Times-Roman)</li><li>timesb (Times-Bold)</li><li>timesi (Times-Italic)</li><li>timesbi (Times-BoldItalic)</li><li>helvetica (Helvetica)</li><li>helveticab (Helvetica-Bold)</li><li>helveticai (Helvetica-Oblique)</li><li>helveticabi (Helvetica-BoldOblique)</li><li>courier (Courier)</li><li>courierb (Courier-Bold)</li><li>courieri (Courier-Oblique)</li><li>courierbi (Courier-BoldOblique)</li><li>symbol (Symbol)</li><li>zapfdingbats (ZapfDingbats)</li></ul> It is also possible to pass an empty string. In that case, the current family is retained.
4461 * @param $style (string) Font style. Possible values are (case insensitive):<ul><li>empty string: regular</li><li>B: bold</li><li>I: italic</li><li>U: underline</li><li>D: line through</li><li>O: overline</li></ul> or any combination. The default value is regular. Bold and italic styles do not apply to Symbol and ZapfDingbats basic fonts or other fonts when not defined.
4462 * @param $size (float) Font size in points. The default value is the current size. If no size has been specified since the beginning of the document, the value taken is 12
4463 * @param $fontfile (string) The font definition file. By default, the name is built from the family and style, in lower case with no spaces.
4464 * @param $subset (mixed) if true embedd only a subset of the font (stores only the information related to the used characters); if false embedd full font; if 'default' uses the default value set using setFontSubsetting(). This option is valid only for TrueTypeUnicode fonts. If you want to enable users to change the document, set this parameter to false. If you subset the font, the person who receives your PDF would need to have your same font in order to make changes to your PDF. The file size of the PDF would also be smaller because you are embedding only part of a font.
4465 * @param $out (boolean) if true output the font size command, otherwise only set the font properties.
4466 * @author Nicola Asuni
4467 * @public
4468 * @since 1.0
4469 * @see AddFont(), SetFontSize()
4470 */
4471 public function SetFont($family, $style='', $size=null, $fontfile='', $subset='default', $out=true) {
4472 //Select a font; size given in points
4473 if ($size === null) {
4474 $size = $this->FontSizePt;
4475 }
4476 if ($size < 0) {
4477 $size = 0;
4478 }
4479 // try to add font (if not already added)
4480 $fontdata = $this->AddFont($family, $style, $fontfile, $subset);
4481 $this->FontFamily = $fontdata['family'];
4482 $this->FontStyle = $fontdata['style'];
4483 if (isset($this->CurrentFont['fontkey']) AND isset($this->CurrentFont['subsetchars'])) {
4484 // save subset chars of the previous font
4485 $this->setFontSubBuffer($this->CurrentFont['fontkey'], 'subsetchars', $this->CurrentFont['subsetchars']);
4486 }
4487 $this->CurrentFont = $this->getFontBuffer($fontdata['fontkey']);
4488 $this->SetFontSize($size, $out);
4489 }
4490
4491 /**
4492 * Defines the size of the current font.
4493 * @param $size (float) The font size in points.
4494 * @param $out (boolean) if true output the font size command, otherwise only set the font properties.
4495 * @public
4496 * @since 1.0
4497 * @see SetFont()
4498 */
4499 public function SetFontSize($size, $out=true) {
4500 // font size in points
4501 $this->FontSizePt = $size;
4502 // font size in user units
4503 $this->FontSize = $size / $this->k;
4504 // calculate some font metrics
4505 if (isset($this->CurrentFont['desc']['FontBBox'])) {
4506 $bbox = explode(' ', substr($this->CurrentFont['desc']['FontBBox'], 1, -1));
4507 $font_height = ((intval($bbox[3]) - intval($bbox[1])) * $size / 1000);
4508 } else {
4509 $font_height = $size * 1.219;
4510 }
4511 if (isset($this->CurrentFont['desc']['Ascent']) AND ($this->CurrentFont['desc']['Ascent'] > 0)) {
4512 $font_ascent = ($this->CurrentFont['desc']['Ascent'] * $size / 1000);
4513 }
4514 if (isset($this->CurrentFont['desc']['Descent']) AND ($this->CurrentFont['desc']['Descent'] <= 0)) {
4515 $font_descent = (- $this->CurrentFont['desc']['Descent'] * $size / 1000);
4516 }
4517 if (!isset($font_ascent) AND !isset($font_descent)) {
4518 // core font
4519 $font_ascent = 0.76 * $font_height;
4520 $font_descent = $font_height - $font_ascent;
4521 } elseif (!isset($font_descent)) {
4522 $font_descent = $font_height - $font_ascent;
4523 } elseif (!isset($font_ascent)) {
4524 $font_ascent = $font_height - $font_descent;
4525 }
4526 $this->FontAscent = ($font_ascent / $this->k);
4527 $this->FontDescent = ($font_descent / $this->k);
4528 if ($out AND ($this->page > 0) AND (isset($this->CurrentFont['i'])) AND ($this->state == 2)) {
4529 $this->_out(sprintf('BT /F%d %F Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
4530 }
4531 }
4532
4533 /**
4534 * Returns the bounding box of the current font in user units.
4535 * @return array
4536 * @public
4537 * @since 5.9.152 (2012-03-23)
4538 */
4539 public function getFontBBox() {
4540 $fbbox = array();
4541 if (isset($this->CurrentFont['desc']['FontBBox'])) {
4542 $tmpbbox = explode(' ', substr($this->CurrentFont['desc']['FontBBox'], 1, -1));
4543 $fbbox = array_map(array($this,'getAbsFontMeasure'), $tmpbbox);
4544 } else {
4545 // Find max width
4546 if (isset($this->CurrentFont['desc']['MaxWidth'])) {
4547 $maxw = $this->getAbsFontMeasure(intval($this->CurrentFont['desc']['MaxWidth']));
4548 } else {
4549 $maxw = 0;
4550 if (isset($this->CurrentFont['desc']['MissingWidth'])) {
4551 $maxw = max($maxw, $this->CurrentFont['desc']['MissingWidth']);
4552 }
4553 if (isset($this->CurrentFont['desc']['AvgWidth'])) {
4554 $maxw = max($maxw, $this->CurrentFont['desc']['AvgWidth']);
4555 }
4556 if (isset($this->CurrentFont['dw'])) {
4557 $maxw = max($maxw, $this->CurrentFont['dw']);
4558 }
4559 foreach ($this->CurrentFont['cw'] as $char => $w) {
4560 $maxw = max($maxw, $w);
4561 }
4562 if ($maxw == 0) {
4563 $maxw = 600;
4564 }
4565 $maxw = $this->getAbsFontMeasure($maxw);
4566 }
4567 $fbbox = array(0, (0 - $this->FontDescent), $maxw, $this->FontAscent);
4568 }
4569 return $fbbox;
4570 }
4571
4572 /**
4573 * Convert a relative font measure into absolute value.
4574 * @param $s (int) Font measure.
4575 * @return float Absolute measure.
4576 * @since 5.9.186 (2012-09-13)
4577 */
4578 public function getAbsFontMeasure($s) {
4579 return ($s * $this->FontSize / 1000);
4580 }
4581
4582 /**
4583 * Returns the glyph bounding box of the specified character in the current font in user units.
4584 * @param $char (int) Input character code.
4585 * @return mixed array(xMin, yMin, xMax, yMax) or FALSE if not defined.
4586 * @since 5.9.186 (2012-09-13)
4587 */
4588 public function getCharBBox($char) {
4589 if (isset($this->CurrentFont['cbbox'][$char])) {
4590 return array_map(array($this,'getAbsFontMeasure'), $this->CurrentFont['cbbox'][intval($char)]);
4591 }
4592 return false;
4593 }
4594
4595 /**
4596 * Return the font descent value
4597 * @param $font (string) font name
4598 * @param $style (string) font style
4599 * @param $size (float) The size (in points)
4600 * @return int font descent
4601 * @public
4602 * @author Nicola Asuni
4603 * @since 4.9.003 (2010-03-30)
4604 */
4605 public function getFontDescent($font, $style='', $size=0) {
4606 $fontdata = $this->AddFont($font, $style);
4607 $fontinfo = $this->getFontBuffer($fontdata['fontkey']);
4608 if (isset($fontinfo['desc']['Descent']) AND ($fontinfo['desc']['Descent'] <= 0)) {
4609 $descent = (- $fontinfo['desc']['Descent'] * $size / 1000);
4610 } else {
4611 $descent = (1.219 * 0.24 * $size);
4612 }
4613 return ($descent / $this->k);
4614 }
4615
4616 /**
4617 * Return the font ascent value.
4618 * @param $font (string) font name
4619 * @param $style (string) font style
4620 * @param $size (float) The size (in points)
4621 * @return int font ascent
4622 * @public
4623 * @author Nicola Asuni
4624 * @since 4.9.003 (2010-03-30)
4625 */
4626 public function getFontAscent($font, $style='', $size=0) {
4627 $fontdata = $this->AddFont($font, $style);
4628 $fontinfo = $this->getFontBuffer($fontdata['fontkey']);
4629 if (isset($fontinfo['desc']['Ascent']) AND ($fontinfo['desc']['Ascent'] > 0)) {
4630 $ascent = ($fontinfo['desc']['Ascent'] * $size / 1000);
4631 } else {
4632 $ascent = 1.219 * 0.76 * $size;
4633 }
4634 return ($ascent / $this->k);
4635 }
4636
4637 /**
4638 * Return true in the character is present in the specified font.
4639 * @param $char (mixed) Character to check (integer value or string)
4640 * @param $font (string) Font name (family name).
4641 * @param $style (string) Font style.
4642 * @return (boolean) true if the char is defined, false otherwise.
4643 * @public
4644 * @since 5.9.153 (2012-03-28)
4645 */
4646 public function isCharDefined($char, $font='', $style='') {
4647 if (is_string($char)) {
4648 // get character code
4649 $char = TCPDF_FONTS::UTF8StringToArray($char, $this->isunicode, $this->CurrentFont);
4650 $char = $char[0];
4651 }
4652 if (TCPDF_STATIC::empty_string($font)) {
4653 if (TCPDF_STATIC::empty_string($style)) {
4654 return (isset($this->CurrentFont['cw'][intval($char)]));
4655 }
4656 $font = $this->FontFamily;
4657 }
4658 $fontdata = $this->AddFont($font, $style);
4659 $fontinfo = $this->getFontBuffer($fontdata['fontkey']);
4660 return (isset($fontinfo['cw'][intval($char)]));
4661 }
4662
4663 /**
4664 * Replace missing font characters on selected font with specified substitutions.
4665 * @param $text (string) Text to process.
4666 * @param $font (string) Font name (family name).
4667 * @param $style (string) Font style.
4668 * @param $subs (array) Array of possible character substitutions. The key is the character to check (integer value) and the value is a single intege value or an array of possible substitutes.
4669 * @return (string) Processed text.
4670 * @public
4671 * @since 5.9.153 (2012-03-28)
4672 */
4673 public function replaceMissingChars($text, $font='', $style='', $subs=array()) {
4674 if (empty($subs)) {
4675 return $text;
4676 }
4677 if (TCPDF_STATIC::empty_string($font)) {
4678 $font = $this->FontFamily;
4679 }
4680 $fontdata = $this->AddFont($font, $style);
4681 $fontinfo = $this->getFontBuffer($fontdata['fontkey']);
4682 $uniarr = TCPDF_FONTS::UTF8StringToArray($text, $this->isunicode, $this->CurrentFont);
4683 foreach ($uniarr as $k => $chr) {
4684 if (!isset($fontinfo['cw'][$chr])) {
4685 // this character is missing on the selected font
4686 if (isset($subs[$chr])) {
4687 // we have available substitutions
4688 if (is_array($subs[$chr])) {
4689 foreach($subs[$chr] as $s) {
4690 if (isset($fontinfo['cw'][$s])) {
4691 $uniarr[$k] = $s;
4692 break;
4693 }
4694 }
4695 } elseif (isset($fontinfo['cw'][$subs[$chr]])) {
4696 $uniarr[$k] = $subs[$chr];
4697 }
4698 }
4699 }
4700 }
4701 return TCPDF_FONTS::UniArrSubString(TCPDF_FONTS::UTF8ArrayToUniArray($uniarr, $this->isunicode));
4702 }
4703
4704 /**
4705 * Defines the default monospaced font.
4706 * @param $font (string) Font name.
4707 * @public
4708 * @since 4.5.025
4709 */
4710 public function SetDefaultMonospacedFont($font) {
4711 $this->default_monospaced_font = $font;
4712 }
4713
4714 /**
4715 * Creates a new internal link and returns its identifier. An internal link is a clickable area which directs to another place within the document.<br />
4716 * The identifier can then be passed to Cell(), Write(), Image() or Link(). The destination is defined with SetLink().
4717 * @public
4718 * @since 1.5
4719 * @see Cell(), Write(), Image(), Link(), SetLink()
4720 */
4721 public function AddLink() {
4722 // create a new internal link
4723 $n = count($this->links) + 1;
4724 $this->links[$n] = array('p' => 0, 'y' => 0, 'f' => false);
4725 return $n;
4726 }
4727
4728 /**
4729 * Defines the page and position a link points to.
4730 * @param $link (int) The link identifier returned by AddLink()
4731 * @param $y (float) Ordinate of target position; -1 indicates the current position. The default value is 0 (top of page)
4732 * @param $page (int) Number of target page; -1 indicates the current page (default value). If you prefix a page number with the * character, then this page will not be changed when adding/deleting/moving pages.
4733 * @public
4734 * @since 1.5
4735 * @see AddLink()
4736 */
4737 public function SetLink($link, $y=0, $page=-1) {
4738 $fixed = false;
4739 if (!empty($page) AND ($page[0] == '*')) {
4740 $page = intval(substr($page, 1));
4741 // this page number will not be changed when moving/add/deleting pages
4742 $fixed = true;
4743 }
4744 if ($page < 0) {
4745 $page = $this->page;
4746 }
4747 if ($y == -1) {
4748 $y = $this->y;
4749 }
4750 $this->links[$link] = array('p' => $page, 'y' => $y, 'f' => $fixed);
4751 }
4752
4753 /**
4754 * Puts a link on a rectangular area of the page.
4755 * Text or image links are generally put via Cell(), Write() or Image(), but this method can be useful for instance to define a clickable area inside an image.
4756 * @param $x (float) Abscissa of the upper-left corner of the rectangle
4757 * @param $y (float) Ordinate of the upper-left corner of the rectangle
4758 * @param $w (float) Width of the rectangle
4759 * @param $h (float) Height of the rectangle
4760 * @param $link (mixed) URL or identifier returned by AddLink()
4761 * @param $spaces (int) number of spaces on the text to link
4762 * @public
4763 * @since 1.5
4764 * @see AddLink(), Annotation(), Cell(), Write(), Image()
4765 */
4766 public function Link($x, $y, $w, $h, $link, $spaces=0) {
4767 $this->Annotation($x, $y, $w, $h, $link, array('Subtype'=>'Link'), $spaces);
4768 }
4769
4770 /**
4771 * Puts a markup annotation on a rectangular area of the page.
4772 * !!!!THE ANNOTATION SUPPORT IS NOT YET FULLY IMPLEMENTED !!!!
4773 * @param $x (float) Abscissa of the upper-left corner of the rectangle
4774 * @param $y (float) Ordinate of the upper-left corner of the rectangle
4775 * @param $w (float) Width of the rectangle
4776 * @param $h (float) Height of the rectangle
4777 * @param $text (string) annotation text or alternate content
4778 * @param $opt (array) array of options (see section 8.4 of PDF reference 1.7).
4779 * @param $spaces (int) number of spaces on the text to link
4780 * @public
4781 * @since 4.0.018 (2008-08-06)
4782 */
4783 public function Annotation($x, $y, $w, $h, $text, $opt=array('Subtype'=>'Text'), $spaces=0) {
4784 if ($this->inxobj) {
4785 // store parameters for later use on template
4786 $this->xobjects[$this->xobjid]['annotations'][] = array('x' => $x, 'y' => $y, 'w' => $w, 'h' => $h, 'text' => $text, 'opt' => $opt, 'spaces' => $spaces);
4787 return;
4788 }
4789 if ($x === '') {
4790 $x = $this->x;
4791 }
4792 if ($y === '') {
4793 $y = $this->y;
4794 }
4795 // check page for no-write regions and adapt page margins if necessary
4796 list($x, $y) = $this->checkPageRegions($h, $x, $y);
4797 // recalculate coordinates to account for graphic transformations
4798 if (isset($this->transfmatrix) AND !empty($this->transfmatrix)) {
4799 for ($i=$this->transfmatrix_key; $i > 0; --$i) {
4800 $maxid = count($this->transfmatrix[$i]) - 1;
4801 for ($j=$maxid; $j >= 0; --$j) {
4802 $ctm = $this->transfmatrix[$i][$j];
4803 if (isset($ctm['a'])) {
4804 $x = $x * $this->k;
4805 $y = ($this->h - $y) * $this->k;
4806 $w = $w * $this->k;
4807 $h = $h * $this->k;
4808 // top left
4809 $xt = $x;
4810 $yt = $y;
4811 $x1 = ($ctm['a'] * $xt) + ($ctm['c'] * $yt) + $ctm['e'];
4812 $y1 = ($ctm['b'] * $xt) + ($ctm['d'] * $yt) + $ctm['f'];
4813 // top right
4814 $xt = $x + $w;
4815 $yt = $y;
4816 $x2 = ($ctm['a'] * $xt) + ($ctm['c'] * $yt) + $ctm['e'];
4817 $y2 = ($ctm['b'] * $xt) + ($ctm['d'] * $yt) + $ctm['f'];
4818 // bottom left
4819 $xt = $x;
4820 $yt = $y - $h;
4821 $x3 = ($ctm['a'] * $xt) + ($ctm['c'] * $yt) + $ctm['e'];
4822 $y3 = ($ctm['b'] * $xt) + ($ctm['d'] * $yt) + $ctm['f'];
4823 // bottom right
4824 $xt = $x + $w;
4825 $yt = $y - $h;
4826 $x4 = ($ctm['a'] * $xt) + ($ctm['c'] * $yt) + $ctm['e'];
4827 $y4 = ($ctm['b'] * $xt) + ($ctm['d'] * $yt) + $ctm['f'];
4828 // new coordinates (rectangle area)
4829 $x = min($x1, $x2, $x3, $x4);
4830 $y = max($y1, $y2, $y3, $y4);
4831 $w = (max($x1, $x2, $x3, $x4) - $x) / $this->k;
4832 $h = ($y - min($y1, $y2, $y3, $y4)) / $this->k;
4833 $x = $x / $this->k;
4834 $y = $this->h - ($y / $this->k);
4835 }
4836 }
4837 }
4838 }
4839 if ($this->page <= 0) {
4840 $page = 1;
4841 } else {
4842 $page = $this->page;
4843 }
4844 if (!isset($this->PageAnnots[$page])) {
4845 $this->PageAnnots[$page] = array();
4846 }
4847 $this->PageAnnots[$page][] = array('n' => ++$this->n, 'x' => $x, 'y' => $y, 'w' => $w, 'h' => $h, 'txt' => $text, 'opt' => $opt, 'numspaces' => $spaces);
4848 if (!$this->pdfa_mode) {
4849 if ((($opt['Subtype'] == 'FileAttachment') OR ($opt['Subtype'] == 'Sound')) AND (!TCPDF_STATIC::empty_string($opt['FS']))
4850 AND (@file_exists($opt['FS']) OR TCPDF_STATIC::isValidURL($opt['FS']))
4851 AND (!isset($this->embeddedfiles[basename($opt['FS'])]))) {
4852 $this->embeddedfiles[basename($opt['FS'])] = array('f' => ++$this->n, 'n' => ++$this->n, 'file' => $opt['FS']);
4853 }
4854 }
4855 // Add widgets annotation's icons
4856 if (isset($opt['mk']['i']) AND @file_exists($opt['mk']['i'])) {
4857 $this->Image($opt['mk']['i'], '', '', 10, 10, '', '', '', false, 300, '', false, false, 0, false, true);
4858 }
4859 if (isset($opt['mk']['ri']) AND @file_exists($opt['mk']['ri'])) {
4860 $this->Image($opt['mk']['ri'], '', '', 0, 0, '', '', '', false, 300, '', false, false, 0, false, true);
4861 }
4862 if (isset($opt['mk']['ix']) AND @file_exists($opt['mk']['ix'])) {
4863 $this->Image($opt['mk']['ix'], '', '', 0, 0, '', '', '', false, 300, '', false, false, 0, false, true);
4864 }
4865 }
4866
4867 /**
4868 * Embedd the attached files.
4869 * @since 4.4.000 (2008-12-07)
4870 * @protected
4871 * @see Annotation()
4872 */
4873 protected function _putEmbeddedFiles() {
4874 if ($this->pdfa_mode) {
4875 // embedded files are not allowed in PDF/A mode
4876 return;
4877 }
4878 reset($this->embeddedfiles);
4879 foreach ($this->embeddedfiles as $filename => $filedata) {
4880 $data = TCPDF_STATIC::fileGetContents($filedata['file']);
4881 if ($data !== FALSE) {
4882 $rawsize = strlen($data);
4883 if ($rawsize > 0) {
4884 // update name tree
4885 $this->efnames[$filename] = $filedata['f'].' 0 R';
4886 // embedded file specification object
4887 $out = $this->_getobj($filedata['f'])."\n";
4888 $out .= '<</Type /Filespec /F '.$this->_datastring($filename, $filedata['f']).' /EF <</F '.$filedata['n'].' 0 R>> >>';
4889 $out .= "\n".'endobj';
4890 $this->_out($out);
4891 // embedded file object
4892 $filter = '';
4893 if ($this->compress) {
4894 $data = gzcompress($data);
4895 $filter = ' /Filter /FlateDecode';
4896 }
4897 $stream = $this->_getrawstream($data, $filedata['n']);
4898 $out = $this->_getobj($filedata['n'])."\n";
4899 $out .= '<< /Type /EmbeddedFile'.$filter.' /Length '.strlen($stream).' /Params <</Size '.$rawsize.'>> >>';
4900 $out .= ' stream'."\n".$stream."\n".'endstream';
4901 $out .= "\n".'endobj';
4902 $this->_out($out);
4903 }
4904 }
4905 }
4906 }
4907
4908 /**
4909 * Prints a text cell at the specified position.
4910 * This method allows to place a string precisely on the page.
4911 * @param $x (float) Abscissa of the cell origin
4912 * @param $y (float) Ordinate of the cell origin
4913 * @param $txt (string) String to print
4914 * @param $fstroke (int) outline size in user units (false = disable)
4915 * @param $fclip (boolean) if true activate clipping mode (you must call StartTransform() before this function and StopTransform() to stop the clipping tranformation).
4916 * @param $ffill (boolean) if true fills the text
4917 * @param $border (mixed) Indicates if borders must be drawn around the cell. 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 - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0)))
4918 * @param $ln (int) Indicates where the current position should go after the call. Possible values are:<ul><li>0: to the right (or left for RTL languages)</li><li>1: to the beginning of the next line</li><li>2: below</li></ul>Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0.
4919 * @param $align (string) Allows to center or align the text. Possible values are:<ul><li>L or empty string: left align (default value)</li><li>C: center</li><li>R: right align</li><li>J: justify</li></ul>
4920 * @param $fill (boolean) Indicates if the cell background must be painted (true) or transparent (false).
4921 * @param $link (mixed) URL or identifier returned by AddLink().
4922 * @param $stretch (int) font stretch mode: <ul><li>0 = disabled</li><li>1 = horizontal scaling only if text is larger than cell width</li><li>2 = forced horizontal scaling to fit cell width</li><li>3 = character spacing only if text is larger than cell width</li><li>4 = forced character spacing to fit cell width</li></ul> General font stretching and scaling values will be preserved when possible.
4923 * @param $ignore_min_height (boolean) if true ignore automatic minimum height value.
4924 * @param $calign (string) cell vertical alignment relative to the specified Y value. Possible values are:<ul><li>T : cell top</li><li>A : font top</li><li>L : font baseline</li><li>D : font bottom</li><li>B : cell bottom</li></ul>
4925 * @param $valign (string) text vertical alignment inside the cell. Possible values are:<ul><li>T : top</li><li>C : center</li><li>B : bottom</li></ul>
4926 * @param $rtloff (boolean) if true uses the page top-left corner as origin of axis for $x and $y initial position.
4927 * @public
4928 * @since 1.0
4929 * @see Cell(), Write(), MultiCell(), WriteHTML(), WriteHTMLCell()
4930 */
4931 public function Text($x, $y, $txt, $fstroke=false, $fclip=false, $ffill=true, $border=0, $ln=0, $align='', $fill=false, $link='', $stretch=0, $ignore_min_height=false, $calign='T', $valign='M', $rtloff=false) {
4932 $textrendermode = $this->textrendermode;
4933 $textstrokewidth = $this->textstrokewidth;
4934 $this->setTextRenderingMode($fstroke, $ffill, $fclip);
4935 $this->SetXY($x, $y, $rtloff);
4936 $this->Cell(0, 0, $txt, $border, $ln, $align, $fill, $link, $stretch, $ignore_min_height, $calign, $valign);
4937 // restore previous rendering mode
4938 $this->textrendermode = $textrendermode;
4939 $this->textstrokewidth = $textstrokewidth;
4940 }
4941
4942 /**
4943 * Whenever a page break condition is met, the method is called, and the break is issued or not depending on the returned value.
4944 * The default implementation returns a value according to the mode selected by SetAutoPageBreak().<br />
4945 * This method is called automatically and should not be called directly by the application.
4946 * @return boolean
4947 * @public
4948 * @since 1.4
4949 * @see SetAutoPageBreak()
4950 */
4951 public function AcceptPageBreak() {
4952 if ($this->num_columns > 1) {
4953 // multi column mode
4954 if ($this->current_column < ($this->num_columns - 1)) {
4955 // go to next column
4956 $this->selectColumn($this->current_column + 1);
4957 } elseif ($this->AutoPageBreak) {
4958 // add a new page
4959 $this->AddPage();
4960 // set first column
4961 $this->selectColumn(0);
4962 }
4963 // avoid page breaking from checkPageBreak()
4964 return false;
4965 }
4966 return $this->AutoPageBreak;
4967 }
4968
4969 /**
4970 * Add page if needed.
4971 * @param $h (float) Cell height. Default value: 0.
4972 * @param $y (mixed) starting y position, leave empty for current position.
4973 * @param $addpage (boolean) if true add a page, otherwise only return the true/false state
4974 * @return boolean true in case of page break, false otherwise.
4975 * @since 3.2.000 (2008-07-01)
4976 * @protected
4977 */
4978 protected function checkPageBreak($h=0, $y='', $addpage=true) {
4979 if (TCPDF_STATIC::empty_string($y)) {
4980 $y = $this->y;
4981 }
4982 $current_page = $this->page;
4983 if ((($y + $h) > $this->PageBreakTrigger) AND ($this->inPageBody()) AND ($this->AcceptPageBreak())) {
4984 if ($addpage) {
4985 //Automatic page break
4986 $x = $this->x;
4987 $this->AddPage($this->CurOrientation);
4988 $this->y = $this->tMargin;
4989 $oldpage = $this->page - 1;
4990 if ($this->rtl) {
4991 if ($this->pagedim[$this->page]['orm'] != $this->pagedim[$oldpage]['orm']) {
4992 $this->x = $x - ($this->pagedim[$this->page]['orm'] - $this->pagedim[$oldpage]['orm']);
4993 } else {
4994 $this->x = $x;
4995 }
4996 } else {
4997 if ($this->pagedim[$this->page]['olm'] != $this->pagedim[$oldpage]['olm']) {
4998 $this->x = $x + ($this->pagedim[$this->page]['olm'] - $this->pagedim[$oldpage]['olm']);
4999 } else {
5000 $this->x = $x;
5001 }
5002 }
5003 }
5004 return true;
5005 }
5006 if ($current_page != $this->page) {
5007 // account for columns mode
5008 return true;
5009 }
5010 return false;
5011 }
5012
5013 /**
5014 * Prints a cell (rectangular area) with optional borders, background color and character string. The upper-left corner of the cell corresponds to the current position. The text can be aligned or centered. After the call, the current position moves to the right or to the next line. It is possible to put a link on the text.<br />
5015 * If automatic page breaking is enabled and the cell goes beyond the limit, a page break is done before outputting.
5016 * @param $w (float) Cell width. If 0, the cell extends up to the right margin.
5017 * @param $h (float) Cell height. Default value: 0.
5018 * @param $txt (string) String to print. Default value: empty string.
5019 * @param $border (mixed) Indicates if borders must be drawn around the cell. 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 - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0)))
5020 * @param $ln (int) Indicates where the current position should go after the call. Possible values are:<ul><li>0: to the right (or left for RTL languages)</li><li>1: to the beginning of the next line</li><li>2: below</li></ul> Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0.
5021 * @param $align (string) Allows to center or align the text. Possible values are:<ul><li>L or empty string: left align (default value)</li><li>C: center</li><li>R: right align</li><li>J: justify</li></ul>
5022 * @param $fill (boolean) Indicates if the cell background must be painted (true) or transparent (false).
5023 * @param $link (mixed) URL or identifier returned by AddLink().
5024 * @param $stretch (int) font stretch mode: <ul><li>0 = disabled</li><li>1 = horizontal scaling only if text is larger than cell width</li><li>2 = forced horizontal scaling to fit cell width</li><li>3 = character spacing only if text is larger than cell width</li><li>4 = forced character spacing to fit cell width</li></ul> General font stretching and scaling values will be preserved when possible.
5025 * @param $ignore_min_height (boolean) if true ignore automatic minimum height value.
5026 * @param $calign (string) cell vertical alignment relative to the specified Y value. Possible values are:<ul><li>T : cell top</li><li>C : center</li><li>B : cell bottom</li><li>A : font top</li><li>L : font baseline</li><li>D : font bottom</li></ul>
5027 * @param $valign (string) text vertical alignment inside the cell. Possible values are:<ul><li>T : top</li><li>C : center</li><li>B : bottom</li></ul>
5028 * @public
5029 * @since 1.0
5030 * @see SetFont(), SetDrawColor(), SetFillColor(), SetTextColor(), SetLineWidth(), AddLink(), Ln(), MultiCell(), Write(), SetAutoPageBreak()
5031 */
5032 public function Cell($w, $h=0, $txt='', $border=0, $ln=0, $align='', $fill=false, $link='', $stretch=0, $ignore_min_height=false, $calign='T', $valign='M') {
5033 $prev_cell_margin = $this->cell_margin;
5034 $prev_cell_padding = $this->cell_padding;
5035 $this->adjustCellPadding($border);
5036 if (!$ignore_min_height) {
5037 $min_cell_height = $this->getCellHeight($this->FontSize);
5038 if ($h < $min_cell_height) {
5039 $h = $min_cell_height;
5040 }
5041 }
5042 $this->checkPageBreak($h + $this->cell_margin['T'] + $this->cell_margin['B']);
5043 // apply text shadow if enabled
5044 if ($this->txtshadow['enabled']) {
5045 // save data
5046 $x = $this->x;
5047 $y = $this->y;
5048 $bc = $this->bgcolor;
5049 $fc = $this->fgcolor;
5050 $sc = $this->strokecolor;
5051 $alpha = $this->alpha;
5052 // print shadow
5053 $this->x += $this->txtshadow['depth_w'];
5054 $this->y += $this->txtshadow['depth_h'];
5055 $this->SetFillColorArray($this->txtshadow['color']);
5056 $this->SetTextColorArray($this->txtshadow['color']);
5057 $this->SetDrawColorArray($this->txtshadow['color']);
5058 if ($this->txtshadow['opacity'] != $alpha['CA']) {
5059 $this->setAlpha($this->txtshadow['opacity'], $this->txtshadow['blend_mode']);
5060 }
5061 if ($this->state == 2) {
5062 $this->_out($this->getCellCode($w, $h, $txt, $border, $ln, $align, $fill, $link, $stretch, true, $calign, $valign));
5063 }
5064 //restore data
5065 $this->x = $x;
5066 $this->y = $y;
5067 $this->SetFillColorArray($bc);
5068 $this->SetTextColorArray($fc);
5069 $this->SetDrawColorArray($sc);
5070 if ($this->txtshadow['opacity'] != $alpha['CA']) {
5071 $this->setAlpha($alpha['CA'], $alpha['BM'], $alpha['ca'], $alpha['AIS']);
5072 }
5073 }
5074 if ($this->state == 2) {
5075 $this->_out($this->getCellCode($w, $h, $txt, $border, $ln, $align, $fill, $link, $stretch, true, $calign, $valign));
5076 }
5077 $this->cell_padding = $prev_cell_padding;
5078 $this->cell_margin = $prev_cell_margin;
5079 }
5080
5081 /**
5082 * Returns the PDF string code to print a cell (rectangular area) with optional borders, background color and character string. The upper-left corner of the cell corresponds to the current position. The text can be aligned or centered. After the call, the current position moves to the right or to the next line. It is possible to put a link on the text.<br />
5083 * If automatic page breaking is enabled and the cell goes beyond the limit, a page break is done before outputting.
5084 * @param $w (float) Cell width. If 0, the cell extends up to the right margin.
5085 * @param $h (float) Cell height. Default value: 0.
5086 * @param $txt (string) String to print. Default value: empty string.
5087 * @param $border (mixed) Indicates if borders must be drawn around the cell. 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 - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0)))
5088 * @param $ln (int) Indicates where the current position should go after the call. Possible values are:<ul><li>0: to the right (or left for RTL languages)</li><li>1: to the beginning of the next line</li><li>2: below</li></ul>Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0.
5089 * @param $align (string) Allows to center or align the text. Possible values are:<ul><li>L or empty string: left align (default value)</li><li>C: center</li><li>R: right align</li><li>J: justify</li></ul>
5090 * @param $fill (boolean) Indicates if the cell background must be painted (true) or transparent (false).
5091 * @param $link (mixed) URL or identifier returned by AddLink().
5092 * @param $stretch (int) font stretch mode: <ul><li>0 = disabled</li><li>1 = horizontal scaling only if text is larger than cell width</li><li>2 = forced horizontal scaling to fit cell width</li><li>3 = character spacing only if text is larger than cell width</li><li>4 = forced character spacing to fit cell width</li></ul> General font stretching and scaling values will be preserved when possible.
5093 * @param $ignore_min_height (boolean) if true ignore automatic minimum height value.
5094 * @param $calign (string) cell vertical alignment relative to the specified Y value. Possible values are:<ul><li>T : cell top</li><li>C : center</li><li>B : cell bottom</li><li>A : font top</li><li>L : font baseline</li><li>D : font bottom</li></ul>
5095 * @param $valign (string) text vertical alignment inside the cell. Possible values are:<ul><li>T : top</li><li>M : middle</li><li>B : bottom</li></ul>
5096 * @return string containing cell code
5097 * @protected
5098 * @since 1.0
5099 * @see Cell()
5100 */
5101 protected function getCellCode($w, $h=0, $txt='', $border=0, $ln=0, $align='', $fill=false, $link='', $stretch=0, $ignore_min_height=false, $calign='T', $valign='M') {
5102 // replace 'NO-BREAK SPACE' (U+00A0) character with a simple space
5103 $txt = str_replace(TCPDF_FONTS::unichr(160, $this->isunicode), ' ', $txt);
5104 $prev_cell_margin = $this->cell_margin;
5105 $prev_cell_padding = $this->cell_padding;
5106 $txt = TCPDF_STATIC::removeSHY($txt, $this->isunicode);
5107 $rs = ''; //string to be returned
5108 $this->adjustCellPadding($border);
5109 if (!$ignore_min_height) {
5110 $min_cell_height = $this->getCellHeight($this->FontSize);
5111 if ($h < $min_cell_height) {
5112 $h = $min_cell_height;
5113 }
5114 }
5115 $k = $this->k;
5116 // check page for no-write regions and adapt page margins if necessary
5117 list($this->x, $this->y) = $this->checkPageRegions($h, $this->x, $this->y);
5118 if ($this->rtl) {
5119 $x = $this->x - $this->cell_margin['R'];
5120 } else {
5121 $x = $this->x + $this->cell_margin['L'];
5122 }
5123 $y = $this->y + $this->cell_margin['T'];
5124 $prev_font_stretching = $this->font_stretching;
5125 $prev_font_spacing = $this->font_spacing;
5126 // cell vertical alignment
5127 switch ($calign) {
5128 case 'A': {
5129 // font top
5130 switch ($valign) {
5131 case 'T': {
5132 // top
5133 $y -= $this->cell_padding['T'];
5134 break;
5135 }
5136 case 'B': {
5137 // bottom
5138 $y -= ($h - $this->cell_padding['B'] - $this->FontAscent - $this->FontDescent);
5139 break;
5140 }
5141 default:
5142 case 'C':
5143 case 'M': {
5144 // center
5145 $y -= (($h - $this->FontAscent - $this->FontDescent) / 2);
5146 break;
5147 }
5148 }
5149 break;
5150 }
5151 case 'L': {
5152 // font baseline
5153 switch ($valign) {
5154 case 'T': {
5155 // top
5156 $y -= ($this->cell_padding['T'] + $this->FontAscent);
5157 break;
5158 }
5159 case 'B': {
5160 // bottom
5161 $y -= ($h - $this->cell_padding['B'] - $this->FontDescent);
5162 break;
5163 }
5164 default:
5165 case 'C':
5166 case 'M': {
5167 // center
5168 $y -= (($h + $this->FontAscent - $this->FontDescent) / 2);
5169 break;
5170 }
5171 }
5172 break;
5173 }
5174 case 'D': {
5175 // font bottom
5176 switch ($valign) {
5177 case 'T': {
5178 // top
5179 $y -= ($this->cell_padding['T'] + $this->FontAscent + $this->FontDescent);
5180 break;
5181 }
5182 case 'B': {
5183 // bottom
5184 $y -= ($h - $this->cell_padding['B']);
5185 break;
5186 }
5187 default:
5188 case 'C':
5189 case 'M': {
5190 // center
5191 $y -= (($h + $this->FontAscent + $this->FontDescent) / 2);
5192 break;
5193 }
5194 }
5195 break;
5196 }
5197 case 'B': {
5198 // cell bottom
5199 $y -= $h;
5200 break;
5201 }
5202 case 'C':
5203 case 'M': {
5204 // cell center
5205 $y -= ($h / 2);
5206 break;
5207 }
5208 default:
5209 case 'T': {
5210 // cell top
5211 break;
5212 }
5213 }
5214 // text vertical alignment
5215 switch ($valign) {
5216 case 'T': {
5217 // top
5218 $yt = $y + $this->cell_padding['T'];
5219 break;
5220 }
5221 case 'B': {
5222 // bottom
5223 $yt = $y + $h - $this->cell_padding['B'] - $this->FontAscent - $this->FontDescent;
5224 break;
5225 }
5226 default:
5227 case 'C':
5228 case 'M': {
5229 // center
5230 $yt = $y + (($h - $this->FontAscent - $this->FontDescent) / 2);
5231 break;
5232 }
5233 }
5234 $basefonty = $yt + $this->FontAscent;
5235 if (TCPDF_STATIC::empty_string($w) OR ($w <= 0)) {
5236 if ($this->rtl) {
5237 $w = $x - $this->lMargin;
5238 } else {
5239 $w = $this->w - $this->rMargin - $x;
5240 }
5241 }
5242 $s = '';
5243 // fill and borders
5244 if (is_string($border) AND (strlen($border) == 4)) {
5245 // full border
5246 $border = 1;
5247 }
5248 if ($fill OR ($border == 1)) {
5249 if ($fill) {
5250 $op = ($border == 1) ? 'B' : 'f';
5251 } else {
5252 $op = 'S';
5253 }
5254 if ($this->rtl) {
5255 $xk = (($x - $w) * $k);
5256 } else {
5257 $xk = ($x * $k);
5258 }
5259 $s .= sprintf('%F %F %F %F re %s ', $xk, (($this->h - $y) * $k), ($w * $k), (-$h * $k), $op);
5260 }
5261 // draw borders
5262 $s .= $this->getCellBorder($x, $y, $w, $h, $border);
5263 if ($txt != '') {
5264 $txt2 = $txt;
5265 if ($this->isunicode) {
5266 if (($this->CurrentFont['type'] == 'core') OR ($this->CurrentFont['type'] == 'TrueType') OR ($this->CurrentFont['type'] == 'Type1')) {
5267 $txt2 = TCPDF_FONTS::UTF8ToLatin1($txt2, $this->isunicode, $this->CurrentFont);
5268 } else {
5269 $unicode = TCPDF_FONTS::UTF8StringToArray($txt, $this->isunicode, $this->CurrentFont); // array of UTF-8 unicode values
5270 $unicode = TCPDF_FONTS::utf8Bidi($unicode, '', $this->tmprtl, $this->isunicode, $this->CurrentFont);
5271 // replace thai chars (if any)
5272 if (defined('K_THAI_TOPCHARS') AND (K_THAI_TOPCHARS == true)) {
5273 // number of chars
5274 $numchars = count($unicode);
5275 // po pla, for far, for fan
5276 $longtail = array(0x0e1b, 0x0e1d, 0x0e1f);
5277 // do chada, to patak
5278 $lowtail = array(0x0e0e, 0x0e0f);
5279 // mai hun arkad, sara i, sara ii, sara ue, sara uee
5280 $upvowel = array(0x0e31, 0x0e34, 0x0e35, 0x0e36, 0x0e37);
5281 // mai ek, mai tho, mai tri, mai chattawa, karan
5282 $tonemark = array(0x0e48, 0x0e49, 0x0e4a, 0x0e4b, 0x0e4c);
5283 // sara u, sara uu, pinthu
5284 $lowvowel = array(0x0e38, 0x0e39, 0x0e3a);
5285 $output = array();
5286 for ($i = 0; $i < $numchars; $i++) {
5287 if (($unicode[$i] >= 0x0e00) && ($unicode[$i] <= 0x0e5b)) {
5288 $ch0 = $unicode[$i];
5289 $ch1 = ($i > 0) ? $unicode[($i - 1)] : 0;
5290 $ch2 = ($i > 1) ? $unicode[($i - 2)] : 0;
5291 $chn = ($i < ($numchars - 1)) ? $unicode[($i + 1)] : 0;
5292 if (in_array($ch0, $tonemark)) {
5293 if ($chn == 0x0e33) {
5294 // sara um
5295 if (in_array($ch1, $longtail)) {
5296 // tonemark at upper left
5297 $output[] = $this->replaceChar($ch0, (0xf713 + $ch0 - 0x0e48));
5298 } else {
5299 // tonemark at upper right (normal position)
5300 $output[] = $ch0;
5301 }
5302 } elseif (in_array($ch1, $longtail) OR (in_array($ch2, $longtail) AND in_array($ch1, $lowvowel))) {
5303 // tonemark at lower left
5304 $output[] = $this->replaceChar($ch0, (0xf705 + $ch0 - 0x0e48));
5305 } elseif (in_array($ch1, $upvowel)) {
5306 if (in_array($ch2, $longtail)) {
5307 // tonemark at upper left
5308 $output[] = $this->replaceChar($ch0, (0xf713 + $ch0 - 0x0e48));
5309 } else {
5310 // tonemark at upper right (normal position)
5311 $output[] = $ch0;
5312 }
5313 } else {
5314 // tonemark at lower right
5315 $output[] = $this->replaceChar($ch0, (0xf70a + $ch0 - 0x0e48));
5316 }
5317 } elseif (($ch0 == 0x0e33) AND (in_array($ch1, $longtail) OR (in_array($ch2, $longtail) AND in_array($ch1, $tonemark)))) {
5318 // add lower left nikhahit and sara aa
5319 if ($this->isCharDefined(0xf711) AND $this->isCharDefined(0x0e32)) {
5320 $output[] = 0xf711;
5321 $this->CurrentFont['subsetchars'][0xf711] = true;
5322 $output[] = 0x0e32;
5323 $this->CurrentFont['subsetchars'][0x0e32] = true;
5324 } else {
5325 $output[] = $ch0;
5326 }
5327 } elseif (in_array($ch1, $longtail)) {
5328 if ($ch0 == 0x0e31) {
5329 // lower left mai hun arkad
5330 $output[] = $this->replaceChar($ch0, 0xf710);
5331 } elseif (in_array($ch0, $upvowel)) {
5332 // lower left
5333 $output[] = $this->replaceChar($ch0, (0xf701 + $ch0 - 0x0e34));
5334 } elseif ($ch0 == 0x0e47) {
5335 // lower left mai tai koo
5336 $output[] = $this->replaceChar($ch0, 0xf712);
5337 } else {
5338 // normal character
5339 $output[] = $ch0;
5340 }
5341 } elseif (in_array($ch1, $lowtail) AND in_array($ch0, $lowvowel)) {
5342 // lower vowel
5343 $output[] = $this->replaceChar($ch0, (0xf718 + $ch0 - 0x0e38));
5344 } elseif (($ch0 == 0x0e0d) AND in_array($chn, $lowvowel)) {
5345 // yo ying without lower part
5346 $output[] = $this->replaceChar($ch0, 0xf70f);
5347 } elseif (($ch0 == 0x0e10) AND in_array($chn, $lowvowel)) {
5348 // tho santan without lower part
5349 $output[] = $this->replaceChar($ch0, 0xf700);
5350 } else {
5351 $output[] = $ch0;
5352 }
5353 } else {
5354 // non-thai character
5355 $output[] = $unicode[$i];
5356 }
5357 }
5358 $unicode = $output;
5359 // update font subsetchars
5360 $this->setFontSubBuffer($this->CurrentFont['fontkey'], 'subsetchars', $this->CurrentFont['subsetchars']);
5361 } // end of K_THAI_TOPCHARS
5362 $txt2 = TCPDF_FONTS::arrUTF8ToUTF16BE($unicode, false);
5363 }
5364 }
5365 $txt2 = TCPDF_STATIC::_escape($txt2);
5366 // get current text width (considering general font stretching and spacing)
5367 $txwidth = $this->GetStringWidth($txt);
5368 $width = $txwidth;
5369 // check for stretch mode
5370 if ($stretch > 0) {
5371 // calculate ratio between cell width and text width
5372 if ($width <= 0) {
5373 $ratio = 1;
5374 } else {
5375 $ratio = (($w - $this->cell_padding['L'] - $this->cell_padding['R']) / $width);
5376 }
5377 // check if stretching is required
5378 if (($ratio < 1) OR (($ratio > 1) AND (($stretch % 2) == 0))) {
5379 // the text will be stretched to fit cell width
5380 if ($stretch > 2) {
5381 // set new character spacing
5382 $this->font_spacing += ($w - $this->cell_padding['L'] - $this->cell_padding['R'] - $width) / (max(($this->GetNumChars($txt) - 1), 1) * ($this->font_stretching / 100));
5383 } else {
5384 // set new horizontal stretching
5385 $this->font_stretching *= $ratio;
5386 }
5387 // recalculate text width (the text fills the entire cell)
5388 $width = $w - $this->cell_padding['L'] - $this->cell_padding['R'];
5389 // reset alignment
5390 $align = '';
5391 }
5392 }
5393 if ($this->font_stretching != 100) {
5394 // apply font stretching
5395 $rs .= sprintf('BT %F Tz ET ', $this->font_stretching);
5396 }
5397 if ($this->font_spacing != 0) {
5398 // increase/decrease font spacing
5399 $rs .= sprintf('BT %F Tc ET ', ($this->font_spacing * $this->k));
5400 }
5401 if ($this->ColorFlag AND ($this->textrendermode < 4)) {
5402 $s .= 'q '.$this->TextColor.' ';
5403 }
5404 // rendering mode
5405 $s .= sprintf('BT %d Tr %F w ET ', $this->textrendermode, ($this->textstrokewidth * $this->k));
5406 // count number of spaces
5407 $ns = substr_count($txt, chr(32));
5408 // Justification
5409 $spacewidth = 0;
5410 if (($align == 'J') AND ($ns > 0)) {
5411 if ($this->isUnicodeFont()) {
5412 // get string width without spaces
5413 $width = $this->GetStringWidth(str_replace(' ', '', $txt));
5414 // calculate average space width
5415 $spacewidth = -1000 * ($w - $width - $this->cell_padding['L'] - $this->cell_padding['R']) / ($ns?$ns:1) / ($this->FontSize?$this->FontSize:1);
5416 if ($this->font_stretching != 100) {
5417 // word spacing is affected by stretching
5418 $spacewidth /= ($this->font_stretching / 100);
5419 }
5420 // set word position to be used with TJ operator
5421 $txt2 = str_replace(chr(0).chr(32), ') '.sprintf('%F', $spacewidth).' (', $txt2);
5422 $unicode_justification = true;
5423 } else {
5424 // get string width
5425 $width = $txwidth;
5426 // new space width
5427 $spacewidth = (($w - $width - $this->cell_padding['L'] - $this->cell_padding['R']) / ($ns?$ns:1)) * $this->k;
5428 if ($this->font_stretching != 100) {
5429 // word spacing (Tw) is affected by stretching
5430 $spacewidth /= ($this->font_stretching / 100);
5431 }
5432 // set word spacing
5433 $rs .= sprintf('BT %F Tw ET ', $spacewidth);
5434 }
5435 $width = $w - $this->cell_padding['L'] - $this->cell_padding['R'];
5436 }
5437 // replace carriage return characters
5438 $txt2 = str_replace("\r", ' ', $txt2);
5439 switch ($align) {
5440 case 'C': {
5441 $dx = ($w - $width) / 2;
5442 break;
5443 }
5444 case 'R': {
5445 if ($this->rtl) {
5446 $dx = $this->cell_padding['R'];
5447 } else {
5448 $dx = $w - $width - $this->cell_padding['R'];
5449 }
5450 break;
5451 }
5452 case 'L': {
5453 if ($this->rtl) {
5454 $dx = $w - $width - $this->cell_padding['L'];
5455 } else {
5456 $dx = $this->cell_padding['L'];
5457 }
5458 break;
5459 }
5460 case 'J':
5461 default: {
5462 if ($this->rtl) {
5463 $dx = $this->cell_padding['R'];
5464 } else {
5465 $dx = $this->cell_padding['L'];
5466 }
5467 break;
5468 }
5469 }
5470 if ($this->rtl) {
5471 $xdx = $x - $dx - $width;
5472 } else {
5473 $xdx = $x + $dx;
5474 }
5475 $xdk = $xdx * $k;
5476 // print text
5477 $s .= sprintf('BT %F %F Td [(%s)] TJ ET', $xdk, (($this->h - $basefonty) * $k), $txt2);
5478 if (isset($uniblock)) {
5479 // print overlapping characters as separate string
5480 $xshift = 0; // horizontal shift
5481 $ty = (($this->h - $basefonty + (0.2 * $this->FontSize)) * $k);
5482 $spw = (($w - $txwidth - $this->cell_padding['L'] - $this->cell_padding['R']) / ($ns?$ns:1));
5483 foreach ($uniblock as $uk => $uniarr) {
5484 if (($uk % 2) == 0) {
5485 // x space to skip
5486 if ($spacewidth != 0) {
5487 // justification shift
5488 $xshift += (count(array_keys($uniarr, 32)) * $spw);
5489 }
5490 $xshift += $this->GetArrStringWidth($uniarr); // + shift justification
5491 } else {
5492 // character to print
5493 $topchr = TCPDF_FONTS::arrUTF8ToUTF16BE($uniarr, false);
5494 $topchr = TCPDF_STATIC::_escape($topchr);
5495 $s .= sprintf(' BT %F %F Td [(%s)] TJ ET', ($xdk + ($xshift * $k)), $ty, $topchr);
5496 }
5497 }
5498 }
5499 if ($this->underline) {
5500 $s .= ' '.$this->_dounderlinew($xdx, $basefonty, $width);
5501 }
5502 if ($this->linethrough) {
5503 $s .= ' '.$this->_dolinethroughw($xdx, $basefonty, $width);
5504 }
5505 if ($this->overline) {
5506 $s .= ' '.$this->_dooverlinew($xdx, $basefonty, $width);
5507 }
5508 if ($this->ColorFlag AND ($this->textrendermode < 4)) {
5509 $s .= ' Q';
5510 }
5511 if ($link) {
5512 $this->Link($xdx, $yt, $width, ($this->FontAscent + $this->FontDescent), $link, $ns);
5513 }
5514 }
5515 // output cell
5516 if ($s) {
5517 // output cell
5518 $rs .= $s;
5519 if ($this->font_spacing != 0) {
5520 // reset font spacing mode
5521 $rs .= ' BT 0 Tc ET';
5522 }
5523 if ($this->font_stretching != 100) {
5524 // reset font stretching mode
5525 $rs .= ' BT 100 Tz ET';
5526 }
5527 }
5528 // reset word spacing
5529 if (!$this->isUnicodeFont() AND ($align == 'J')) {
5530 $rs .= ' BT 0 Tw ET';
5531 }
5532 // reset stretching and spacing
5533 $this->font_stretching = $prev_font_stretching;
5534 $this->font_spacing = $prev_font_spacing;
5535 $this->lasth = $h;
5536 if ($ln > 0) {
5537 //Go to the beginning of the next line
5538 $this->y = $y + $h + $this->cell_margin['B'];
5539 if ($ln == 1) {
5540 if ($this->rtl) {
5541 $this->x = $this->w - $this->rMargin;
5542 } else {
5543 $this->x = $this->lMargin;
5544 }
5545 }
5546 } else {
5547 // go left or right by case
5548 if ($this->rtl) {
5549 $this->x = $x - $w - $this->cell_margin['L'];
5550 } else {
5551 $this->x = $x + $w + $this->cell_margin['R'];
5552 }
5553 }
5554 $gstyles = ''.$this->linestyleWidth.' '.$this->linestyleCap.' '.$this->linestyleJoin.' '.$this->linestyleDash.' '.$this->DrawColor.' '.$this->FillColor."\n";
5555 $rs = $gstyles.$rs;
5556 $this->cell_padding = $prev_cell_padding;
5557 $this->cell_margin = $prev_cell_margin;
5558 return $rs;
5559 }
5560
5561 /**
5562 * Replace a char if is defined on the current font.
5563 * @param $oldchar (int) Integer code (unicode) of the character to replace.
5564 * @param $newchar (int) Integer code (unicode) of the new character.
5565 * @return int the replaced char or the old char in case the new char i not defined
5566 * @protected
5567 * @since 5.9.167 (2012-06-22)
5568 */
5569 protected function replaceChar($oldchar, $newchar) {
5570 if ($this->isCharDefined($newchar)) {
5571 // add the new char on the subset list
5572 $this->CurrentFont['subsetchars'][$newchar] = true;
5573 // return the new character
5574 return $newchar;
5575 }
5576 // return the old char
5577 return $oldchar;
5578 }
5579
5580 /**
5581 * Returns the code to draw the cell border
5582 * @param $x (float) X coordinate.
5583 * @param $y (float) Y coordinate.
5584 * @param $w (float) Cell width.
5585 * @param $h (float) Cell height.
5586 * @param $brd (mixed) Indicates if borders must be drawn around the cell. 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 - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0)))
5587 * @return string containing cell border code
5588 * @protected
5589 * @see SetLineStyle()
5590 * @since 5.7.000 (2010-08-02)
5591 */
5592 protected function getCellBorder($x, $y, $w, $h, $brd) {
5593 $s = ''; // string to be returned
5594 if (empty($brd)) {
5595 return $s;
5596 }
5597 if ($brd == 1) {
5598 $brd = array('LRTB' => true);
5599 }
5600 // calculate coordinates for border
5601 $k = $this->k;
5602 if ($this->rtl) {
5603 $xeL = ($x - $w) * $k;
5604 $xeR = $x * $k;
5605 } else {
5606 $xeL = $x * $k;
5607 $xeR = ($x + $w) * $k;
5608 }
5609 $yeL = (($this->h - ($y + $h)) * $k);
5610 $yeT = (($this->h - $y) * $k);
5611 $xeT = $xeL;
5612 $xeB = $xeR;
5613 $yeR = $yeT;
5614 $yeB = $yeL;
5615 if (is_string($brd)) {
5616 // convert string to array
5617 $slen = strlen($brd);
5618 $newbrd = array();
5619 for ($i = 0; $i < $slen; ++$i) {
5620 $newbrd[$brd[$i]] = array('cap' => 'square', 'join' => 'miter');
5621 }
5622 $brd = $newbrd;
5623 }
5624 if (isset($brd['mode'])) {
5625 $mode = $brd['mode'];
5626 unset($brd['mode']);
5627 } else {
5628 $mode = 'normal';
5629 }
5630 foreach ($brd as $border => $style) {
5631 if (is_array($style) AND !empty($style)) {
5632 // apply border style
5633 $prev_style = $this->linestyleWidth.' '.$this->linestyleCap.' '.$this->linestyleJoin.' '.$this->linestyleDash.' '.$this->DrawColor.' ';
5634 $s .= $this->SetLineStyle($style, true)."\n";
5635 }
5636 switch ($mode) {
5637 case 'ext': {
5638 $off = (($this->LineWidth / 2) * $k);
5639 $xL = $xeL - $off;
5640 $xR = $xeR + $off;
5641 $yT = $yeT + $off;
5642 $yL = $yeL - $off;
5643 $xT = $xL;
5644 $xB = $xR;
5645 $yR = $yT;
5646 $yB = $yL;
5647 $w += $this->LineWidth;
5648 $h += $this->LineWidth;
5649 break;
5650 }
5651 case 'int': {
5652 $off = ($this->LineWidth / 2) * $k;
5653 $xL = $xeL + $off;
5654 $xR = $xeR - $off;
5655 $yT = $yeT - $off;
5656 $yL = $yeL + $off;
5657 $xT = $xL;
5658 $xB = $xR;
5659 $yR = $yT;
5660 $yB = $yL;
5661 $w -= $this->LineWidth;
5662 $h -= $this->LineWidth;
5663 break;
5664 }
5665 case 'normal':
5666 default: {
5667 $xL = $xeL;
5668 $xT = $xeT;
5669 $xB = $xeB;
5670 $xR = $xeR;
5671 $yL = $yeL;
5672 $yT = $yeT;
5673 $yB = $yeB;
5674 $yR = $yeR;
5675 break;
5676 }
5677 }
5678 // draw borders by case
5679 if (strlen($border) == 4) {
5680 $s .= sprintf('%F %F %F %F re S ', $xT, $yT, ($w * $k), (-$h * $k));
5681 } elseif (strlen($border) == 3) {
5682 if (strpos($border,'B') === false) { // LTR
5683 $s .= sprintf('%F %F m ', $xL, $yL);
5684 $s .= sprintf('%F %F l ', $xT, $yT);
5685 $s .= sprintf('%F %F l ', $xR, $yR);
5686 $s .= sprintf('%F %F l ', $xB, $yB);
5687 $s .= 'S ';
5688 } elseif (strpos($border,'L') === false) { // TRB
5689 $s .= sprintf('%F %F m ', $xT, $yT);
5690 $s .= sprintf('%F %F l ', $xR, $yR);
5691 $s .= sprintf('%F %F l ', $xB, $yB);
5692 $s .= sprintf('%F %F l ', $xL, $yL);
5693 $s .= 'S ';
5694 } elseif (strpos($border,'T') === false) { // RBL
5695 $s .= sprintf('%F %F m ', $xR, $yR);
5696 $s .= sprintf('%F %F l ', $xB, $yB);
5697 $s .= sprintf('%F %F l ', $xL, $yL);
5698 $s .= sprintf('%F %F l ', $xT, $yT);
5699 $s .= 'S ';
5700 } elseif (strpos($border,'R') === false) { // BLT
5701 $s .= sprintf('%F %F m ', $xB, $yB);
5702 $s .= sprintf('%F %F l ', $xL, $yL);
5703 $s .= sprintf('%F %F l ', $xT, $yT);
5704 $s .= sprintf('%F %F l ', $xR, $yR);
5705 $s .= 'S ';
5706 }
5707 } elseif (strlen($border) == 2) {
5708 if ((strpos($border,'L') !== false) AND (strpos($border,'T') !== false)) { // LT
5709 $s .= sprintf('%F %F m ', $xL, $yL);
5710 $s .= sprintf('%F %F l ', $xT, $yT);
5711 $s .= sprintf('%F %F l ', $xR, $yR);
5712 $s .= 'S ';
5713 } elseif ((strpos($border,'T') !== false) AND (strpos($border,'R') !== false)) { // TR
5714 $s .= sprintf('%F %F m ', $xT, $yT);
5715 $s .= sprintf('%F %F l ', $xR, $yR);
5716 $s .= sprintf('%F %F l ', $xB, $yB);
5717 $s .= 'S ';
5718 } elseif ((strpos($border,'R') !== false) AND (strpos($border,'B') !== false)) { // RB
5719 $s .= sprintf('%F %F m ', $xR, $yR);
5720 $s .= sprintf('%F %F l ', $xB, $yB);
5721 $s .= sprintf('%F %F l ', $xL, $yL);
5722 $s .= 'S ';
5723 } elseif ((strpos($border,'B') !== false) AND (strpos($border,'L') !== false)) { // BL
5724 $s .= sprintf('%F %F m ', $xB, $yB);
5725 $s .= sprintf('%F %F l ', $xL, $yL);
5726 $s .= sprintf('%F %F l ', $xT, $yT);
5727 $s .= 'S ';
5728 } elseif ((strpos($border,'L') !== false) AND (strpos($border,'R') !== false)) { // LR
5729 $s .= sprintf('%F %F m ', $xL, $yL);
5730 $s .= sprintf('%F %F l ', $xT, $yT);
5731 $s .= 'S ';
5732 $s .= sprintf('%F %F m ', $xR, $yR);
5733 $s .= sprintf('%F %F l ', $xB, $yB);
5734 $s .= 'S ';
5735 } elseif ((strpos($border,'T') !== false) AND (strpos($border,'B') !== false)) { // TB
5736 $s .= sprintf('%F %F m ', $xT, $yT);
5737 $s .= sprintf('%F %F l ', $xR, $yR);
5738 $s .= 'S ';
5739 $s .= sprintf('%F %F m ', $xB, $yB);
5740 $s .= sprintf('%F %F l ', $xL, $yL);
5741 $s .= 'S ';
5742 }
5743 } else { // strlen($border) == 1
5744 if (strpos($border,'L') !== false) { // L
5745 $s .= sprintf('%F %F m ', $xL, $yL);
5746 $s .= sprintf('%F %F l ', $xT, $yT);
5747 $s .= 'S ';
5748 } elseif (strpos($border,'T') !== false) { // T
5749 $s .= sprintf('%F %F m ', $xT, $yT);
5750 $s .= sprintf('%F %F l ', $xR, $yR);
5751 $s .= 'S ';
5752 } elseif (strpos($border,'R') !== false) { // R
5753 $s .= sprintf('%F %F m ', $xR, $yR);
5754 $s .= sprintf('%F %F l ', $xB, $yB);
5755 $s .= 'S ';
5756 } elseif (strpos($border,'B') !== false) { // B
5757 $s .= sprintf('%F %F m ', $xB, $yB);
5758 $s .= sprintf('%F %F l ', $xL, $yL);
5759 $s .= 'S ';
5760 }
5761 }
5762 if (is_array($style) AND !empty($style)) {
5763 // reset border style to previous value
5764 $s .= "\n".$this->linestyleWidth.' '.$this->linestyleCap.' '.$this->linestyleJoin.' '.$this->linestyleDash.' '.$this->DrawColor."\n";
5765 }
5766 }
5767 return $s;
5768 }
5769
5770 /**
5771 * This method allows printing text with line breaks.
5772 * They can be automatic (as soon as the text reaches the right border of the cell) or explicit (via the \n character). As many cells as necessary are output, one below the other.<br />
5773 * Text can be aligned, centered or justified. The cell block can be framed and the background painted.
5774 * @param $w (float) Width of cells. If 0, they extend up to the right margin of the page.
5775 * @param $h (float) Cell minimum height. The cell extends automatically if needed.
5776 * @param $txt (string) String to print
5777 * @param $border (mixed) Indicates if borders must be drawn around the cell. 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 - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0)))
5778 * @param $align (string) Allows to center or align the text. Possible values are:<ul><li>L or empty string: left align</li><li>C: center</li><li>R: right align</li><li>J: justification (default value when $ishtml=false)</li></ul>
5779 * @param $fill (boolean) Indicates if the cell background must be painted (true) or transparent (false).
5780 * @param $ln (int) Indicates where the current position should go after the call. Possible values are:<ul><li>0: to the right</li><li>1: to the beginning of the next line [DEFAULT]</li><li>2: below</li></ul>
5781 * @param $x (float) x position in user units
5782 * @param $y (float) y position in user units
5783 * @param $reseth (boolean) if true reset the last cell height (default true).
5784 * @param $stretch (int) font stretch mode: <ul><li>0 = disabled</li><li>1 = horizontal scaling only if text is larger than cell width</li><li>2 = forced horizontal scaling to fit cell width</li><li>3 = character spacing only if text is larger than cell width</li><li>4 = forced character spacing to fit cell width</li></ul> General font stretching and scaling values will be preserved when possible.
5785 * @param $ishtml (boolean) INTERNAL USE ONLY -- set to true if $txt is HTML content (default = false). Never set this parameter to true, use instead writeHTMLCell() or writeHTML() methods.
5786 * @param $autopadding (boolean) if true, uses internal padding and automatically adjust it to account for line width.
5787 * @param $maxh (float) maximum height. It should be >= $h and less then remaining space to the bottom of the page, or 0 for disable this feature. This feature works only when $ishtml=false.
5788 * @param $valign (string) Vertical alignment of text (requires $maxh = $h > 0). Possible values are:<ul><li>T: TOP</li><li>M: middle</li><li>B: bottom</li></ul>. This feature works only when $ishtml=false and the cell must fit in a single page.
5789 * @param $fitcell (boolean) if true attempt to fit all the text within the cell by reducing the font size (do not work in HTML mode). $maxh must be greater than 0 and wqual to $h.
5790 * @return int Return the number of cells or 1 for html mode.
5791 * @public
5792 * @since 1.3
5793 * @see SetFont(), SetDrawColor(), SetFillColor(), SetTextColor(), SetLineWidth(), Cell(), Write(), SetAutoPageBreak()
5794 */
5795 public function MultiCell($w, $h, $txt, $border=0, $align='J', $fill=false, $ln=1, $x='', $y='', $reseth=true, $stretch=0, $ishtml=false, $autopadding=true, $maxh=0, $valign='T', $fitcell=false) {
5796 $prev_cell_margin = $this->cell_margin;
5797 $prev_cell_padding = $this->cell_padding;
5798 // adjust internal padding
5799 $this->adjustCellPadding($border);
5800 $mc_padding = $this->cell_padding;
5801 $mc_margin = $this->cell_margin;
5802 $this->cell_padding['T'] = 0;
5803 $this->cell_padding['B'] = 0;
5804 $this->setCellMargins(0, 0, 0, 0);
5805 if (TCPDF_STATIC::empty_string($this->lasth) OR $reseth) {
5806 // reset row height
5807 $this->resetLastH();
5808 }
5809 if (!TCPDF_STATIC::empty_string($y)) {
5810 $this->SetY($y);
5811 } else {
5812 $y = $this->GetY();
5813 }
5814 $resth = 0;
5815 if (($h > 0) AND $this->inPageBody() AND (($y + $h + $mc_margin['T'] + $mc_margin['B']) > $this->PageBreakTrigger)) {
5816 // spit cell in more pages/columns
5817 $newh = ($this->PageBreakTrigger - $y);
5818 $resth = ($h - $newh); // cell to be printed on the next page/column
5819 $h = $newh;
5820 }
5821 // get current page number
5822 $startpage = $this->page;
5823 // get current column
5824 $startcolumn = $this->current_column;
5825 if (!TCPDF_STATIC::empty_string($x)) {
5826 $this->SetX($x);
5827 } else {
5828 $x = $this->GetX();
5829 }
5830 // check page for no-write regions and adapt page margins if necessary
5831 list($x, $y) = $this->checkPageRegions(0, $x, $y);
5832 // apply margins
5833 $oy = $y + $mc_margin['T'];
5834 if ($this->rtl) {
5835 $ox = ($this->w - $x - $mc_margin['R']);
5836 } else {
5837 $ox = ($x + $mc_margin['L']);
5838 }
5839 $this->x = $ox;
5840 $this->y = $oy;
5841 // set width
5842 if (TCPDF_STATIC::empty_string($w) OR ($w <= 0)) {
5843 if ($this->rtl) {
5844 $w = ($this->x - $this->lMargin - $mc_margin['L']);
5845 } else {
5846 $w = ($this->w - $this->x - $this->rMargin - $mc_margin['R']);
5847 }
5848 }
5849 // store original margin values
5850 $lMargin = $this->lMargin;
5851 $rMargin = $this->rMargin;
5852 if ($this->rtl) {
5853 $this->rMargin = ($this->w - $this->x);
5854 $this->lMargin = ($this->x - $w);
5855 } else {
5856 $this->lMargin = ($this->x);
5857 $this->rMargin = ($this->w - $this->x - $w);
5858 }
5859 $this->clMargin = $this->lMargin;
5860 $this->crMargin = $this->rMargin;
5861 if ($autopadding) {
5862 // add top padding
5863 $this->y += $mc_padding['T'];
5864 }
5865 if ($ishtml) { // ******* Write HTML text
5866 $this->writeHTML($txt, true, false, $reseth, true, $align);
5867 $nl = 1;
5868 } else { // ******* Write simple text
5869 $prev_FontSizePt = $this->FontSizePt;
5870 if ($fitcell) {
5871 // ajust height values
5872 $tobottom = ($this->h - $this->y - $this->bMargin - $this->cell_padding['T'] - $this->cell_padding['B']);
5873 $h = $maxh = max(min($h, $tobottom), min($maxh, $tobottom));
5874 }
5875 // vertical alignment
5876 if ($maxh > 0) {
5877 // get text height
5878 $text_height = $this->getStringHeight($w, $txt, $reseth, $autopadding, $mc_padding, $border);
5879 if ($fitcell AND ($text_height > $maxh) AND ($this->FontSizePt > 1)) {
5880 // try to reduce font size to fit text on cell (use a quick search algorithm)
5881 $fmin = 1;
5882 $fmax = $this->FontSizePt;
5883 $diff_epsilon = (1 / $this->k); // one point (min resolution)
5884 $maxit = (2 * min(100, max(10, intval($fmax)))); // max number of iterations
5885 while ($maxit >= 0) {
5886 $fmid = (($fmax + $fmin) / 2);
5887 $this->SetFontSize($fmid, false);
5888 $this->resetLastH();
5889 $text_height = $this->getStringHeight($w, $txt, $reseth, $autopadding, $mc_padding, $border);
5890 $diff = ($maxh - $text_height);
5891 if ($diff >= 0) {
5892 if ($diff <= $diff_epsilon) {
5893 break;
5894 }
5895 $fmin = $fmid;
5896 } else {
5897 $fmax = $fmid;
5898 }
5899 --$maxit;
5900 }
5901 if ($maxit < 0) {
5902 // premature exit, we get the minimum font value to fit the cell
5903 $this->SetFontSize($fmin);
5904 $this->resetLastH();
5905 $text_height = $this->getStringHeight($w, $txt, $reseth, $autopadding, $mc_padding, $border);
5906 } else {
5907 $this->SetFontSize($fmid);
5908 $this->resetLastH();
5909 }
5910 }
5911 if ($text_height < $maxh) {
5912 if ($valign == 'M') {
5913 // text vertically centered
5914 $this->y += (($maxh - $text_height) / 2);
5915 } elseif ($valign == 'B') {
5916 // text vertically aligned on bottom
5917 $this->y += ($maxh - $text_height);
5918 }
5919 }
5920 }
5921 $nl = $this->Write($this->lasth, $txt, '', 0, $align, true, $stretch, false, true, $maxh, 0, $mc_margin);
5922 if ($fitcell) {
5923 // restore font size
5924 $this->SetFontSize($prev_FontSizePt);
5925 }
5926 }
5927 if ($autopadding) {
5928 // add bottom padding
5929 $this->y += $mc_padding['B'];
5930 }
5931 // Get end-of-text Y position
5932 $currentY = $this->y;
5933 // get latest page number
5934 $endpage = $this->page;
5935 if ($resth > 0) {
5936 $skip = ($endpage - $startpage);
5937 $tmpresth = $resth;
5938 while ($tmpresth > 0) {
5939 if ($skip <= 0) {
5940 // add a page (or trig AcceptPageBreak() for multicolumn mode)
5941 $this->checkPageBreak($this->PageBreakTrigger + 1);
5942 }
5943 if ($this->num_columns > 1) {
5944 $tmpresth -= ($this->h - $this->y - $this->bMargin);
5945 } else {
5946 $tmpresth -= ($this->h - $this->tMargin - $this->bMargin);
5947 }
5948 --$skip;
5949 }
5950 $currentY = $this->y;
5951 $endpage = $this->page;
5952 }
5953 // get latest column
5954 $endcolumn = $this->current_column;
5955 if ($this->num_columns == 0) {
5956 $this->num_columns = 1;
5957 }
5958 // disable page regions check
5959 $check_page_regions = $this->check_page_regions;
5960 $this->check_page_regions = false;
5961 // get border modes
5962 $border_start = TCPDF_STATIC::getBorderMode($border, $position='start', $this->opencell);
5963 $border_end = TCPDF_STATIC::getBorderMode($border, $position='end', $this->opencell);
5964 $border_middle = TCPDF_STATIC::getBorderMode($border, $position='middle', $this->opencell);
5965 // design borders around HTML cells.
5966 for ($page = $startpage; $page <= $endpage; ++$page) { // for each page
5967 $ccode = '';
5968 $this->setPage($page);
5969 if ($this->num_columns < 2) {
5970 // single-column mode
5971 $this->SetX($x);
5972 $this->y = $this->tMargin;
5973 }
5974 // account for margin changes
5975 if ($page > $startpage) {
5976 if (($this->rtl) AND ($this->pagedim[$page]['orm'] != $this->pagedim[$startpage]['orm'])) {
5977 $this->x -= ($this->pagedim[$page]['orm'] - $this->pagedim[$startpage]['orm']);
5978 } elseif ((!$this->rtl) AND ($this->pagedim[$page]['olm'] != $this->pagedim[$startpage]['olm'])) {
5979 $this->x += ($this->pagedim[$page]['olm'] - $this->pagedim[$startpage]['olm']);
5980 }
5981 }
5982 if ($startpage == $endpage) {
5983 // single page
5984 for ($column = $startcolumn; $column <= $endcolumn; ++$column) { // for each column
5985 $this->selectColumn($column);
5986 if ($this->rtl) {
5987 $this->x -= $mc_margin['R'];
5988 } else {
5989 $this->x += $mc_margin['L'];
5990 }
5991 if ($startcolumn == $endcolumn) { // single column
5992 $cborder = $border;
5993 $h = max($h, ($currentY - $oy));
5994 $this->y = $oy;
5995 } elseif ($column == $startcolumn) { // first column
5996 $cborder = $border_start;
5997 $this->y = $oy;
5998 $h = $this->h - $this->y - $this->bMargin;
5999 } elseif ($column == $endcolumn) { // end column
6000 $cborder = $border_end;
6001 $h = $currentY - $this->y;
6002 if ($resth > $h) {
6003 $h = $resth;
6004 }
6005 } else { // middle column
6006 $cborder = $border_middle;
6007 $h = $this->h - $this->y - $this->bMargin;
6008 $resth -= $h;
6009 }
6010 $ccode .= $this->getCellCode($w, $h, '', $cborder, 1, '', $fill, '', 0, true)."\n";
6011 } // end for each column
6012 } elseif ($page == $startpage) { // first page
6013 for ($column = $startcolumn; $column < $this->num_columns; ++$column) { // for each column
6014 $this->selectColumn($column);
6015 if ($this->rtl) {
6016 $this->x -= $mc_margin['R'];
6017 } else {
6018 $this->x += $mc_margin['L'];
6019 }
6020 if ($column == $startcolumn) { // first column
6021 $cborder = $border_start;
6022 $this->y = $oy;
6023 $h = $this->h - $this->y - $this->bMargin;
6024 } else { // middle column
6025 $cborder = $border_middle;
6026 $h = $this->h - $this->y - $this->bMargin;
6027 $resth -= $h;
6028 }
6029 $ccode .= $this->getCellCode($w, $h, '', $cborder, 1, '', $fill, '', 0, true)."\n";
6030 } // end for each column
6031 } elseif ($page == $endpage) { // last page
6032 for ($column = 0; $column <= $endcolumn; ++$column) { // for each column
6033 $this->selectColumn($column);
6034 if ($this->rtl) {
6035 $this->x -= $mc_margin['R'];
6036 } else {
6037 $this->x += $mc_margin['L'];
6038 }
6039 if ($column == $endcolumn) {
6040 // end column
6041 $cborder = $border_end;
6042 $h = $currentY - $this->y;
6043 if ($resth > $h) {
6044 $h = $resth;
6045 }
6046 } else {
6047 // middle column
6048 $cborder = $border_middle;
6049 $h = $this->h - $this->y - $this->bMargin;
6050 $resth -= $h;
6051 }
6052 $ccode .= $this->getCellCode($w, $h, '', $cborder, 1, '', $fill, '', 0, true)."\n";
6053 } // end for each column
6054 } else { // middle page
6055 for ($column = 0; $column < $this->num_columns; ++$column) { // for each column
6056 $this->selectColumn($column);
6057 if ($this->rtl) {
6058 $this->x -= $mc_margin['R'];
6059 } else {
6060 $this->x += $mc_margin['L'];
6061 }
6062 $cborder = $border_middle;
6063 $h = $this->h - $this->y - $this->bMargin;
6064 $resth -= $h;
6065 $ccode .= $this->getCellCode($w, $h, '', $cborder, 1, '', $fill, '', 0, true)."\n";
6066 } // end for each column
6067 }
6068 if ($cborder OR $fill) {
6069 $offsetlen = strlen($ccode);
6070 // draw border and fill
6071 if ($this->inxobj) {
6072 // we are inside an XObject template
6073 if (end($this->xobjects[$this->xobjid]['transfmrk']) !== false) {
6074 $pagemarkkey = key($this->xobjects[$this->xobjid]['transfmrk']);
6075 $pagemark = $this->xobjects[$this->xobjid]['transfmrk'][$pagemarkkey];
6076 $this->xobjects[$this->xobjid]['transfmrk'][$pagemarkkey] += $offsetlen;
6077 } else {
6078 $pagemark = $this->xobjects[$this->xobjid]['intmrk'];
6079 $this->xobjects[$this->xobjid]['intmrk'] += $offsetlen;
6080 }
6081 $pagebuff = $this->xobjects[$this->xobjid]['outdata'];
6082 $pstart = substr($pagebuff, 0, $pagemark);
6083 $pend = substr($pagebuff, $pagemark);
6084 $this->xobjects[$this->xobjid]['outdata'] = $pstart.$ccode.$pend;
6085 } else {
6086 if (end($this->transfmrk[$this->page]) !== false) {
6087 $pagemarkkey = key($this->transfmrk[$this->page]);
6088 $pagemark = $this->transfmrk[$this->page][$pagemarkkey];
6089 $this->transfmrk[$this->page][$pagemarkkey] += $offsetlen;
6090 } elseif ($this->InFooter) {
6091 $pagemark = $this->footerpos[$this->page];
6092 $this->footerpos[$this->page] += $offsetlen;
6093 } else {
6094 $pagemark = $this->intmrk[$this->page];
6095 $this->intmrk[$this->page] += $offsetlen;
6096 }
6097 $pagebuff = $this->getPageBuffer($this->page);
6098 $pstart = substr($pagebuff, 0, $pagemark);
6099 $pend = substr($pagebuff, $pagemark);
6100 $this->setPageBuffer($this->page, $pstart.$ccode.$pend);
6101 }
6102 }
6103 } // end for each page
6104 // restore page regions check
6105 $this->check_page_regions = $check_page_regions;
6106 // Get end-of-cell Y position
6107 $currentY = $this->GetY();
6108 // restore previous values
6109 if ($this->num_columns > 1) {
6110 $this->selectColumn();
6111 } else {
6112 // restore original margins
6113 $this->lMargin = $lMargin;
6114 $this->rMargin = $rMargin;
6115 if ($this->page > $startpage) {
6116 // check for margin variations between pages (i.e. booklet mode)
6117 $dl = ($this->pagedim[$this->page]['olm'] - $this->pagedim[$startpage]['olm']);
6118 $dr = ($this->pagedim[$this->page]['orm'] - $this->pagedim[$startpage]['orm']);
6119 if (($dl != 0) OR ($dr != 0)) {
6120 $this->lMargin += $dl;
6121 $this->rMargin += $dr;
6122 }
6123 }
6124 }
6125 if ($ln > 0) {
6126 //Go to the beginning of the next line
6127 $this->SetY($currentY + $mc_margin['B']);
6128 if ($ln == 2) {
6129 $this->SetX($x + $w + $mc_margin['L'] + $mc_margin['R']);
6130 }
6131 } else {
6132 // go left or right by case
6133 $this->setPage($startpage);
6134 $this->y = $y;
6135 $this->SetX($x + $w + $mc_margin['L'] + $mc_margin['R']);
6136 }
6137 $this->setContentMark();
6138 $this->cell_padding = $prev_cell_padding;
6139 $this->cell_margin = $prev_cell_margin;
6140 $this->clMargin = $this->lMargin;
6141 $this->crMargin = $this->rMargin;
6142 return $nl;
6143 }
6144
6145 /**
6146 * This method return the estimated number of lines for print a simple text string using Multicell() method.
6147 * @param $txt (string) String for calculating his height
6148 * @param $w (float) Width of cells. If 0, they extend up to the right margin of the page.
6149 * @param $reseth (boolean) if true reset the last cell height (default false).
6150 * @param $autopadding (boolean) if true, uses internal padding and automatically adjust it to account for line width (default true).
6151 * @param $cellpadding (float) Internal cell padding, if empty uses default cell padding.
6152 * @param $border (mixed) Indicates if borders must be drawn around the cell. 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 - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0)))
6153 * @return float Return the minimal height needed for multicell method for printing the $txt param.
6154 * @author Alexander Escalona Fern\E1ndez, Nicola Asuni
6155 * @public
6156 * @since 4.5.011
6157 */
6158 public function getNumLines($txt, $w=0, $reseth=false, $autopadding=true, $cellpadding='', $border=0) {
6159 if ($txt === NULL) {
6160 return 0;
6161 }
6162 if ($txt === '') {
6163 // empty string
6164 return 1;
6165 }
6166 // adjust internal padding
6167 $prev_cell_padding = $this->cell_padding;
6168 $prev_lasth = $this->lasth;
6169 if (is_array($cellpadding)) {
6170 $this->cell_padding = $cellpadding;
6171 }
6172 $this->adjustCellPadding($border);
6173 if (TCPDF_STATIC::empty_string($w) OR ($w <= 0)) {
6174 if ($this->rtl) {
6175 $w = $this->x - $this->lMargin;
6176 } else {
6177 $w = $this->w - $this->rMargin - $this->x;
6178 }
6179 }
6180 $wmax = $w - $this->cell_padding['L'] - $this->cell_padding['R'];
6181 if ($reseth) {
6182 // reset row height
6183 $this->resetLastH();
6184 }
6185 $lines = 1;
6186 $sum = 0;
6187 $chars = TCPDF_FONTS::utf8Bidi(TCPDF_FONTS::UTF8StringToArray($txt, $this->isunicode, $this->CurrentFont), $txt, $this->tmprtl, $this->isunicode, $this->CurrentFont);
6188 $charsWidth = $this->GetArrStringWidth($chars, '', '', 0, true);
6189 $length = count($chars);
6190 $lastSeparator = -1;
6191 for ($i = 0; $i < $length; ++$i) {
6192 $c = $chars[$i];
6193 $charWidth = $charsWidth[$i];
6194 if (($c != 160)
6195 AND (($c == 173)
6196 OR preg_match($this->re_spaces, TCPDF_FONTS::unichr($c, $this->isunicode))
6197 OR (($c == 45)
6198 AND ($i > 0) AND ($i < ($length - 1))
6199 AND @preg_match('/[\p{L}]/'.$this->re_space['m'], TCPDF_FONTS::unichr($chars[($i - 1)], $this->isunicode))
6200 AND @preg_match('/[\p{L}]/'.$this->re_space['m'], TCPDF_FONTS::unichr($chars[($i + 1)], $this->isunicode))
6201 )
6202 )
6203 ) {
6204 $lastSeparator = $i;
6205 }
6206 if ((($sum + $charWidth) > $wmax) OR ($c == 10)) {
6207 ++$lines;
6208 if ($c == 10) {
6209 $lastSeparator = -1;
6210 $sum = 0;
6211 } elseif ($lastSeparator != -1) {
6212 $i = $lastSeparator;
6213 $lastSeparator = -1;
6214 $sum = 0;
6215 } else {
6216 $sum = $charWidth;
6217 }
6218 } else {
6219 $sum += $charWidth;
6220 }
6221 }
6222 if ($chars[($length - 1)] == 10) {
6223 --$lines;
6224 }
6225 $this->cell_padding = $prev_cell_padding;
6226 $this->lasth = $prev_lasth;
6227 return $lines;
6228 }
6229
6230 /**
6231 * This method return the estimated height needed for printing a simple text string using the Multicell() method.
6232 * Generally, if you want to know the exact height for a block of content you can use the following alternative technique:
6233 * @pre
6234 * // store current object
6235 * $pdf->startTransaction();
6236 * // store starting values
6237 * $start_y = $pdf->GetY();
6238 * $start_page = $pdf->getPage();
6239 * // call your printing functions with your parameters
6240 * // - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
6241 * $pdf->MultiCell($w=0, $h=0, $txt, $border=1, $align='L', $fill=false, $ln=1, $x='', $y='', $reseth=true, $stretch=0, $ishtml=false, $autopadding=true, $maxh=0);
6242 * // - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
6243 * // get the new Y
6244 * $end_y = $pdf->GetY();
6245 * $end_page = $pdf->getPage();
6246 * // calculate height
6247 * $height = 0;
6248 * if ($end_page == $start_page) {
6249 * $height = $end_y - $start_y;
6250 * } else {
6251 * for ($page=$start_page; $page <= $end_page; ++$page) {
6252 * $this->setPage($page);
6253 * if ($page == $start_page) {
6254 * // first page
6255 * $height = $this->h - $start_y - $this->bMargin;
6256 * } elseif ($page == $end_page) {
6257 * // last page
6258 * $height = $end_y - $this->tMargin;
6259 * } else {
6260 * $height = $this->h - $this->tMargin - $this->bMargin;
6261 * }
6262 * }
6263 * }
6264 * // restore previous object
6265 * $pdf = $pdf->rollbackTransaction();
6266 *
6267 * @param $w (float) Width of cells. If 0, they extend up to the right margin of the page.
6268 * @param $txt (string) String for calculating his height
6269 * @param $reseth (boolean) if true reset the last cell height (default false).
6270 * @param $autopadding (boolean) if true, uses internal padding and automatically adjust it to account for line width (default true).
6271 * @param $cellpadding (float) Internal cell padding, if empty uses default cell padding.
6272 * @param $border (mixed) Indicates if borders must be drawn around the cell. 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 - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0)))
6273 * @return float Return the minimal height needed for multicell method for printing the $txt param.
6274 * @author Nicola Asuni, Alexander Escalona Fern\E1ndez
6275 * @public
6276 */
6277 public function getStringHeight($w, $txt, $reseth=false, $autopadding=true, $cellpadding='', $border=0) {
6278 // adjust internal padding
6279 $prev_cell_padding = $this->cell_padding;
6280 $prev_lasth = $this->lasth;
6281 if (is_array($cellpadding)) {
6282 $this->cell_padding = $cellpadding;
6283 }
6284 $this->adjustCellPadding($border);
6285 $lines = $this->getNumLines($txt, $w, $reseth, $autopadding, $cellpadding, $border);
6286 $height = $this->getCellHeight(($lines * $this->FontSize), $autopadding);
6287 $this->cell_padding = $prev_cell_padding;
6288 $this->lasth = $prev_lasth;
6289 return $height;
6290 }
6291
6292 /**
6293 * This method prints text from the current position.<br />
6294 * @param $h (float) Line height
6295 * @param $txt (string) String to print
6296 * @param $link (mixed) URL or identifier returned by AddLink()
6297 * @param $fill (boolean) Indicates if the cell background must be painted (true) or transparent (false).
6298 * @param $align (string) Allows to center or align the text. Possible values are:<ul><li>L or empty string: left align (default value)</li><li>C: center</li><li>R: right align</li><li>J: justify</li></ul>
6299 * @param $ln (boolean) if true set cursor at the bottom of the line, otherwise set cursor at the top of the line.
6300 * @param $stretch (int) font stretch mode: <ul><li>0 = disabled</li><li>1 = horizontal scaling only if text is larger than cell width</li><li>2 = forced horizontal scaling to fit cell width</li><li>3 = character spacing only if text is larger than cell width</li><li>4 = forced character spacing to fit cell width</li></ul> General font stretching and scaling values will be preserved when possible.
6301 * @param $firstline (boolean) if true prints only the first line and return the remaining string.
6302 * @param $firstblock (boolean) if true the string is the starting of a line.
6303 * @param $maxh (float) maximum height. It should be >= $h and less then remaining space to the bottom of the page, or 0 for disable this feature.
6304 * @param $wadj (float) first line width will be reduced by this amount (used in HTML mode).
6305 * @param $margin (array) margin array of the parent container
6306 * @return mixed Return the number of cells or the remaining string if $firstline = true.
6307 * @public
6308 * @since 1.5
6309 */
6310 public function Write($h, $txt, $link='', $fill=false, $align='', $ln=false, $stretch=0, $firstline=false, $firstblock=false, $maxh=0, $wadj=0, $margin='') {
6311 // check page for no-write regions and adapt page margins if necessary
6312 list($this->x, $this->y) = $this->checkPageRegions($h, $this->x, $this->y);
6313 if (strlen($txt) == 0) {
6314 // fix empty text
6315 $txt = ' ';
6316 }
6317 if ($margin === '') {
6318 // set default margins
6319 $margin = $this->cell_margin;
6320 }
6321 // remove carriage returns
6322 $s = str_replace("\r", '', $txt);
6323 // check if string contains arabic text
6324 if (preg_match(TCPDF_FONT_DATA::$uni_RE_PATTERN_ARABIC, $s)) {
6325 $arabic = true;
6326 } else {
6327 $arabic = false;
6328 }
6329 // check if string contains RTL text
6330 if ($arabic OR ($this->tmprtl == 'R') OR preg_match(TCPDF_FONT_DATA::$uni_RE_PATTERN_RTL, $s)) {
6331 $rtlmode = true;
6332 } else {
6333 $rtlmode = false;
6334 }
6335 // get a char width
6336 $chrwidth = $this->GetCharWidth(46); // dot character
6337 // get array of unicode values
6338 $chars = TCPDF_FONTS::UTF8StringToArray($s, $this->isunicode, $this->CurrentFont);
6339 // calculate maximum width for a single character on string
6340 $chrw = $this->GetArrStringWidth($chars, '', '', 0, true);
6341 array_walk($chrw, array($this, 'getRawCharWidth'));
6342 $maxchwidth = max($chrw);
6343 // get array of chars
6344 $uchars = TCPDF_FONTS::UTF8ArrayToUniArray($chars, $this->isunicode);
6345 // get the number of characters
6346 $nb = count($chars);
6347 // replacement for SHY character (minus symbol)
6348 $shy_replacement = 45;
6349 $shy_replacement_char = TCPDF_FONTS::unichr($shy_replacement, $this->isunicode);
6350 // widht for SHY replacement
6351 $shy_replacement_width = $this->GetCharWidth($shy_replacement);
6352 // page width
6353 $pw = $w = $this->w - $this->lMargin - $this->rMargin;
6354 // calculate remaining line width ($w)
6355 if ($this->rtl) {
6356 $w = $this->x - $this->lMargin;
6357 } else {
6358 $w = $this->w - $this->rMargin - $this->x;
6359 }
6360 // max column width
6361 $wmax = ($w - $wadj);
6362 if (!$firstline) {
6363 $wmax -= ($this->cell_padding['L'] + $this->cell_padding['R']);
6364 }
6365 if ((!$firstline) AND (($chrwidth > $wmax) OR ($maxchwidth > $wmax))) {
6366 // the maximum width character do not fit on column
6367 return '';
6368 }
6369 // minimum row height
6370 $row_height = max($h, $this->getCellHeight($this->FontSize));
6371 // max Y
6372 $maxy = $this->y + $maxh - max($row_height, $h);
6373 $start_page = $this->page;
6374 $i = 0; // character position
6375 $j = 0; // current starting position
6376 $sep = -1; // position of the last blank space
6377 $prevsep = $sep; // previous separator
6378 $shy = false; // true if the last blank is a soft hypen (SHY)
6379 $prevshy = $shy; // previous shy mode
6380 $l = 0; // current string length
6381 $nl = 0; //number of lines
6382 $linebreak = false;
6383 $pc = 0; // previous character
6384 // for each character
6385 while ($i < $nb) {
6386 if (($maxh > 0) AND ($this->y > $maxy) ) {
6387 break;
6388 }
6389 //Get the current character
6390 $c = $chars[$i];
6391 if ($c == 10) { // 10 = "\n" = new line
6392 //Explicit line break
6393 if ($align == 'J') {
6394 if ($this->rtl) {
6395 $talign = 'R';
6396 } else {
6397 $talign = 'L';
6398 }
6399 } else {
6400 $talign = $align;
6401 }
6402 $tmpstr = TCPDF_FONTS::UniArrSubString($uchars, $j, $i);
6403 if ($firstline) {
6404 $startx = $this->x;
6405 $tmparr = array_slice($chars, $j, ($i - $j));
6406 if ($rtlmode) {
6407 $tmparr = TCPDF_FONTS::utf8Bidi($tmparr, $tmpstr, $this->tmprtl, $this->isunicode, $this->CurrentFont);
6408 }
6409 $linew = $this->GetArrStringWidth($tmparr);
6410 unset($tmparr);
6411 if ($this->rtl) {
6412 $this->endlinex = $startx - $linew;
6413 } else {
6414 $this->endlinex = $startx + $linew;
6415 }
6416 $w = $linew;
6417 $tmpcellpadding = $this->cell_padding;
6418 if ($maxh == 0) {
6419 $this->SetCellPadding(0);
6420 }
6421 }
6422 if ($firstblock AND $this->isRTLTextDir()) {
6423 $tmpstr = $this->stringRightTrim($tmpstr);
6424 }
6425 // Skip newlines at the begining of a page or column
6426 if (!empty($tmpstr) OR ($this->y < ($this->PageBreakTrigger - $row_height))) {
6427 $this->Cell($w, $h, $tmpstr, 0, 1, $talign, $fill, $link, $stretch);
6428 }
6429 unset($tmpstr);
6430 if ($firstline) {
6431 $this->cell_padding = $tmpcellpadding;
6432 return (TCPDF_FONTS::UniArrSubString($uchars, $i));
6433 }
6434 ++$nl;
6435 $j = $i + 1;
6436 $l = 0;
6437 $sep = -1;
6438 $prevsep = $sep;
6439 $shy = false;
6440 // account for margin changes
6441 if ((($this->y + $this->lasth) > $this->PageBreakTrigger) AND ($this->inPageBody())) {
6442 $this->AcceptPageBreak();
6443 if ($this->rtl) {
6444 $this->x -= $margin['R'];
6445 } else {
6446 $this->x += $margin['L'];
6447 }
6448 $this->lMargin += $margin['L'];
6449 $this->rMargin += $margin['R'];
6450 }
6451 $w = $this->getRemainingWidth();
6452 $wmax = ($w - $this->cell_padding['L'] - $this->cell_padding['R']);
6453 } else {
6454 // 160 is the non-breaking space.
6455 // 173 is SHY (Soft Hypen).
6456 // \p{Z} or \p{Separator}: any kind of Unicode whitespace or invisible separator.
6457 // \p{Lo} or \p{Other_Letter}: a Unicode letter or ideograph that does not have lowercase and uppercase variants.
6458 // \p{Lo} is needed because Chinese characters are packed next to each other without spaces in between.
6459 if (($c != 160)
6460 AND (($c == 173)
6461 OR preg_match($this->re_spaces, TCPDF_FONTS::unichr($c, $this->isunicode))
6462 OR (($c == 45)
6463 AND ($i < ($nb - 1))
6464 AND @preg_match('/[\p{L}]/'.$this->re_space['m'], TCPDF_FONTS::unichr($pc, $this->isunicode))
6465 AND @preg_match('/[\p{L}]/'.$this->re_space['m'], TCPDF_FONTS::unichr($chars[($i + 1)], $this->isunicode))
6466 )
6467 )
6468 ) {
6469 // update last blank space position
6470 $prevsep = $sep;
6471 $sep = $i;
6472 // check if is a SHY
6473 if (($c == 173) OR ($c == 45)) {
6474 $prevshy = $shy;
6475 $shy = true;
6476 if ($pc == 45) {
6477 $tmp_shy_replacement_width = 0;
6478 $tmp_shy_replacement_char = '';
6479 } else {
6480 $tmp_shy_replacement_width = $shy_replacement_width;
6481 $tmp_shy_replacement_char = $shy_replacement_char;
6482 }
6483 } else {
6484 $shy = false;
6485 }
6486 }
6487 // update string length
6488 if ($this->isUnicodeFont() AND ($arabic)) {
6489 // with bidirectional algorithm some chars may be changed affecting the line length
6490 // *** very slow ***
6491 $l = $this->GetArrStringWidth(TCPDF_FONTS::utf8Bidi(array_slice($chars, $j, ($i - $j)), '', $this->tmprtl, $this->isunicode, $this->CurrentFont));
6492 } else {
6493 $l += $this->GetCharWidth($c);
6494 }
6495 if (($l > $wmax) OR (($c == 173) AND (($l + $tmp_shy_replacement_width) >= $wmax))) {
6496 if (($c == 173) AND (($l + $tmp_shy_replacement_width) > $wmax)) {
6497 $sep = $prevsep;
6498 $shy = $prevshy;
6499 }
6500 // we have reached the end of column
6501 if ($sep == -1) {
6502 // check if the line was already started
6503 if (($this->rtl AND ($this->x <= ($this->w - $this->rMargin - $this->cell_padding['R'] - $margin['R'] - $chrwidth)))
6504 OR ((!$this->rtl) AND ($this->x >= ($this->lMargin + $this->cell_padding['L'] + $margin['L'] + $chrwidth)))) {
6505 // print a void cell and go to next line
6506 $this->Cell($w, $h, '', 0, 1);
6507 $linebreak = true;
6508 if ($firstline) {
6509 return (TCPDF_FONTS::UniArrSubString($uchars, $j));
6510 }
6511 } else {
6512 // truncate the word because do not fit on column
6513 $tmpstr = TCPDF_FONTS::UniArrSubString($uchars, $j, $i);
6514 if ($firstline) {
6515 $startx = $this->x;
6516 $tmparr = array_slice($chars, $j, ($i - $j));
6517 if ($rtlmode) {
6518 $tmparr = TCPDF_FONTS::utf8Bidi($tmparr, $tmpstr, $this->tmprtl, $this->isunicode, $this->CurrentFont);
6519 }
6520 $linew = $this->GetArrStringWidth($tmparr);
6521 unset($tmparr);
6522 if ($this->rtl) {
6523 $this->endlinex = $startx - $linew;
6524 } else {
6525 $this->endlinex = $startx + $linew;
6526 }
6527 $w = $linew;
6528 $tmpcellpadding = $this->cell_padding;
6529 if ($maxh == 0) {
6530 $this->SetCellPadding(0);
6531 }
6532 }
6533 if ($firstblock AND $this->isRTLTextDir()) {
6534 $tmpstr = $this->stringRightTrim($tmpstr);
6535 }
6536 $this->Cell($w, $h, $tmpstr, 0, 1, $align, $fill, $link, $stretch);
6537 unset($tmpstr);
6538 if ($firstline) {
6539 $this->cell_padding = $tmpcellpadding;
6540 return (TCPDF_FONTS::UniArrSubString($uchars, $i));
6541 }
6542 $j = $i;
6543 --$i;
6544 }
6545 } else {
6546 // word wrapping
6547 if ($this->rtl AND (!$firstblock) AND ($sep < $i)) {
6548 $endspace = 1;
6549 } else {
6550 $endspace = 0;
6551 }
6552 // check the length of the next string
6553 $strrest = TCPDF_FONTS::UniArrSubString($uchars, ($sep + $endspace));
6554 $nextstr = TCPDF_STATIC::pregSplit('/'.$this->re_space['p'].'/', $this->re_space['m'], $this->stringTrim($strrest));
6555 if (isset($nextstr[0]) AND ($this->GetStringWidth($nextstr[0]) > $pw)) {
6556 // truncate the word because do not fit on a full page width
6557 $tmpstr = TCPDF_FONTS::UniArrSubString($uchars, $j, $i);
6558 if ($firstline) {
6559 $startx = $this->x;
6560 $tmparr = array_slice($chars, $j, ($i - $j));
6561 if ($rtlmode) {
6562 $tmparr = TCPDF_FONTS::utf8Bidi($tmparr, $tmpstr, $this->tmprtl, $this->isunicode, $this->CurrentFont);
6563 }
6564 $linew = $this->GetArrStringWidth($tmparr);
6565 unset($tmparr);
6566 if ($this->rtl) {
6567 $this->endlinex = ($startx - $linew);
6568 } else {
6569 $this->endlinex = ($startx + $linew);
6570 }
6571 $w = $linew;
6572 $tmpcellpadding = $this->cell_padding;
6573 if ($maxh == 0) {
6574 $this->SetCellPadding(0);
6575 }
6576 }
6577 if ($firstblock AND $this->isRTLTextDir()) {
6578 $tmpstr = $this->stringRightTrim($tmpstr);
6579 }
6580 $this->Cell($w, $h, $tmpstr, 0, 1, $align, $fill, $link, $stretch);
6581 unset($tmpstr);
6582 if ($firstline) {
6583 $this->cell_padding = $tmpcellpadding;
6584 return (TCPDF_FONTS::UniArrSubString($uchars, $i));
6585 }
6586 $j = $i;
6587 --$i;
6588 } else {
6589 // word wrapping
6590 if ($shy) {
6591 // add hypen (minus symbol) at the end of the line
6592 $shy_width = $tmp_shy_replacement_width;
6593 if ($this->rtl) {
6594 $shy_char_left = $tmp_shy_replacement_char;
6595 $shy_char_right = '';
6596 } else {
6597 $shy_char_left = '';
6598 $shy_char_right = $tmp_shy_replacement_char;
6599 }
6600 } else {
6601 $shy_width = 0;
6602 $shy_char_left = '';
6603 $shy_char_right = '';
6604 }
6605 $tmpstr = TCPDF_FONTS::UniArrSubString($uchars, $j, ($sep + $endspace));
6606 if ($firstline) {
6607 $startx = $this->x;
6608 $tmparr = array_slice($chars, $j, (($sep + $endspace) - $j));
6609 if ($rtlmode) {
6610 $tmparr = TCPDF_FONTS::utf8Bidi($tmparr, $tmpstr, $this->tmprtl, $this->isunicode, $this->CurrentFont);
6611 }
6612 $linew = $this->GetArrStringWidth($tmparr);
6613 unset($tmparr);
6614 if ($this->rtl) {
6615 $this->endlinex = $startx - $linew - $shy_width;
6616 } else {
6617 $this->endlinex = $startx + $linew + $shy_width;
6618 }
6619 $w = $linew;
6620 $tmpcellpadding = $this->cell_padding;
6621 if ($maxh == 0) {
6622 $this->SetCellPadding(0);
6623 }
6624 }
6625 // print the line
6626 if ($firstblock AND $this->isRTLTextDir()) {
6627 $tmpstr = $this->stringRightTrim($tmpstr);
6628 }
6629 $this->Cell($w, $h, $shy_char_left.$tmpstr.$shy_char_right, 0, 1, $align, $fill, $link, $stretch);
6630 unset($tmpstr);
6631 if ($firstline) {
6632 if ($chars[$sep] == 45) {
6633 $endspace += 1;
6634 }
6635 // return the remaining text
6636 $this->cell_padding = $tmpcellpadding;
6637 return (TCPDF_FONTS::UniArrSubString($uchars, ($sep + $endspace)));
6638 }
6639 $i = $sep;
6640 $sep = -1;
6641 $shy = false;
6642 $j = ($i + 1);
6643 }
6644 }
6645 // account for margin changes
6646 if ((($this->y + $this->lasth) > $this->PageBreakTrigger) AND ($this->inPageBody())) {
6647 $this->AcceptPageBreak();
6648 if ($this->rtl) {
6649 $this->x -= $margin['R'];
6650 } else {
6651 $this->x += $margin['L'];
6652 }
6653 $this->lMargin += $margin['L'];
6654 $this->rMargin += $margin['R'];
6655 }
6656 $w = $this->getRemainingWidth();
6657 $wmax = $w - $this->cell_padding['L'] - $this->cell_padding['R'];
6658 if ($linebreak) {
6659 $linebreak = false;
6660 } else {
6661 ++$nl;
6662 $l = 0;
6663 }
6664 }
6665 }
6666 // save last character
6667 $pc = $c;
6668 ++$i;
6669 } // end while i < nb
6670 // print last substring (if any)
6671 if ($l > 0) {
6672 switch ($align) {
6673 case 'J':
6674 case 'C': {
6675 $w = $w;
6676 break;
6677 }
6678 case 'L': {
6679 if ($this->rtl) {
6680 $w = $w;
6681 } else {
6682 $w = $l;
6683 }
6684 break;
6685 }
6686 case 'R': {
6687 if ($this->rtl) {
6688 $w = $l;
6689 } else {
6690 $w = $w;
6691 }
6692 break;
6693 }
6694 default: {
6695 $w = $l;
6696 break;
6697 }
6698 }
6699 $tmpstr = TCPDF_FONTS::UniArrSubString($uchars, $j, $nb);
6700 if ($firstline) {
6701 $startx = $this->x;
6702 $tmparr = array_slice($chars, $j, ($nb - $j));
6703 if ($rtlmode) {
6704 $tmparr = TCPDF_FONTS::utf8Bidi($tmparr, $tmpstr, $this->tmprtl, $this->isunicode, $this->CurrentFont);
6705 }
6706 $linew = $this->GetArrStringWidth($tmparr);
6707 unset($tmparr);
6708 if ($this->rtl) {
6709 $this->endlinex = $startx - $linew;
6710 } else {
6711 $this->endlinex = $startx + $linew;
6712 }
6713 $w = $linew;
6714 $tmpcellpadding = $this->cell_padding;
6715 if ($maxh == 0) {
6716 $this->SetCellPadding(0);
6717 }
6718 }
6719 if ($firstblock AND $this->isRTLTextDir()) {
6720 $tmpstr = $this->stringRightTrim($tmpstr);
6721 }
6722 $this->Cell($w, $h, $tmpstr, 0, $ln, $align, $fill, $link, $stretch);
6723 unset($tmpstr);
6724 if ($firstline) {
6725 $this->cell_padding = $tmpcellpadding;
6726 return (TCPDF_FONTS::UniArrSubString($uchars, $nb));
6727 }
6728 ++$nl;
6729 }
6730 if ($firstline) {
6731 return '';
6732 }
6733 return $nl;
6734 }
6735
6736 /**
6737 * Returns the remaining width between the current position and margins.
6738 * @return int Return the remaining width
6739 * @protected
6740 */
6741 protected function getRemainingWidth() {
6742 list($this->x, $this->y) = $this->checkPageRegions(0, $this->x, $this->y);
6743 if ($this->rtl) {
6744 return ($this->x - $this->lMargin);
6745 } else {
6746 return ($this->w - $this->rMargin - $this->x);
6747 }
6748 }
6749
6750 /**
6751 * Set the block dimensions accounting for page breaks and page/column fitting
6752 * @param $w (float) width
6753 * @param $h (float) height
6754 * @param $x (float) X coordinate
6755 * @param $y (float) Y coodiante
6756 * @param $fitonpage (boolean) if true the block is resized to not exceed page dimensions.
6757 * @return array($w, $h, $x, $y)
6758 * @protected
6759 * @since 5.5.009 (2010-07-05)
6760 */
6761 protected function fitBlock($w, $h, $x, $y, $fitonpage=false) {
6762 if ($w <= 0) {
6763 // set maximum width
6764 $w = ($this->w - $this->lMargin - $this->rMargin);
6765 if ($w <= 0) {
6766 $w = 1;
6767 }
6768 }
6769 if ($h <= 0) {
6770 // set maximum height
6771 $h = ($this->PageBreakTrigger - $this->tMargin);
6772 if ($h <= 0) {
6773 $h = 1;
6774 }
6775 }
6776 // resize the block to be vertically contained on a single page or single column
6777 if ($fitonpage OR $this->AutoPageBreak) {
6778 $ratio_wh = ($w / $h);
6779 if ($h > ($this->PageBreakTrigger - $this->tMargin)) {
6780 $h = $this->PageBreakTrigger - $this->tMargin;
6781 $w = ($h * $ratio_wh);
6782 }
6783 // resize the block to be horizontally contained on a single page or single column
6784 if ($fitonpage) {
6785 $maxw = ($this->w - $this->lMargin - $this->rMargin);
6786 if ($w > $maxw) {
6787 $w = $maxw;
6788 $h = ($w / $ratio_wh);
6789 }
6790 }
6791 }
6792 // Check whether we need a new page or new column first as this does not fit
6793 $prev_x = $this->x;
6794 $prev_y = $this->y;
6795 if ($this->checkPageBreak($h, $y) OR ($this->y < $prev_y)) {
6796 $y = $this->y;
6797 if ($this->rtl) {
6798 $x += ($prev_x - $this->x);
6799 } else {
6800 $x += ($this->x - $prev_x);
6801 }
6802 $this->newline = true;
6803 }
6804 // resize the block to be contained on the remaining available page or column space
6805 if ($fitonpage) {
6806 $ratio_wh = ($w / $h);
6807 if (($y + $h) > $this->PageBreakTrigger) {
6808 $h = $this->PageBreakTrigger - $y;
6809 $w = ($h * $ratio_wh);
6810 }
6811 if ((!$this->rtl) AND (($x + $w) > ($this->w - $this->rMargin))) {
6812 $w = $this->w - $this->rMargin - $x;
6813 $h = ($w / $ratio_wh);
6814 } elseif (($this->rtl) AND (($x - $w) < ($this->lMargin))) {
6815 $w = $x - $this->lMargin;
6816 $h = ($w / $ratio_wh);
6817 }
6818 }
6819 return array($w, $h, $x, $y);
6820 }
6821
6822 /**
6823 * Puts an image in the page.
6824 * The upper-left corner must be given.
6825 * The dimensions can be specified in different ways:<ul>
6826 * <li>explicit width and height (expressed in user unit)</li>
6827 * <li>one explicit dimension, the other being calculated automatically in order to keep the original proportions</li>
6828 * <li>no explicit dimension, in which case the image is put at 72 dpi</li></ul>
6829 * Supported formats are JPEG and PNG images whitout GD library and all images supported by GD: GD, GD2, GD2PART, GIF, JPEG, PNG, BMP, XBM, XPM;
6830 * The format can be specified explicitly or inferred from the file extension.<br />
6831 * It is possible to put a link on the image.<br />
6832 * Remark: if an image is used several times, only one copy will be embedded in the file.<br />
6833 * @param $file (string) Name of the file containing the image or a '@' character followed by the image data string. To link an image without embedding it on the document, set an asterisk character before the URL (i.e.: '*http://www.example.com/image.jpg').
6834 * @param $x (float) Abscissa of the upper-left corner (LTR) or upper-right corner (RTL).
6835 * @param $y (float) Ordinate of the upper-left corner (LTR) or upper-right corner (RTL).
6836 * @param $w (float) Width of the image in the page. If not specified or equal to zero, it is automatically calculated.
6837 * @param $h (float) Height of the image in the page. If not specified or equal to zero, it is automatically calculated.
6838 * @param $type (string) Image format. Possible values are (case insensitive): JPEG and PNG (whitout GD library) and all images supported by GD: GD, GD2, GD2PART, GIF, JPEG, PNG, BMP, XBM, XPM;. If not specified, the type is inferred from the file extension.
6839 * @param $link (mixed) URL or identifier returned by AddLink().
6840 * @param $align (string) Indicates the alignment of the pointer next to image insertion relative to image height. The value can be:<ul><li>T: top-right for LTR or top-left for RTL</li><li>M: middle-right for LTR or middle-left for RTL</li><li>B: bottom-right for LTR or bottom-left for RTL</li><li>N: next line</li></ul>
6841 * @param $resize (mixed) If true resize (reduce) the image to fit $w and $h (requires GD or ImageMagick library); if false do not resize; if 2 force resize in all cases (upscaling and downscaling).
6842 * @param $dpi (int) dot-per-inch resolution used on resize
6843 * @param $palign (string) Allows to center or align the image on the current line. Possible values are:<ul><li>L : left align</li><li>C : center</li><li>R : right align</li><li>'' : empty string : left for LTR or right for RTL</li></ul>
6844 * @param $ismask (boolean) true if this image is a mask, false otherwise
6845 * @param $imgmask (mixed) image object returned by this function or false
6846 * @param $border (mixed) Indicates if borders must be drawn around the cell. 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 - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0)))
6847 * @param $fitbox (mixed) If not false scale image dimensions proportionally to fit within the ($w, $h) box. $fitbox can be true or a 2 characters string indicating the image alignment inside the box. The first character indicate the horizontal alignment (L = left, C = center, R = right) the second character indicate the vertical algnment (T = top, M = middle, B = bottom).
6848 * @param $hidden (boolean) If true do not display the image.
6849 * @param $fitonpage (boolean) If true the image is resized to not exceed page dimensions.
6850 * @param $alt (boolean) If true the image will be added as alternative and not directly printed (the ID of the image will be returned).
6851 * @param $altimgs (array) Array of alternate images IDs. Each alternative image must be an array with two values: an integer representing the image ID (the value returned by the Image method) and a boolean value to indicate if the image is the default for printing.
6852 * @return image information
6853 * @public
6854 * @since 1.1
6855 */
6856 public function Image($file, $x='', $y='', $w=0, $h=0, $type='', $link='', $align='', $resize=false, $dpi=300, $palign='', $ismask=false, $imgmask=false, $border=0, $fitbox=false, $hidden=false, $fitonpage=false, $alt=false, $altimgs=array()) {
6857 if ($this->state != 2) {
6858 return;
6859 }
6860 if ($x === '') {
6861 $x = $this->x;
6862 }
6863 if ($y === '') {
6864 $y = $this->y;
6865 }
6866 // check page for no-write regions and adapt page margins if necessary
6867 list($x, $y) = $this->checkPageRegions($h, $x, $y);
6868 $exurl = ''; // external streams
6869 $imsize = FALSE;
6870 // check if we are passing an image as file or string
6871 if ($file[0] === '@') {
6872 // image from string
6873 $imgdata = substr($file, 1);
6874 } else { // image file
6875 if ($file[0] === '*') {
6876 // image as external stream
6877 $file = substr($file, 1);
6878 $exurl = $file;
6879 }
6880 // check if is a local file
6881 if (!@file_exists($file)) {
6882 // try to encode spaces on filename
6883 $tfile = str_replace(' ', '%20', $file);
6884 if (@file_exists($tfile)) {
6885 $file = $tfile;
6886 }
6887 }
6888 if (($imsize = @getimagesize($file)) === FALSE) {
6889 if (in_array($file, $this->imagekeys)) {
6890 // get existing image data
6891 $info = $this->getImageBuffer($file);
6892 $imsize = array($info['w'], $info['h']);
6893 } elseif (strpos($file, '__tcpdf_img') === FALSE) {
6894 $imgdata = TCPDF_STATIC::fileGetContents($file);
6895 }
6896 }
6897 }
6898 if (!empty($imgdata)) {
6899 // copy image to cache
6900 $original_file = $file;
6901 $file = TCPDF_STATIC::getObjFilename('img');
6902 $fp = fopen($file, 'w');
6903 if (!$fp) {
6904 $this->Error('Unable to write file: '.$file);
6905 }
6906 fwrite($fp, $imgdata);
6907 fclose($fp);
6908 unset($imgdata);
6909 $imsize = @getimagesize($file);
6910 if ($imsize === FALSE) {
6911 unlink($file);
6912 $file = $original_file;
6913 } else {
6914 $this->cached_files[] = $file;
6915 }
6916 }
6917 if ($imsize === FALSE) {
6918 if (($w > 0) AND ($h > 0)) {
6919 // get measures from specified data
6920 $pw = $this->getHTMLUnitToUnits($w, 0, $this->pdfunit, true) * $this->imgscale * $this->k;
6921 $ph = $this->getHTMLUnitToUnits($h, 0, $this->pdfunit, true) * $this->imgscale * $this->k;
6922 $imsize = array($pw, $ph);
6923 } else {
6924 $this->Error('[Image] Unable to fetch image: '.$file);
6925 }
6926 }
6927 // file hash
6928 $filehash = md5($this->file_id.$file);
6929 // get original image width and height in pixels
6930 list($pixw, $pixh) = $imsize;
6931 // calculate image width and height on document
6932 if (($w <= 0) AND ($h <= 0)) {
6933 // convert image size to document unit
6934 $w = $this->pixelsToUnits($pixw);
6935 $h = $this->pixelsToUnits($pixh);
6936 } elseif ($w <= 0) {
6937 $w = $h * $pixw / $pixh;
6938 } elseif ($h <= 0) {
6939 $h = $w * $pixh / $pixw;
6940 } elseif (($fitbox !== false) AND ($w > 0) AND ($h > 0)) {
6941 if (strlen($fitbox) !== 2) {
6942 // set default alignment
6943 $fitbox = '--';
6944 }
6945 // scale image dimensions proportionally to fit within the ($w, $h) box
6946 if ((($w * $pixh) / ($h * $pixw)) < 1) {
6947 // store current height
6948 $oldh = $h;
6949 // calculate new height
6950 $h = $w * $pixh / $pixw;
6951 // height difference
6952 $hdiff = ($oldh - $h);
6953 // vertical alignment
6954 switch (strtoupper($fitbox[1])) {
6955 case 'T': {
6956 break;
6957 }
6958 case 'M': {
6959 $y += ($hdiff / 2);
6960 break;
6961 }
6962 case 'B': {
6963 $y += $hdiff;
6964 break;
6965 }
6966 }
6967 } else {
6968 // store current width
6969 $oldw = $w;
6970 // calculate new width
6971 $w = $h * $pixw / $pixh;
6972 // width difference
6973 $wdiff = ($oldw - $w);
6974 // horizontal alignment
6975 switch (strtoupper($fitbox[0])) {
6976 case 'L': {
6977 if ($this->rtl) {
6978 $x -= $wdiff;
6979 }
6980 break;
6981 }
6982 case 'C': {
6983 if ($this->rtl) {
6984 $x -= ($wdiff / 2);
6985 } else {
6986 $x += ($wdiff / 2);
6987 }
6988 break;
6989 }
6990 case 'R': {
6991 if (!$this->rtl) {
6992 $x += $wdiff;
6993 }
6994 break;
6995 }
6996 }
6997 }
6998 }
6999 // fit the image on available space
7000 list($w, $h, $x, $y) = $this->fitBlock($w, $h, $x, $y, $fitonpage);
7001 // calculate new minimum dimensions in pixels
7002 $neww = round($w * $this->k * $dpi / $this->dpi);
7003 $newh = round($h * $this->k * $dpi / $this->dpi);
7004 // check if resize is necessary (resize is used only to reduce the image)
7005 $newsize = ($neww * $newh);
7006 $pixsize = ($pixw * $pixh);
7007 if (intval($resize) == 2) {
7008 $resize = true;
7009 } elseif ($newsize >= $pixsize) {
7010 $resize = false;
7011 }
7012 // check if image has been already added on document
7013 $newimage = true;
7014 if (in_array($file, $this->imagekeys)) {
7015 $newimage = false;
7016 // get existing image data
7017 $info = $this->getImageBuffer($file);
7018 if (strpos($file, '__tcpdf_imgmask_') === FALSE) {
7019 // check if the newer image is larger
7020 $oldsize = ($info['w'] * $info['h']);
7021 if ((($oldsize < $newsize) AND ($resize)) OR (($oldsize < $pixsize) AND (!$resize))) {
7022 $newimage = true;
7023 }
7024 }
7025 } elseif (($ismask === false) AND ($imgmask === false) AND (strpos($file, '__tcpdf_imgmask_') === FALSE)) {
7026 // create temp image file (without alpha channel)
7027 $tempfile_plain = K_PATH_CACHE.'__tcpdf_imgmask_plain_'.$filehash;
7028 // create temp alpha file
7029 $tempfile_alpha = K_PATH_CACHE.'__tcpdf_imgmask_alpha_'.$filehash;
7030 // check for cached images
7031 if (in_array($tempfile_plain, $this->imagekeys)) {
7032 // get existing image data
7033 $info = $this->getImageBuffer($tempfile_plain);
7034 // check if the newer image is larger
7035 $oldsize = ($info['w'] * $info['h']);
7036 if ((($oldsize < $newsize) AND ($resize)) OR (($oldsize < $pixsize) AND (!$resize))) {
7037 $newimage = true;
7038 } else {
7039 $newimage = false;
7040 // embed mask image
7041 $imgmask = $this->Image($tempfile_alpha, $x, $y, $w, $h, 'PNG', '', '', $resize, $dpi, '', true, false);
7042 // embed image, masked with previously embedded mask
7043 return $this->Image($tempfile_plain, $x, $y, $w, $h, $type, $link, $align, $resize, $dpi, $palign, false, $imgmask);
7044 }
7045 }
7046 }
7047 if ($newimage) {
7048 //First use of image, get info
7049 $type = strtolower($type);
7050 if ($type == '') {
7051 $type = TCPDF_IMAGES::getImageFileType($file, $imsize);
7052 } elseif ($type == 'jpg') {
7053 $type = 'jpeg';
7054 }
7055 $mqr = TCPDF_STATIC::get_mqr();
7056 TCPDF_STATIC::set_mqr(false);
7057 // Specific image handlers (defined on TCPDF_IMAGES CLASS)
7058 $mtd = '_parse'.$type;
7059 // GD image handler function
7060 $gdfunction = 'imagecreatefrom'.$type;
7061 $info = false;
7062 if ((method_exists('TCPDF_IMAGES', $mtd)) AND (!($resize AND (function_exists($gdfunction) OR extension_loaded('imagick'))))) {
7063 // TCPDF image functions
7064 $info = TCPDF_IMAGES::$mtd($file);
7065 if (($ismask === false) AND ($imgmask === false) AND (strpos($file, '__tcpdf_imgmask_') === FALSE)
7066 AND (($info === 'pngalpha') OR (isset($info['trns']) AND !empty($info['trns'])))) {
7067 return $this->ImagePngAlpha($file, $x, $y, $pixw, $pixh, $w, $h, 'PNG', $link, $align, $resize, $dpi, $palign, $filehash);
7068 }
7069 }
7070 if (($info === false) AND function_exists($gdfunction)) {
7071 try {
7072 // GD library
7073 $img = $gdfunction($file);
7074 if ($img !== false) {
7075 if ($resize) {
7076 $imgr = imagecreatetruecolor($neww, $newh);
7077 if (($type == 'gif') OR ($type == 'png')) {
7078 $imgr = TCPDF_IMAGES::setGDImageTransparency($imgr, $img);
7079 }
7080 imagecopyresampled($imgr, $img, 0, 0, 0, 0, $neww, $newh, $pixw, $pixh);
7081 $img = $imgr;
7082 }
7083 if (($type == 'gif') OR ($type == 'png')) {
7084 $info = TCPDF_IMAGES::_toPNG($img);
7085 } else {
7086 $info = TCPDF_IMAGES::_toJPEG($img, $this->jpeg_quality);
7087 }
7088 }
7089 } catch(Exception $e) {
7090 $info = false;
7091 }
7092 }
7093 if (($info === false) AND extension_loaded('imagick')) {
7094 try {
7095 // ImageMagick library
7096 $img = new Imagick();
7097 if ($type == 'svg') {
7098 if ($file[0] === '@') {
7099 // image from string
7100 $svgimg = substr($file, 1);
7101 } else {
7102 // get SVG file content
7103 $svgimg = TCPDF_STATIC::fileGetContents($file);
7104 }
7105 if ($svgimg !== FALSE) {
7106 // get width and height
7107 $regs = array();
7108 if (preg_match('/<svg([^\>]*)>/si', $svgimg, $regs)) {
7109 $svgtag = $regs[1];
7110 $tmp = array();
7111 if (preg_match('/[\s]+width[\s]*=[\s]*"([^"]*)"/si', $svgtag, $tmp)) {
7112 $ow = $this->getHTMLUnitToUnits($tmp[1], 1, $this->svgunit, false);
7113 $owu = sprintf('%F', ($ow * $dpi / 72)).$this->pdfunit;
7114 $svgtag = preg_replace('/[\s]+width[\s]*=[\s]*"[^"]*"/si', ' width="'.$owu.'"', $svgtag, 1);
7115 } else {
7116 $ow = $w;
7117 }
7118 $tmp = array();
7119 if (preg_match('/[\s]+height[\s]*=[\s]*"([^"]*)"/si', $svgtag, $tmp)) {
7120 $oh = $this->getHTMLUnitToUnits($tmp[1], 1, $this->svgunit, false);
7121 $ohu = sprintf('%F', ($oh * $dpi / 72)).$this->pdfunit;
7122 $svgtag = preg_replace('/[\s]+height[\s]*=[\s]*"[^"]*"/si', ' height="'.$ohu.'"', $svgtag, 1);
7123 } else {
7124 $oh = $h;
7125 }
7126 $tmp = array();
7127 if (!preg_match('/[\s]+viewBox[\s]*=[\s]*"[\s]*([0-9\.]+)[\s]+([0-9\.]+)[\s]+([0-9\.]+)[\s]+([0-9\.]+)[\s]*"/si', $svgtag, $tmp)) {
7128 $vbw = ($ow * $this->imgscale * $this->k);
7129 $vbh = ($oh * $this->imgscale * $this->k);
7130 $vbox = sprintf(' viewBox="0 0 %F %F" ', $vbw, $vbh);
7131 $svgtag = $vbox.$svgtag;
7132 }
7133 $svgimg = preg_replace('/<svg([^\>]*)>/si', '<svg'.$svgtag.'>', $svgimg, 1);
7134 }
7135 $img->readImageBlob($svgimg);
7136 }
7137 } else {
7138 $img->readImage($file);
7139 }
7140 if ($resize) {
7141 $img->resizeImage($neww, $newh, 10, 1, false);
7142 }
7143 $img->setCompressionQuality($this->jpeg_quality);
7144 $img->setImageFormat('jpeg');
7145 $tempname = TCPDF_STATIC::getObjFilename('img');
7146 $img->writeImage($tempname);
7147 $info = TCPDF_IMAGES::_parsejpeg($tempname);
7148 unlink($tempname);
7149 $img->destroy();
7150 } catch(Exception $e) {
7151 $info = false;
7152 }
7153 }
7154 if ($info === false) {
7155 // unable to process image
7156 return;
7157 }
7158 TCPDF_STATIC::set_mqr($mqr);
7159 if ($ismask) {
7160 // force grayscale
7161 $info['cs'] = 'DeviceGray';
7162 }
7163 if ($imgmask !== false) {
7164 $info['masked'] = $imgmask;
7165 }
7166 if (!empty($exurl)) {
7167 $info['exurl'] = $exurl;
7168 }
7169 // array of alternative images
7170 $info['altimgs'] = $altimgs;
7171 // add image to document
7172 $info['i'] = $this->setImageBuffer($file, $info);
7173 }
7174 // set alignment
7175 $this->img_rb_y = $y + $h;
7176 // set alignment
7177 if ($this->rtl) {
7178 if ($palign == 'L') {
7179 $ximg = $this->lMargin;
7180 } elseif ($palign == 'C') {
7181 $ximg = ($this->w + $this->lMargin - $this->rMargin - $w) / 2;
7182 } elseif ($palign == 'R') {
7183 $ximg = $this->w - $this->rMargin - $w;
7184 } else {
7185 $ximg = $x - $w;
7186 }
7187 $this->img_rb_x = $ximg;
7188 } else {
7189 if ($palign == 'L') {
7190 $ximg = $this->lMargin;
7191 } elseif ($palign == 'C') {
7192 $ximg = ($this->w + $this->lMargin - $this->rMargin - $w) / 2;
7193 } elseif ($palign == 'R') {
7194 $ximg = $this->w - $this->rMargin - $w;
7195 } else {
7196 $ximg = $x;
7197 }
7198 $this->img_rb_x = $ximg + $w;
7199 }
7200 if ($ismask OR $hidden) {
7201 // image is not displayed
7202 return $info['i'];
7203 }
7204 $xkimg = $ximg * $this->k;
7205 if (!$alt) {
7206 // only non-alternative immages will be set
7207 $this->_out(sprintf('q %F 0 0 %F %F %F cm /I%u Do Q', ($w * $this->k), ($h * $this->k), $xkimg, (($this->h - ($y + $h)) * $this->k), $info['i']));
7208 }
7209 if (!empty($border)) {
7210 $bx = $this->x;
7211 $by = $this->y;
7212 $this->x = $ximg;
7213 if ($this->rtl) {
7214 $this->x += $w;
7215 }
7216 $this->y = $y;
7217 $this->Cell($w, $h, '', $border, 0, '', 0, '', 0, true);
7218 $this->x = $bx;
7219 $this->y = $by;
7220 }
7221 if ($link) {
7222 $this->Link($ximg, $y, $w, $h, $link, 0);
7223 }
7224 // set pointer to align the next text/objects
7225 switch($align) {
7226 case 'T': {
7227 $this->y = $y;
7228 $this->x = $this->img_rb_x;
7229 break;
7230 }
7231 case 'M': {
7232 $this->y = $y + round($h/2);
7233 $this->x = $this->img_rb_x;
7234 break;
7235 }
7236 case 'B': {
7237 $this->y = $this->img_rb_y;
7238 $this->x = $this->img_rb_x;
7239 break;
7240 }
7241 case 'N': {
7242 $this->SetY($this->img_rb_y);
7243 break;
7244 }
7245 default:{
7246 break;
7247 }
7248 }
7249 $this->endlinex = $this->img_rb_x;
7250 if ($this->inxobj) {
7251 // we are inside an XObject template
7252 $this->xobjects[$this->xobjid]['images'][] = $info['i'];
7253 }
7254 return $info['i'];
7255 }
7256
7257 /**
7258 * Extract info from a PNG image with alpha channel using the Imagick or GD library.
7259 * @param $file (string) Name of the file containing the image.
7260 * @param $x (float) Abscissa of the upper-left corner.
7261 * @param $y (float) Ordinate of the upper-left corner.
7262 * @param $wpx (float) Original width of the image in pixels.
7263 * @param $hpx (float) original height of the image in pixels.
7264 * @param $w (float) Width of the image in the page. If not specified or equal to zero, it is automatically calculated.
7265 * @param $h (float) Height of the image in the page. If not specified or equal to zero, it is automatically calculated.
7266 * @param $type (string) Image format. Possible values are (case insensitive): JPEG and PNG (whitout GD library) and all images supported by GD: GD, GD2, GD2PART, GIF, JPEG, PNG, BMP, XBM, XPM;. If not specified, the type is inferred from the file extension.
7267 * @param $link (mixed) URL or identifier returned by AddLink().
7268 * @param $align (string) Indicates the alignment of the pointer next to image insertion relative to image height. The value can be:<ul><li>T: top-right for LTR or top-left for RTL</li><li>M: middle-right for LTR or middle-left for RTL</li><li>B: bottom-right for LTR or bottom-left for RTL</li><li>N: next line</li></ul>
7269 * @param $resize (boolean) If true resize (reduce) the image to fit $w and $h (requires GD library).
7270 * @param $dpi (int) dot-per-inch resolution used on resize
7271 * @param $palign (string) Allows to center or align the image on the current line. Possible values are:<ul><li>L : left align</li><li>C : center</li><li>R : right align</li><li>'' : empty string : left for LTR or right for RTL</li></ul>
7272 * @param $filehash (string) File hash used to build unique file names.
7273 * @author Nicola Asuni
7274 * @protected
7275 * @since 4.3.007 (2008-12-04)
7276 * @see Image()
7277 */
7278 protected function ImagePngAlpha($file, $x, $y, $wpx, $hpx, $w, $h, $type, $link, $align, $resize, $dpi, $palign, $filehash='') {
7279 // create temp images
7280 if (empty($filehash)) {
7281 $filehash = md5($this->file_id.$file);
7282 }
7283 // create temp image file (without alpha channel)
7284 $tempfile_plain = K_PATH_CACHE.'__tcpdf_imgmask_plain_'.$filehash;
7285 // create temp alpha file
7286 $tempfile_alpha = K_PATH_CACHE.'__tcpdf_imgmask_alpha_'.$filehash;
7287 $parsed = false;
7288 $parse_error = '';
7289 // ImageMagick extension
7290 if (($parsed === false) AND extension_loaded('imagick')) {
7291 try {
7292 // ImageMagick library
7293 $img = new Imagick();
7294 $img->readImage($file);
7295 // clone image object
7296 $imga = TCPDF_STATIC::objclone($img);
7297 // extract alpha channel
7298 if (method_exists($img, 'setImageAlphaChannel') AND defined('Imagick::ALPHACHANNEL_EXTRACT')) {
7299 $img->setImageAlphaChannel(Imagick::ALPHACHANNEL_EXTRACT);
7300 } else {
7301 $img->separateImageChannel(8); // 8 = (imagick::CHANNEL_ALPHA | imagick::CHANNEL_OPACITY | imagick::CHANNEL_MATTE);
7302 $img->negateImage(true);
7303 }
7304 $img->setImageFormat('png');
7305 $img->writeImage($tempfile_alpha);
7306 // remove alpha channel
7307 if (method_exists($imga, 'setImageMatte')) {
7308 $imga->setImageMatte(false);
7309 } else {
7310 $imga->separateImageChannel(39); // 39 = (imagick::CHANNEL_ALL & ~(imagick::CHANNEL_ALPHA | imagick::CHANNEL_OPACITY | imagick::CHANNEL_MATTE));
7311 }
7312 $imga->setImageFormat('png');
7313 $imga->writeImage($tempfile_plain);
7314 $parsed = true;
7315 } catch (Exception $e) {
7316 // Imagemagick fails, try with GD
7317 $parse_error = 'Imagick library error: '.$e->getMessage();
7318 }
7319 }
7320 // GD extension
7321 if (($parsed === false) AND function_exists('imagecreatefrompng')) {
7322 try {
7323 // generate images
7324 $img = imagecreatefrompng($file);
7325 $imgalpha = imagecreate($wpx, $hpx);
7326 // generate gray scale palette (0 -> 255)
7327 for ($c = 0; $c < 256; ++$c) {
7328 ImageColorAllocate($imgalpha, $c, $c, $c);
7329 }
7330 // extract alpha channel
7331 for ($xpx = 0; $xpx < $wpx; ++$xpx) {
7332 for ($ypx = 0; $ypx < $hpx; ++$ypx) {
7333 $color = imagecolorat($img, $xpx, $ypx);
7334 // get and correct gamma color
7335 $alpha = $this->getGDgamma($img, $color);
7336 imagesetpixel($imgalpha, $xpx, $ypx, $alpha);
7337 }
7338 }
7339 imagepng($imgalpha, $tempfile_alpha);
7340 imagedestroy($imgalpha);
7341 // extract image without alpha channel
7342 $imgplain = imagecreatetruecolor($wpx, $hpx);
7343 imagecopy($imgplain, $img, 0, 0, 0, 0, $wpx, $hpx);
7344 imagepng($imgplain, $tempfile_plain);
7345 imagedestroy($imgplain);
7346 $parsed = true;
7347 } catch (Exception $e) {
7348 // GD fails
7349 $parse_error = 'GD library error: '.$e->getMessage();
7350 }
7351 }
7352 if ($parsed === false) {
7353 if (empty($parse_error)) {
7354 $this->Error('TCPDF requires the Imagick or GD extension to handle PNG images with alpha channel.');
7355 } else {
7356 $this->Error($parse_error);
7357 }
7358 }
7359 // embed mask image
7360 $imgmask = $this->Image($tempfile_alpha, $x, $y, $w, $h, 'PNG', '', '', $resize, $dpi, '', true, false);
7361 // embed image, masked with previously embedded mask
7362 $this->Image($tempfile_plain, $x, $y, $w, $h, $type, $link, $align, $resize, $dpi, $palign, false, $imgmask);
7363 // remove temp files
7364 unlink($tempfile_alpha);
7365 unlink($tempfile_plain);
7366 }
7367
7368 /**
7369 * Get the GD-corrected PNG gamma value from alpha color
7370 * @param $img (int) GD image Resource ID.
7371 * @param $c (int) alpha color
7372 * @protected
7373 * @since 4.3.007 (2008-12-04)
7374 */
7375 protected function getGDgamma($img, $c) {
7376 if (!isset($this->gdgammacache['#'.$c])) {
7377 $colors = imagecolorsforindex($img, $c);
7378 // GD alpha is only 7 bit (0 -> 127)
7379 $this->gdgammacache['#'.$c] = (((127 - $colors['alpha']) / 127) * 255);
7380 // correct gamma
7381 $this->gdgammacache['#'.$c] = (pow(($this->gdgammacache['#'.$c] / 255), 2.2) * 255);
7382 // store the latest values on cache to improve performances
7383 if (count($this->gdgammacache) > 8) {
7384 // remove one element from the cache array
7385 array_shift($this->gdgammacache);
7386 }
7387 }
7388 return $this->gdgammacache['#'.$c];
7389 }
7390
7391 /**
7392 * Performs a line break.
7393 * The current abscissa goes back to the left margin and the ordinate increases by the amount passed in parameter.
7394 * @param $h (float) The height of the break. By default, the value equals the height of the last printed cell.
7395 * @param $cell (boolean) if true add the current left (or right o for RTL) padding to the X coordinate
7396 * @public
7397 * @since 1.0
7398 * @see Cell()
7399 */
7400 public function Ln($h='', $cell=false) {
7401 if (($this->num_columns > 1) AND ($this->y == $this->columns[$this->current_column]['y']) AND isset($this->columns[$this->current_column]['x']) AND ($this->x == $this->columns[$this->current_column]['x'])) {
7402 // revove vertical space from the top of the column
7403 return;
7404 }
7405 if ($cell) {
7406 if ($this->rtl) {
7407 $cellpadding = $this->cell_padding['R'];
7408 } else {
7409 $cellpadding = $this->cell_padding['L'];
7410 }
7411 } else {
7412 $cellpadding = 0;
7413 }
7414 if ($this->rtl) {
7415 $this->x = $this->w - $this->rMargin - $cellpadding;
7416 } else {
7417 $this->x = $this->lMargin + $cellpadding;
7418 }
7419 if (is_string($h)) {
7420 $this->y += $this->lasth;
7421 } else {
7422 $this->y += $h;
7423 }
7424 $this->newline = true;
7425 }
7426
7427 /**
7428 * Returns the relative X value of current position.
7429 * The value is relative to the left border for LTR languages and to the right border for RTL languages.
7430 * @return float
7431 * @public
7432 * @since 1.2
7433 * @see SetX(), GetY(), SetY()
7434 */
7435 public function GetX() {
7436 //Get x position
7437 if ($this->rtl) {
7438 return ($this->w - $this->x);
7439 } else {
7440 return $this->x;
7441 }
7442 }
7443
7444 /**
7445 * Returns the absolute X value of current position.
7446 * @return float
7447 * @public
7448 * @since 1.2
7449 * @see SetX(), GetY(), SetY()
7450 */
7451 public function GetAbsX() {
7452 return $this->x;
7453 }
7454
7455 /**
7456 * Returns the ordinate of the current position.
7457 * @return float
7458 * @public
7459 * @since 1.0
7460 * @see SetY(), GetX(), SetX()
7461 */
7462 public function GetY() {
7463 return $this->y;
7464 }
7465
7466 /**
7467 * Defines the abscissa of the current position.
7468 * If the passed value is negative, it is relative to the right of the page (or left if language is RTL).
7469 * @param $x (float) The value of the abscissa in user units.
7470 * @param $rtloff (boolean) if true always uses the page top-left corner as origin of axis.
7471 * @public
7472 * @since 1.2
7473 * @see GetX(), GetY(), SetY(), SetXY()
7474 */
7475 public function SetX($x, $rtloff=false) {
7476 $x = floatval($x);
7477 if (!$rtloff AND $this->rtl) {
7478 if ($x >= 0) {
7479 $this->x = $this->w - $x;
7480 } else {
7481 $this->x = abs($x);
7482 }
7483 } else {
7484 if ($x >= 0) {
7485 $this->x = $x;
7486 } else {
7487 $this->x = $this->w + $x;
7488 }
7489 }
7490 if ($this->x < 0) {
7491 $this->x = 0;
7492 }
7493 if ($this->x > $this->w) {
7494 $this->x = $this->w;
7495 }
7496 }
7497
7498 /**
7499 * Moves the current abscissa back to the left margin and sets the ordinate.
7500 * If the passed value is negative, it is relative to the bottom of the page.
7501 * @param $y (float) The value of the ordinate in user units.
7502 * @param $resetx (bool) if true (default) reset the X position.
7503 * @param $rtloff (boolean) if true always uses the page top-left corner as origin of axis.
7504 * @public
7505 * @since 1.0
7506 * @see GetX(), GetY(), SetY(), SetXY()
7507 */
7508 public function SetY($y, $resetx=true, $rtloff=false) {
7509 $y = floatval($y);
7510 if ($resetx) {
7511 //reset x
7512 if (!$rtloff AND $this->rtl) {
7513 $this->x = $this->w - $this->rMargin;
7514 } else {
7515 $this->x = $this->lMargin;
7516 }
7517 }
7518 if ($y >= 0) {
7519 $this->y = $y;
7520 } else {
7521 $this->y = $this->h + $y;
7522 }
7523 if ($this->y < 0) {
7524 $this->y = 0;
7525 }
7526 if ($this->y > $this->h) {
7527 $this->y = $this->h;
7528 }
7529 }
7530
7531 /**
7532 * Defines the abscissa and ordinate of the current position.
7533 * If the passed values are negative, they are relative respectively to the right and bottom of the page.
7534 * @param $x (float) The value of the abscissa.
7535 * @param $y (float) The value of the ordinate.
7536 * @param $rtloff (boolean) if true always uses the page top-left corner as origin of axis.
7537 * @public
7538 * @since 1.2
7539 * @see SetX(), SetY()
7540 */
7541 public function SetXY($x, $y, $rtloff=false) {
7542 $this->SetY($y, false, $rtloff);
7543 $this->SetX($x, $rtloff);
7544 }
7545
7546 /**
7547 * Set the absolute X coordinate of the current pointer.
7548 * @param $x (float) The value of the abscissa in user units.
7549 * @public
7550 * @since 5.9.186 (2012-09-13)
7551 * @see setAbsX(), setAbsY(), SetAbsXY()
7552 */
7553 public function SetAbsX($x) {
7554 $this->x = floatval($x);
7555 }
7556
7557 /**
7558 * Set the absolute Y coordinate of the current pointer.
7559 * @param $y (float) (float) The value of the ordinate in user units.
7560 * @public
7561 * @since 5.9.186 (2012-09-13)
7562 * @see setAbsX(), setAbsY(), SetAbsXY()
7563 */
7564 public function SetAbsY($y) {
7565 $this->y = floatval($y);
7566 }
7567
7568 /**
7569 * Set the absolute X and Y coordinates of the current pointer.
7570 * @param $x (float) The value of the abscissa in user units.
7571 * @param $y (float) (float) The value of the ordinate in user units.
7572 * @public
7573 * @since 5.9.186 (2012-09-13)
7574 * @see setAbsX(), setAbsY(), SetAbsXY()
7575 */
7576 public function SetAbsXY($x, $y) {
7577 $this->SetAbsX($x);
7578 $this->SetAbsY($y);
7579 }
7580
7581 /**
7582 * Send the document to a given destination: string, local file or browser.
7583 * In the last case, the plug-in may be used (if present) or a download ("Save as" dialog box) may be forced.<br />
7584 * The method first calls Close() if necessary to terminate the document.
7585 * @param $name (string) The name of the file when saved. Note that special characters are removed and blanks characters are replaced with the underscore character.
7586 * @param $dest (string) Destination where to send the document. It can take one of the following values:<ul><li>I: send the file inline to the browser (default). The plug-in is used if available. The name given by name is used when one selects the "Save as" option on the link generating the PDF.</li><li>D: send to the browser and force a file download with the name given by name.</li><li>F: save to a local server file with the name given by name.</li><li>S: return the document as a string (name is ignored).</li><li>FI: equivalent to F + I option</li><li>FD: equivalent to F + D option</li><li>E: return the document as base64 mime multi-part email attachment (RFC 2045)</li></ul>
7587 * @public
7588 * @since 1.0
7589 * @see Close()
7590 */
7591 public function Output($name='doc.pdf', $dest='I') {
7592 //Output PDF to some destination
7593 //Finish document if necessary
7594 if ($this->state < 3) {
7595 $this->Close();
7596 }
7597 //Normalize parameters
7598 if (is_bool($dest)) {
7599 $dest = $dest ? 'D' : 'F';
7600 }
7601 $dest = strtoupper($dest);
7602 if ($dest[0] != 'F') {
7603 $name = preg_replace('/[\s]+/', '_', $name);
7604 $name = preg_replace('/[^a-zA-Z0-9_\.-]/', '', $name);
7605 }
7606 if ($this->sign) {
7607 // *** apply digital signature to the document ***
7608 // get the document content
7609 $pdfdoc = $this->getBuffer();
7610 // remove last newline
7611 $pdfdoc = substr($pdfdoc, 0, -1);
7612 // Remove the original buffer
7613 if (isset($this->diskcache) AND $this->diskcache) {
7614 // remove buffer file from cache
7615 unlink($this->buffer);
7616 }
7617 unset($this->buffer);
7618 // remove filler space
7619 $byterange_string_len = strlen(TCPDF_STATIC::$byterange_string);
7620 // define the ByteRange
7621 $byte_range = array();
7622 $byte_range[0] = 0;
7623 $byte_range[1] = strpos($pdfdoc, TCPDF_STATIC::$byterange_string) + $byterange_string_len + 10;
7624 $byte_range[2] = $byte_range[1] + $this->signature_max_length + 2;
7625 $byte_range[3] = strlen($pdfdoc) - $byte_range[2];
7626 $pdfdoc = substr($pdfdoc, 0, $byte_range[1]).substr($pdfdoc, $byte_range[2]);
7627 // replace the ByteRange
7628 $byterange = sprintf('/ByteRange[0 %u %u %u]', $byte_range[1], $byte_range[2], $byte_range[3]);
7629 $byterange .= str_repeat(' ', ($byterange_string_len - strlen($byterange)));
7630 $pdfdoc = str_replace(TCPDF_STATIC::$byterange_string, $byterange, $pdfdoc);
7631 // write the document to a temporary folder
7632 $tempdoc = TCPDF_STATIC::getObjFilename('doc');
7633 $f = fopen($tempdoc, 'wb');
7634 if (!$f) {
7635 $this->Error('Unable to create temporary file: '.$tempdoc);
7636 }
7637 $pdfdoc_length = strlen($pdfdoc);
7638 fwrite($f, $pdfdoc, $pdfdoc_length);
7639 fclose($f);
7640 // get digital signature via openssl library
7641 $tempsign = TCPDF_STATIC::getObjFilename('sig');
7642 if (empty($this->signature_data['extracerts'])) {
7643 openssl_pkcs7_sign($tempdoc, $tempsign, $this->signature_data['signcert'], array($this->signature_data['privkey'], $this->signature_data['password']), array(), PKCS7_BINARY | PKCS7_DETACHED);
7644 } else {
7645 openssl_pkcs7_sign($tempdoc, $tempsign, $this->signature_data['signcert'], array($this->signature_data['privkey'], $this->signature_data['password']), array(), PKCS7_BINARY | PKCS7_DETACHED, $this->signature_data['extracerts']);
7646 }
7647 unlink($tempdoc);
7648 // read signature
7649 $signature = file_get_contents($tempsign);
7650 unlink($tempsign);
7651 // extract signature
7652 $signature = substr($signature, $pdfdoc_length);
7653 $signature = substr($signature, (strpos($signature, "%%EOF\n\n------") + 13));
7654 $tmparr = explode("\n\n", $signature);
7655 $signature = $tmparr[1];
7656 unset($tmparr);
7657 // decode signature
7658 $signature = base64_decode(trim($signature));
7659 // add TSA timestamp to signature
7660 $signature = $this->applyTSA($signature);
7661 // convert signature to hex
7662 $signature = current(unpack('H*', $signature));
7663 $signature = str_pad($signature, $this->signature_max_length, '0');
7664 // disable disk caching
7665 $this->diskcache = false;
7666 // Add signature to the document
7667 $this->buffer = substr($pdfdoc, 0, $byte_range[1]).'<'.$signature.'>'.substr($pdfdoc, $byte_range[1]);
7668 $this->bufferlen = strlen($this->buffer);
7669 }
7670 switch($dest) {
7671 case 'I': {
7672 // Send PDF to the standard output
7673 if (ob_get_contents()) {
7674 $this->Error('Some data has already been output, can\'t send PDF file');
7675 }
7676 if (php_sapi_name() != 'cli') {
7677 // send output to a browser
7678 header('Content-Type: application/pdf');
7679 if (headers_sent()) {
7680 $this->Error('Some data has already been output to browser, can\'t send PDF file');
7681 }
7682 header('Cache-Control: private, must-revalidate, post-check=0, pre-check=0, max-age=1');
7683 //header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1
7684 header('Pragma: public');
7685 header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past
7686 header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
7687 header('Content-Disposition: inline; filename="'.basename($name).'"');
7688 TCPDF_STATIC::sendOutputData($this->getBuffer(), $this->bufferlen);
7689 } else {
7690 echo $this->getBuffer();
7691 }
7692 break;
7693 }
7694 case 'D': {
7695 // download PDF as file
7696 if (ob_get_contents()) {
7697 $this->Error('Some data has already been output, can\'t send PDF file');
7698 }
7699 header('Content-Description: File Transfer');
7700 if (headers_sent()) {
7701 $this->Error('Some data has already been output to browser, can\'t send PDF file');
7702 }
7703 header('Cache-Control: private, must-revalidate, post-check=0, pre-check=0, max-age=1');
7704 //header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1
7705 header('Pragma: public');
7706 header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past
7707 header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
7708 // force download dialog
7709 if (strpos(php_sapi_name(), 'cgi') === false) {
7710 header('Content-Type: application/force-download');
7711 header('Content-Type: application/octet-stream', false);
7712 header('Content-Type: application/download', false);
7713 header('Content-Type: application/pdf', false);
7714 } else {
7715 header('Content-Type: application/pdf');
7716 }
7717 // use the Content-Disposition header to supply a recommended filename
7718 header('Content-Disposition: attachment; filename="'.basename($name).'"');
7719 header('Content-Transfer-Encoding: binary');
7720 TCPDF_STATIC::sendOutputData($this->getBuffer(), $this->bufferlen);
7721 break;
7722 }
7723 case 'F':
7724 case 'FI':
7725 case 'FD': {
7726 // save PDF to a local file
7727 if ($this->diskcache) {
7728 copy($this->buffer, $name);
7729 } else {
7730 $f = fopen($name, 'wb');
7731 if (!$f) {
7732 $this->Error('Unable to create output file: '.$name);
7733 }
7734 fwrite($f, $this->getBuffer(), $this->bufferlen);
7735 fclose($f);
7736 }
7737 if ($dest == 'FI') {
7738 // send headers to browser
7739 header('Content-Type: application/pdf');
7740 header('Cache-Control: private, must-revalidate, post-check=0, pre-check=0, max-age=1');
7741 //header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1
7742 header('Pragma: public');
7743 header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past
7744 header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
7745 header('Content-Disposition: inline; filename="'.basename($name).'"');
7746 TCPDF_STATIC::sendOutputData(file_get_contents($name), filesize($name));
7747 } elseif ($dest == 'FD') {
7748 // send headers to browser
7749 if (ob_get_contents()) {
7750 $this->Error('Some data has already been output, can\'t send PDF file');
7751 }
7752 header('Content-Description: File Transfer');
7753 if (headers_sent()) {
7754 $this->Error('Some data has already been output to browser, can\'t send PDF file');
7755 }
7756 header('Cache-Control: private, must-revalidate, post-check=0, pre-check=0, max-age=1');
7757 header('Pragma: public');
7758 header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past
7759 header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
7760 // force download dialog
7761 if (strpos(php_sapi_name(), 'cgi') === false) {
7762 header('Content-Type: application/force-download');
7763 header('Content-Type: application/octet-stream', false);
7764 header('Content-Type: application/download', false);
7765 header('Content-Type: application/pdf', false);
7766 } else {
7767 header('Content-Type: application/pdf');
7768 }
7769 // use the Content-Disposition header to supply a recommended filename
7770 header('Content-Disposition: attachment; filename="'.basename($name).'"');
7771 header('Content-Transfer-Encoding: binary');
7772 TCPDF_STATIC::sendOutputData(file_get_contents($name), filesize($name));
7773 }
7774 break;
7775 }
7776 case 'E': {
7777 // return PDF as base64 mime multi-part email attachment (RFC 2045)
7778 $retval = 'Content-Type: application/pdf;'."\r\n";
7779 $retval .= ' name="'.$name.'"'."\r\n";
7780 $retval .= 'Content-Transfer-Encoding: base64'."\r\n";
7781 $retval .= 'Content-Disposition: attachment;'."\r\n";
7782 $retval .= ' filename="'.$name.'"'."\r\n\r\n";
7783 $retval .= chunk_split(base64_encode($this->getBuffer()), 76, "\r\n");
7784 return $retval;
7785 }
7786 case 'S': {
7787 // returns PDF as a string
7788 return $this->getBuffer();
7789 }
7790 default: {
7791 $this->Error('Incorrect output destination: '.$dest);
7792 }
7793 }
7794 return '';
7795 }
7796
7797 /**
7798 * Unset all class variables except the following critical variables.
7799 * @param $destroyall (boolean) if true destroys all class variables, otherwise preserves critical variables.
7800 * @param $preserve_objcopy (boolean) if true preserves the objcopy variable
7801 * @public
7802 * @since 4.5.016 (2009-02-24)
7803 */
7804 public function _destroy($destroyall=false, $preserve_objcopy=false) {
7805 if ($destroyall AND isset($this->diskcache) AND $this->diskcache AND (!$preserve_objcopy) AND (!TCPDF_STATIC::empty_string($this->buffer))) {
7806 // remove buffer file from cache
7807 unlink($this->buffer);
7808 }
7809 if ($destroyall AND !empty($this->cached_files)) {
7810 // remove cached files
7811 foreach ($this->cached_files as $cachefile) {
7812 if (is_file($cachefile)) {
7813 unlink($cachefile);
7814 }
7815 }
7816 unset($this->cached_files);
7817 }
7818 $preserve = array(
7819 'internal_encoding',
7820 'state',
7821 'bufferlen',
7822 'buffer',
7823 'diskcache',
7824 'cached_files',
7825 'sign',
7826 'signature_data',
7827 'signature_max_length',
7828 'byterange_string',
7829 'tsa_timestamp',
7830 'tsa_data'
7831 );
7832 foreach (array_keys(get_object_vars($this)) as $val) {
7833 if ($destroyall OR !in_array($val, $preserve)) {
7834 if ((!$preserve_objcopy OR ($val != 'objcopy')) AND isset($this->$val)) {
7835 unset($this->$val);
7836 }
7837 }
7838 }
7839 }
7840
7841 /**
7842 * Check for locale-related bug
7843 * @protected
7844 */
7845 protected function _dochecks() {
7846 //Check for locale-related bug
7847 if (1.1 == 1) {
7848 $this->Error('Don\'t alter the locale before including class file');
7849 }
7850 //Check for decimal separator
7851 if (sprintf('%.1F', 1.0) != '1.0') {
7852 setlocale(LC_NUMERIC, 'C');
7853 }
7854 }
7855
7856 /**
7857 * Return an array containing variations for the basic page number alias.
7858 * @param $a (string) Base alias.
7859 * @return array of page number aliases
7860 * @protected
7861 */
7862 protected function getInternalPageNumberAliases($a= '') {
7863 $alias = array();
7864 // build array of Unicode + ASCII variants (the order is important)
7865 $alias = array('u' => array(), 'a' => array());
7866 $u = '{'.$a.'}';
7867 $alias['u'][] = TCPDF_STATIC::_escape($u);
7868 if ($this->isunicode) {
7869 $alias['u'][] = TCPDF_STATIC::_escape(TCPDF_FONTS::UTF8ToLatin1($u, $this->isunicode, $this->CurrentFont));
7870 $alias['u'][] = TCPDF_STATIC::_escape(TCPDF_FONTS::utf8StrRev($u, false, $this->tmprtl, $this->isunicode, $this->CurrentFont));
7871 $alias['a'][] = TCPDF_STATIC::_escape(TCPDF_FONTS::UTF8ToLatin1($a, $this->isunicode, $this->CurrentFont));
7872 $alias['a'][] = TCPDF_STATIC::_escape(TCPDF_FONTS::utf8StrRev($a, false, $this->tmprtl, $this->isunicode, $this->CurrentFont));
7873 }
7874 $alias['a'][] = TCPDF_STATIC::_escape($a);
7875 return $alias;
7876 }
7877
7878 /**
7879 * Return an array containing all internal page aliases.
7880 * @return array of page number aliases
7881 * @protected
7882 */
7883 protected function getAllInternalPageNumberAliases() {
7884 $basic_alias = array(TCPDF_STATIC::$alias_tot_pages, TCPDF_STATIC::$alias_num_page, TCPDF_STATIC::$alias_group_tot_pages, TCPDF_STATIC::$alias_group_num_page, TCPDF_STATIC::$alias_right_shift);
7885 $pnalias = array();
7886 foreach($basic_alias as $k => $a) {
7887 $pnalias[$k] = $this->getInternalPageNumberAliases($a);
7888 }
7889 return $pnalias;
7890 }
7891
7892 /**
7893 * Replace right shift page number aliases with spaces to correct right alignment.
7894 * This works perfectly only when using monospaced fonts.
7895 * @param $page (string) Page content.
7896 * @param $aliases (array) Array of page aliases.
7897 * @param $diff (int) initial difference to add.
7898 * @return replaced page content.
7899 * @protected
7900 */
7901 protected function replaceRightShiftPageNumAliases($page, $aliases, $diff) {
7902 foreach ($aliases as $type => $alias) {
7903 foreach ($alias as $a) {
7904 // find position of compensation factor
7905 $startnum = (strpos($a, ':') + 1);
7906 $a = substr($a, 0, $startnum);
7907 if (($pos = strpos($page, $a)) !== false) {
7908 // end of alias
7909 $endnum = strpos($page, '}', $pos);
7910 // string to be replaced
7911 $aa = substr($page, $pos, ($endnum - $pos + 1));
7912 // get compensation factor
7913 $ratio = substr($page, ($pos + $startnum), ($endnum - $pos - $startnum));
7914 $ratio = preg_replace('/[^0-9\.]/', '', $ratio);
7915 $ratio = floatval($ratio);
7916 if ($type == 'u') {
7917 $chrdiff = floor(($diff + 12) * $ratio);
7918 $shift = str_repeat(' ', $chrdiff);
7919 $shift = TCPDF_FONTS::UTF8ToUTF16BE($shift, false, $this->isunicode, $this->CurrentFont);
7920 } else {
7921 $chrdiff = floor(($diff + 11) * $ratio);
7922 $shift = str_repeat(' ', $chrdiff);
7923 }
7924 $page = str_replace($aa, $shift, $page);
7925 }
7926 }
7927 }
7928 return $page;
7929 }
7930
7931 /**
7932 * Set page boxes to be included on page descriptions.
7933 * @param $boxes (array) Array of page boxes to set on document: ('MediaBox', 'CropBox', 'BleedBox', 'TrimBox', 'ArtBox').
7934 * @protected
7935 */
7936 protected function setPageBoxTypes($boxes) {
7937 $this->page_boxes = array();
7938 foreach ($boxes as $box) {
7939 if (in_array($box, TCPDF_STATIC::$pageboxes)) {
7940 $this->page_boxes[] = $box;
7941 }
7942 }
7943 }
7944
7945 /**
7946 * Output pages (and replace page number aliases).
7947 * @protected
7948 */
7949 protected function _putpages() {
7950 $filter = ($this->compress) ? '/Filter /FlateDecode ' : '';
7951 // get internal aliases for page numbers
7952 $pnalias = $this->getAllInternalPageNumberAliases();
7953 $num_pages = $this->numpages;
7954 $ptpa = TCPDF_STATIC::formatPageNumber(($this->starting_page_number + $num_pages - 1));
7955 $ptpu = TCPDF_FONTS::UTF8ToUTF16BE($ptpa, false, $this->isunicode, $this->CurrentFont);
7956 $ptp_num_chars = $this->GetNumChars($ptpa);
7957 $pagegroupnum = 0;
7958 $groupnum = 0;
7959 $ptgu = 1;
7960 $ptga = 1;
7961 $ptg_num_chars = 1;
7962 for ($n = 1; $n <= $num_pages; ++$n) {
7963 // get current page
7964 $temppage = $this->getPageBuffer($n);
7965 $pagelen = strlen($temppage);
7966 // set replacements for total pages number
7967 $pnpa = TCPDF_STATIC::formatPageNumber(($this->starting_page_number + $n - 1));
7968 $pnpu = TCPDF_FONTS::UTF8ToUTF16BE($pnpa, false, $this->isunicode, $this->CurrentFont);
7969 $pnp_num_chars = $this->GetNumChars($pnpa);
7970 $pdiff = 0; // difference used for right shift alignment of page numbers
7971 $gdiff = 0; // difference used for right shift alignment of page group numbers
7972 if (!empty($this->pagegroups)) {
7973 if (isset($this->newpagegroup[$n])) {
7974 $pagegroupnum = 0;
7975 ++$groupnum;
7976 $ptga = TCPDF_STATIC::formatPageNumber($this->pagegroups[$groupnum]);
7977 $ptgu = TCPDF_FONTS::UTF8ToUTF16BE($ptga, false, $this->isunicode, $this->CurrentFont);
7978 $ptg_num_chars = $this->GetNumChars($ptga);
7979 }
7980 ++$pagegroupnum;
7981 $pnga = TCPDF_STATIC::formatPageNumber($pagegroupnum);
7982 $pngu = TCPDF_FONTS::UTF8ToUTF16BE($pnga, false, $this->isunicode, $this->CurrentFont);
7983 $png_num_chars = $this->GetNumChars($pnga);
7984 // replace page numbers
7985 $replace = array();
7986 $replace[] = array($ptgu, $ptg_num_chars, 9, $pnalias[2]['u']);
7987 $replace[] = array($ptga, $ptg_num_chars, 7, $pnalias[2]['a']);
7988 $replace[] = array($pngu, $png_num_chars, 9, $pnalias[3]['u']);
7989 $replace[] = array($pnga, $png_num_chars, 7, $pnalias[3]['a']);
7990 list($temppage, $gdiff) = TCPDF_STATIC::replacePageNumAliases($temppage, $replace, $gdiff);
7991 }
7992 // replace page numbers
7993 $replace = array();
7994 $replace[] = array($ptpu, $ptp_num_chars, 9, $pnalias[0]['u']);
7995 $replace[] = array($ptpa, $ptp_num_chars, 7, $pnalias[0]['a']);
7996 $replace[] = array($pnpu, $pnp_num_chars, 9, $pnalias[1]['u']);
7997 $replace[] = array($pnpa, $pnp_num_chars, 7, $pnalias[1]['a']);
7998 list($temppage, $pdiff) = TCPDF_STATIC::replacePageNumAliases($temppage, $replace, $pdiff);
7999 // replace right shift alias
8000 $temppage = $this->replaceRightShiftPageNumAliases($temppage, $pnalias[4], max($pdiff, $gdiff));
8001 // replace EPS marker
8002 $temppage = str_replace($this->epsmarker, '', $temppage);
8003 //Page
8004 $this->page_obj_id[$n] = $this->_newobj();
8005 $out = '<<';
8006 $out .= ' /Type /Page';
8007 $out .= ' /Parent 1 0 R';
8008 if (empty($this->signature_data['approval']) OR ($this->signature_data['approval'] != 'A')) {
8009 $out .= ' /LastModified '.$this->_datestring(0, $this->doc_modification_timestamp);
8010 }
8011 $out .= ' /Resources 2 0 R';
8012 foreach ($this->page_boxes as $box) {
8013 $out .= ' /'.$box;
8014 $out .= sprintf(' [%F %F %F %F]', $this->pagedim[$n][$box]['llx'], $this->pagedim[$n][$box]['lly'], $this->pagedim[$n][$box]['urx'], $this->pagedim[$n][$box]['ury']);
8015 }
8016 if (isset($this->pagedim[$n]['BoxColorInfo']) AND !empty($this->pagedim[$n]['BoxColorInfo'])) {
8017 $out .= ' /BoxColorInfo <<';
8018 foreach ($this->page_boxes as $box) {
8019 if (isset($this->pagedim[$n]['BoxColorInfo'][$box])) {
8020 $out .= ' /'.$box.' <<';
8021 if (isset($this->pagedim[$n]['BoxColorInfo'][$box]['C'])) {
8022 $color = $this->pagedim[$n]['BoxColorInfo'][$box]['C'];
8023 $out .= ' /C [';
8024 $out .= sprintf(' %F %F %F', ($color[0] / 255), ($color[1] / 255), ($color[2] / 255));
8025 $out .= ' ]';
8026 }
8027 if (isset($this->pagedim[$n]['BoxColorInfo'][$box]['W'])) {
8028 $out .= ' /W '.($this->pagedim[$n]['BoxColorInfo'][$box]['W'] * $this->k);
8029 }
8030 if (isset($this->pagedim[$n]['BoxColorInfo'][$box]['S'])) {
8031 $out .= ' /S /'.$this->pagedim[$n]['BoxColorInfo'][$box]['S'];
8032 }
8033 if (isset($this->pagedim[$n]['BoxColorInfo'][$box]['D'])) {
8034 $dashes = $this->pagedim[$n]['BoxColorInfo'][$box]['D'];
8035 $out .= ' /D [';
8036 foreach ($dashes as $dash) {
8037 $out .= sprintf(' %F', ($dash * $this->k));
8038 }
8039 $out .= ' ]';
8040 }
8041 $out .= ' >>';
8042 }
8043 }
8044 $out .= ' >>';
8045 }
8046 $out .= ' /Contents '.($this->n + 1).' 0 R';
8047 $out .= ' /Rotate '.$this->pagedim[$n]['Rotate'];
8048 if (!$this->pdfa_mode) {
8049 $out .= ' /Group << /Type /Group /S /Transparency /CS /DeviceRGB >>';
8050 }
8051 if (isset($this->pagedim[$n]['trans']) AND !empty($this->pagedim[$n]['trans'])) {
8052 // page transitions
8053 if (isset($this->pagedim[$n]['trans']['Dur'])) {
8054 $out .= ' /Dur '.$this->pagedim[$n]['trans']['Dur'];
8055 }
8056 $out .= ' /Trans <<';
8057 $out .= ' /Type /Trans';
8058 if (isset($this->pagedim[$n]['trans']['S'])) {
8059 $out .= ' /S /'.$this->pagedim[$n]['trans']['S'];
8060 }
8061 if (isset($this->pagedim[$n]['trans']['D'])) {
8062 $out .= ' /D '.$this->pagedim[$n]['trans']['D'];
8063 }
8064 if (isset($this->pagedim[$n]['trans']['Dm'])) {
8065 $out .= ' /Dm /'.$this->pagedim[$n]['trans']['Dm'];
8066 }
8067 if (isset($this->pagedim[$n]['trans']['M'])) {
8068 $out .= ' /M /'.$this->pagedim[$n]['trans']['M'];
8069 }
8070 if (isset($this->pagedim[$n]['trans']['Di'])) {
8071 $out .= ' /Di '.$this->pagedim[$n]['trans']['Di'];
8072 }
8073 if (isset($this->pagedim[$n]['trans']['SS'])) {
8074 $out .= ' /SS '.$this->pagedim[$n]['trans']['SS'];
8075 }
8076 if (isset($this->pagedim[$n]['trans']['B'])) {
8077 $out .= ' /B '.$this->pagedim[$n]['trans']['B'];
8078 }
8079 $out .= ' >>';
8080 }
8081 $out .= $this->_getannotsrefs($n);
8082 $out .= ' /PZ '.$this->pagedim[$n]['PZ'];
8083 $out .= ' >>';
8084 $out .= "\n".'endobj';
8085 $this->_out($out);
8086 //Page content
8087 $p = ($this->compress) ? gzcompress($temppage) : $temppage;
8088 $this->_newobj();
8089 $p = $this->_getrawstream($p);
8090 $this->_out('<<'.$filter.'/Length '.strlen($p).'>> stream'."\n".$p."\n".'endstream'."\n".'endobj');
8091 if ($this->diskcache) {
8092 // remove temporary files
8093 unlink($this->pages[$n]);
8094 }
8095 }
8096 //Pages root
8097 $out = $this->_getobj(1)."\n";
8098 $out .= '<< /Type /Pages /Kids [';
8099 foreach($this->page_obj_id as $page_obj) {
8100 $out .= ' '.$page_obj.' 0 R';
8101 }
8102 $out .= ' ] /Count '.$num_pages.' >>';
8103 $out .= "\n".'endobj';
8104 $this->_out($out);
8105 }
8106
8107 /**
8108 * Output references to page annotations
8109 * @param $n (int) page number
8110 * @protected
8111 * @author Nicola Asuni
8112 * @since 4.7.000 (2008-08-29)
8113 * @deprecated
8114 */
8115 protected function _putannotsrefs($n) {
8116 $this->_out($this->_getannotsrefs($n));
8117 }
8118
8119 /**
8120 * Get references to page annotations.
8121 * @param $n (int) page number
8122 * @return string
8123 * @protected
8124 * @author Nicola Asuni
8125 * @since 5.0.010 (2010-05-17)
8126 */
8127 protected function _getannotsrefs($n) {
8128 if (!(isset($this->PageAnnots[$n]) OR ($this->sign AND isset($this->signature_data['cert_type'])))) {
8129 return '';
8130 }
8131 $out = ' /Annots [';
8132 if (isset($this->PageAnnots[$n])) {
8133 foreach ($this->PageAnnots[$n] as $key => $val) {
8134 if (!in_array($val['n'], $this->radio_groups)) {
8135 $out .= ' '.$val['n'].' 0 R';
8136 }
8137 }
8138 // add radiobutton groups
8139 if (isset($this->radiobutton_groups[$n])) {
8140 foreach ($this->radiobutton_groups[$n] as $key => $data) {
8141 if (isset($data['n'])) {
8142 $out .= ' '.$data['n'].' 0 R';
8143 }
8144 }
8145 }
8146 }
8147 if ($this->sign AND ($n == $this->signature_appearance['page']) AND isset($this->signature_data['cert_type'])) {
8148 // set reference for signature object
8149 $out .= ' '.$this->sig_obj_id.' 0 R';
8150 }
8151 if (!empty($this->empty_signature_appearance)) {
8152 foreach ($this->empty_signature_appearance as $esa) {
8153 if ($esa['page'] == $n) {
8154 // set reference for empty signature objects
8155 $out .= ' '.$esa['objid'].' 0 R';
8156 }
8157 }
8158 }
8159 $out .= ' ]';
8160 return $out;
8161 }
8162
8163 /**
8164 * Output annotations objects for all pages.
8165 * !!! THIS METHOD IS NOT YET COMPLETED !!!
8166 * See section 12.5 of PDF 32000_2008 reference.
8167 * @protected
8168 * @author Nicola Asuni
8169 * @since 4.0.018 (2008-08-06)
8170 */
8171 protected function _putannotsobjs() {
8172 // reset object counter
8173 for ($n=1; $n <= $this->numpages; ++$n) {
8174 if (isset($this->PageAnnots[$n])) {
8175 // set page annotations
8176 foreach ($this->PageAnnots[$n] as $key => $pl) {
8177 $annot_obj_id = $this->PageAnnots[$n][$key]['n'];
8178 // create annotation object for grouping radiobuttons
8179 if (isset($this->radiobutton_groups[$n][$pl['txt']]) AND is_array($this->radiobutton_groups[$n][$pl['txt']])) {
8180 $radio_button_obj_id = $this->radiobutton_groups[$n][$pl['txt']]['n'];
8181 $annots = '<<';
8182 $annots .= ' /Type /Annot';
8183 $annots .= ' /Subtype /Widget';
8184 $annots .= ' /Rect [0 0 0 0]';
8185 if ($this->radiobutton_groups[$n][$pl['txt']]['#readonly#']) {
8186 // read only
8187 $annots .= ' /F 68';
8188 $annots .= ' /Ff 49153';
8189 } else {
8190 $annots .= ' /F 4'; // default print for PDF/A
8191 $annots .= ' /Ff 49152';
8192 }
8193 $annots .= ' /T '.$this->_datastring($pl['txt'], $radio_button_obj_id);
8194 if (isset($pl['opt']['tu']) AND is_string($pl['opt']['tu'])) {
8195 $annots .= ' /TU '.$this->_datastring($pl['opt']['tu'], $radio_button_obj_id);
8196 }
8197 $annots .= ' /FT /Btn';
8198 $annots .= ' /Kids [';
8199 $defval = '';
8200 foreach ($this->radiobutton_groups[$n][$pl['txt']] as $key => $data) {
8201 if (isset($data['kid'])) {
8202 $annots .= ' '.$data['kid'].' 0 R';
8203 if ($data['def'] !== 'Off') {
8204 $defval = $data['def'];
8205 }
8206 }
8207 }
8208 $annots .= ' ]';
8209 if (!empty($defval)) {
8210 $annots .= ' /V /'.$defval;
8211 }
8212 $annots .= ' >>';
8213 $this->_out($this->_getobj($radio_button_obj_id)."\n".$annots."\n".'endobj');
8214 $this->form_obj_id[] = $radio_button_obj_id;
8215 // store object id to be used on Parent entry of Kids
8216 $this->radiobutton_groups[$n][$pl['txt']] = $radio_button_obj_id;
8217 }
8218 $formfield = false;
8219 $pl['opt'] = array_change_key_case($pl['opt'], CASE_LOWER);
8220 $a = $pl['x'] * $this->k;
8221 $b = $this->pagedim[$n]['h'] - (($pl['y'] + $pl['h']) * $this->k);
8222 $c = $pl['w'] * $this->k;
8223 $d = $pl['h'] * $this->k;
8224 $rect = sprintf('%F %F %F %F', $a, $b, $a+$c, $b+$d);
8225 // create new annotation object
8226 $annots = '<</Type /Annot';
8227 $annots .= ' /Subtype /'.$pl['opt']['subtype'];
8228 $annots .= ' /Rect ['.$rect.']';
8229 $ft = array('Btn', 'Tx', 'Ch', 'Sig');
8230 if (isset($pl['opt']['ft']) AND in_array($pl['opt']['ft'], $ft)) {
8231 $annots .= ' /FT /'.$pl['opt']['ft'];
8232 $formfield = true;
8233 }
8234 $annots .= ' /Contents '.$this->_textstring($pl['txt'], $annot_obj_id);
8235 $annots .= ' /P '.$this->page_obj_id[$n].' 0 R';
8236 $annots .= ' /NM '.$this->_datastring(sprintf('%04u-%04u', $n, $key), $annot_obj_id);
8237 $annots .= ' /M '.$this->_datestring($annot_obj_id, $this->doc_modification_timestamp);
8238 if (isset($pl['opt']['f'])) {
8239 $fval = 0;
8240 if (is_array($pl['opt']['f'])) {
8241 foreach ($pl['opt']['f'] as $f) {
8242 switch (strtolower($f)) {
8243 case 'invisible': {
8244 $fval += 1 << 0;
8245 break;
8246 }
8247 case 'hidden': {
8248 $fval += 1 << 1;
8249 break;
8250 }
8251 case 'print': {
8252 $fval += 1 << 2;
8253 break;
8254 }
8255 case 'nozoom': {
8256 $fval += 1 << 3;
8257 break;
8258 }
8259 case 'norotate': {
8260 $fval += 1 << 4;
8261 break;
8262 }
8263 case 'noview': {
8264 $fval += 1 << 5;
8265 break;
8266 }
8267 case 'readonly': {
8268 $fval += 1 << 6;
8269 break;
8270 }
8271 case 'locked': {
8272 $fval += 1 << 8;
8273 break;
8274 }
8275 case 'togglenoview': {
8276 $fval += 1 << 9;
8277 break;
8278 }
8279 case 'lockedcontents': {
8280 $fval += 1 << 10;
8281 break;
8282 }
8283 default: {
8284 break;
8285 }
8286 }
8287 }
8288 } else {
8289 $fval = intval($pl['opt']['f']);
8290 }
8291 } else {
8292 $fval = 4;
8293 }
8294 if ($this->pdfa_mode) {
8295 // force print flag for PDF/A mode
8296 $fval |= 4;
8297 }
8298 $annots .= ' /F '.intval($fval);
8299 if (isset($pl['opt']['as']) AND is_string($pl['opt']['as'])) {
8300 $annots .= ' /AS /'.$pl['opt']['as'];
8301 }
8302 if (isset($pl['opt']['ap'])) {
8303 // appearance stream
8304 $annots .= ' /AP <<';
8305 if (is_array($pl['opt']['ap'])) {
8306 foreach ($pl['opt']['ap'] as $apmode => $apdef) {
8307 // $apmode can be: n = normal; r = rollover; d = down;
8308 $annots .= ' /'.strtoupper($apmode);
8309 if (is_array($apdef)) {
8310 $annots .= ' <<';
8311 foreach ($apdef as $apstate => $stream) {
8312 // reference to XObject that define the appearance for this mode-state
8313 $apsobjid = $this->_putAPXObject($c, $d, $stream);
8314 $annots .= ' /'.$apstate.' '.$apsobjid.' 0 R';
8315 }
8316 $annots .= ' >>';
8317 } else {
8318 // reference to XObject that define the appearance for this mode
8319 $apsobjid = $this->_putAPXObject($c, $d, $apdef);
8320 $annots .= ' '.$apsobjid.' 0 R';
8321 }
8322 }
8323 } else {
8324 $annots .= $pl['opt']['ap'];
8325 }
8326 $annots .= ' >>';
8327 }
8328 if (isset($pl['opt']['bs']) AND (is_array($pl['opt']['bs']))) {
8329 $annots .= ' /BS <<';
8330 $annots .= ' /Type /Border';
8331 if (isset($pl['opt']['bs']['w'])) {
8332 $annots .= ' /W '.intval($pl['opt']['bs']['w']);
8333 }
8334 $bstyles = array('S', 'D', 'B', 'I', 'U');
8335 if (isset($pl['opt']['bs']['s']) AND in_array($pl['opt']['bs']['s'], $bstyles)) {
8336 $annots .= ' /S /'.$pl['opt']['bs']['s'];
8337 }
8338 if (isset($pl['opt']['bs']['d']) AND (is_array($pl['opt']['bs']['d']))) {
8339 $annots .= ' /D [';
8340 foreach ($pl['opt']['bs']['d'] as $cord) {
8341 $annots .= ' '.intval($cord);
8342 }
8343 $annots .= ']';
8344 }
8345 $annots .= ' >>';
8346 } else {
8347 $annots .= ' /Border [';
8348 if (isset($pl['opt']['border']) AND (count($pl['opt']['border']) >= 3)) {
8349 $annots .= intval($pl['opt']['border'][0]).' ';
8350 $annots .= intval($pl['opt']['border'][1]).' ';
8351 $annots .= intval($pl['opt']['border'][2]);
8352 if (isset($pl['opt']['border'][3]) AND is_array($pl['opt']['border'][3])) {
8353 $annots .= ' [';
8354 foreach ($pl['opt']['border'][3] as $dash) {
8355 $annots .= intval($dash).' ';
8356 }
8357 $annots .= ']';
8358 }
8359 } else {
8360 $annots .= '0 0 0';
8361 }
8362 $annots .= ']';
8363 }
8364 if (isset($pl['opt']['be']) AND (is_array($pl['opt']['be']))) {
8365 $annots .= ' /BE <<';
8366 $bstyles = array('S', 'C');
8367 if (isset($pl['opt']['be']['s']) AND in_array($pl['opt']['be']['s'], $bstyles)) {
8368 $annots .= ' /S /'.$pl['opt']['bs']['s'];
8369 } else {
8370 $annots .= ' /S /S';
8371 }
8372 if (isset($pl['opt']['be']['i']) AND ($pl['opt']['be']['i'] >= 0) AND ($pl['opt']['be']['i'] <= 2)) {
8373 $annots .= ' /I '.sprintf(' %F', $pl['opt']['be']['i']);
8374 }
8375 $annots .= '>>';
8376 }
8377 if (isset($pl['opt']['c']) AND (is_array($pl['opt']['c'])) AND !empty($pl['opt']['c'])) {
8378 $annots .= ' /C '.TCPDF_COLORS::getColorStringFromArray($pl['opt']['c']);
8379 }
8380 //$annots .= ' /StructParent ';
8381 //$annots .= ' /OC ';
8382 $markups = array('text', 'freetext', 'line', 'square', 'circle', 'polygon', 'polyline', 'highlight', 'underline', 'squiggly', 'strikeout', 'stamp', 'caret', 'ink', 'fileattachment', 'sound');
8383 if (in_array(strtolower($pl['opt']['subtype']), $markups)) {
8384 // this is a markup type
8385 if (isset($pl['opt']['t']) AND is_string($pl['opt']['t'])) {
8386 $annots .= ' /T '.$this->_textstring($pl['opt']['t'], $annot_obj_id);
8387 }
8388 //$annots .= ' /Popup ';
8389 if (isset($pl['opt']['ca'])) {
8390 $annots .= ' /CA '.sprintf('%F', floatval($pl['opt']['ca']));
8391 }
8392 if (isset($pl['opt']['rc'])) {
8393 $annots .= ' /RC '.$this->_textstring($pl['opt']['rc'], $annot_obj_id);
8394 }
8395 $annots .= ' /CreationDate '.$this->_datestring($annot_obj_id, $this->doc_creation_timestamp);
8396 //$annots .= ' /IRT ';
8397 if (isset($pl['opt']['subj'])) {
8398 $annots .= ' /Subj '.$this->_textstring($pl['opt']['subj'], $annot_obj_id);
8399 }
8400 //$annots .= ' /RT ';
8401 //$annots .= ' /IT ';
8402 //$annots .= ' /ExData ';
8403 }
8404 $lineendings = array('Square', 'Circle', 'Diamond', 'OpenArrow', 'ClosedArrow', 'None', 'Butt', 'ROpenArrow', 'RClosedArrow', 'Slash');
8405 // Annotation types
8406 switch (strtolower($pl['opt']['subtype'])) {
8407 case 'text': {
8408 if (isset($pl['opt']['open'])) {
8409 $annots .= ' /Open '. (strtolower($pl['opt']['open']) == 'true' ? 'true' : 'false');
8410 }
8411 $iconsapp = array('Comment', 'Help', 'Insert', 'Key', 'NewParagraph', 'Note', 'Paragraph');
8412 if (isset($pl['opt']['name']) AND in_array($pl['opt']['name'], $iconsapp)) {
8413 $annots .= ' /Name /'.$pl['opt']['name'];
8414 } else {
8415 $annots .= ' /Name /Note';
8416 }
8417 $statemodels = array('Marked', 'Review');
8418 if (isset($pl['opt']['statemodel']) AND in_array($pl['opt']['statemodel'], $statemodels)) {
8419 $annots .= ' /StateModel /'.$pl['opt']['statemodel'];
8420 } else {
8421 $pl['opt']['statemodel'] = 'Marked';
8422 $annots .= ' /StateModel /'.$pl['opt']['statemodel'];
8423 }
8424 if ($pl['opt']['statemodel'] == 'Marked') {
8425 $states = array('Accepted', 'Unmarked');
8426 } else {
8427 $states = array('Accepted', 'Rejected', 'Cancelled', 'Completed', 'None');
8428 }
8429 if (isset($pl['opt']['state']) AND in_array($pl['opt']['state'], $states)) {
8430 $annots .= ' /State /'.$pl['opt']['state'];
8431 } else {
8432 if ($pl['opt']['statemodel'] == 'Marked') {
8433 $annots .= ' /State /Unmarked';
8434 } else {
8435 $annots .= ' /State /None';
8436 }
8437 }
8438 break;
8439 }
8440 case 'link': {
8441 if (is_string($pl['txt'])) {
8442 if ($pl['txt'][0] == '#') {
8443 // internal destination
8444 $annots .= ' /Dest /'.TCPDF_STATIC::encodeNameObject(substr($pl['txt'], 1));
8445 } elseif ($pl['txt'][0] == '%') {
8446 // embedded PDF file
8447 $filename = basename(substr($pl['txt'], 1));
8448 $annots .= ' /A << /S /GoToE /D [0 /Fit] /NewWindow true /T << /R /C /P '.($n - 1).' /A '.$this->embeddedfiles[$filename]['a'].' >> >>';
8449 } elseif ($pl['txt'][0] == '*') {
8450 // embedded generic file
8451 $filename = basename(substr($pl['txt'], 1));
8452 $jsa = 'var D=event.target.doc;var MyData=D.dataObjects;for (var i in MyData) if (MyData[i].path=="'.$filename.'") D.exportDataObject( { cName : MyData[i].name, nLaunch : 2});';
8453 $annots .= ' /A << /S /JavaScript /JS '.$this->_textstring($jsa, $annot_obj_id).'>>';
8454 } else {
8455 $parsedUrl = parse_url($pl['txt']);
8456 if (empty($parsedUrl['scheme']) AND (strtolower(substr($parsedUrl['path'], -4)) == '.pdf')) {
8457 // relative link to a PDF file
8458 $dest = '[0 /Fit]'; // default page 0
8459 if (!empty($parsedUrl['fragment'])) {
8460 // check for named destination
8461 $tmp = explode('=', $parsedUrl['fragment']);
8462 $dest = '('.((count($tmp) == 2) ? $tmp[1] : $tmp[0]).')';
8463 }
8464 $annots .= ' /A <</S /GoToR /D '.$dest.' /F '.$this->_datastring($this->unhtmlentities($parsedUrl['path']), $annot_obj_id).' /NewWindow true>>';
8465 } else {
8466 // external URI link
8467 $annots .= ' /A <</S /URI /URI '.$this->_datastring($this->unhtmlentities($pl['txt']), $annot_obj_id).'>>';
8468 }
8469 }
8470 } elseif (isset($this->links[$pl['txt']])) {
8471 // internal link ID
8472 $l = $this->links[$pl['txt']];
8473 if (isset($this->page_obj_id[($l['p'])])) {
8474 $annots .= sprintf(' /Dest [%u 0 R /XYZ 0 %F null]', $this->page_obj_id[($l['p'])], ($this->pagedim[$l['p']]['h'] - ($l['y'] * $this->k)));
8475 }
8476 }
8477 $hmodes = array('N', 'I', 'O', 'P');
8478 if (isset($pl['opt']['h']) AND in_array($pl['opt']['h'], $hmodes)) {
8479 $annots .= ' /H /'.$pl['opt']['h'];
8480 } else {
8481 $annots .= ' /H /I';
8482 }
8483 //$annots .= ' /PA ';
8484 //$annots .= ' /Quadpoints ';
8485 break;
8486 }
8487 case 'freetext': {
8488 if (isset($pl['opt']['da']) AND !empty($pl['opt']['da'])) {
8489 $annots .= ' /DA ('.$pl['opt']['da'].')';
8490 }
8491 if (isset($pl['opt']['q']) AND ($pl['opt']['q'] >= 0) AND ($pl['opt']['q'] <= 2)) {
8492 $annots .= ' /Q '.intval($pl['opt']['q']);
8493 }
8494 if (isset($pl['opt']['rc'])) {
8495 $annots .= ' /RC '.$this->_textstring($pl['opt']['rc'], $annot_obj_id);
8496 }
8497 if (isset($pl['opt']['ds'])) {
8498 $annots .= ' /DS '.$this->_textstring($pl['opt']['ds'], $annot_obj_id);
8499 }
8500 if (isset($pl['opt']['cl']) AND is_array($pl['opt']['cl'])) {
8501 $annots .= ' /CL [';
8502 foreach ($pl['opt']['cl'] as $cl) {
8503 $annots .= sprintf('%F ', $cl * $this->k);
8504 }
8505 $annots .= ']';
8506 }
8507 $tfit = array('FreeText', 'FreeTextCallout', 'FreeTextTypeWriter');
8508 if (isset($pl['opt']['it']) AND in_array($pl['opt']['it'], $tfit)) {
8509 $annots .= ' /IT /'.$pl['opt']['it'];
8510 }
8511 if (isset($pl['opt']['rd']) AND is_array($pl['opt']['rd'])) {
8512 $l = $pl['opt']['rd'][0] * $this->k;
8513 $r = $pl['opt']['rd'][1] * $this->k;
8514 $t = $pl['opt']['rd'][2] * $this->k;
8515 $b = $pl['opt']['rd'][3] * $this->k;
8516 $annots .= ' /RD ['.sprintf('%F %F %F %F', $l, $r, $t, $b).']';
8517 }
8518 if (isset($pl['opt']['le']) AND in_array($pl['opt']['le'], $lineendings)) {
8519 $annots .= ' /LE /'.$pl['opt']['le'];
8520 }
8521 break;
8522 }
8523 case 'line': {
8524 break;
8525 }
8526 case 'square': {
8527 break;
8528 }
8529 case 'circle': {
8530 break;
8531 }
8532 case 'polygon': {
8533 break;
8534 }
8535 case 'polyline': {
8536 break;
8537 }
8538 case 'highlight': {
8539 break;
8540 }
8541 case 'underline': {
8542 break;
8543 }
8544 case 'squiggly': {
8545 break;
8546 }
8547 case 'strikeout': {
8548 break;
8549 }
8550 case 'stamp': {
8551 break;
8552 }
8553 case 'caret': {
8554 break;
8555 }
8556 case 'ink': {
8557 break;
8558 }
8559 case 'popup': {
8560 break;
8561 }
8562 case 'fileattachment': {
8563 if ($this->pdfa_mode) {
8564 // embedded files are not allowed in PDF/A mode
8565 break;
8566 }
8567 if (!isset($pl['opt']['fs'])) {
8568 break;
8569 }
8570 $filename = basename($pl['opt']['fs']);
8571 if (isset($this->embeddedfiles[$filename]['f'])) {
8572 $annots .= ' /FS '.$this->embeddedfiles[$filename]['f'].' 0 R';
8573 $iconsapp = array('Graph', 'Paperclip', 'PushPin', 'Tag');
8574 if (isset($pl['opt']['name']) AND in_array($pl['opt']['name'], $iconsapp)) {
8575 $annots .= ' /Name /'.$pl['opt']['name'];
8576 } else {
8577 $annots .= ' /Name /PushPin';
8578 }
8579 // index (zero-based) of the annotation in the Annots array of this page
8580 $this->embeddedfiles[$filename]['a'] = $key;
8581 }
8582 break;
8583 }
8584 case 'sound': {
8585 if (!isset($pl['opt']['fs'])) {
8586 break;
8587 }
8588 $filename = basename($pl['opt']['fs']);
8589 if (isset($this->embeddedfiles[$filename]['f'])) {
8590 // ... TO BE COMPLETED ...
8591 // /R /C /B /E /CO /CP
8592 $annots .= ' /Sound '.$this->embeddedfiles[$filename]['f'].' 0 R';
8593 $iconsapp = array('Speaker', 'Mic');
8594 if (isset($pl['opt']['name']) AND in_array($pl['opt']['name'], $iconsapp)) {
8595 $annots .= ' /Name /'.$pl['opt']['name'];
8596 } else {
8597 $annots .= ' /Name /Speaker';
8598 }
8599 }
8600 break;
8601 }
8602 case 'movie': {
8603 break;
8604 }
8605 case 'widget': {
8606 $hmode = array('N', 'I', 'O', 'P', 'T');
8607 if (isset($pl['opt']['h']) AND in_array($pl['opt']['h'], $hmode)) {
8608 $annots .= ' /H /'.$pl['opt']['h'];
8609 }
8610 if (isset($pl['opt']['mk']) AND (is_array($pl['opt']['mk'])) AND !empty($pl['opt']['mk'])) {
8611 $annots .= ' /MK <<';
8612 if (isset($pl['opt']['mk']['r'])) {
8613 $annots .= ' /R '.$pl['opt']['mk']['r'];
8614 }
8615 if (isset($pl['opt']['mk']['bc']) AND (is_array($pl['opt']['mk']['bc']))) {
8616 $annots .= ' /BC '.TCPDF_COLORS::getColorStringFromArray($pl['opt']['mk']['bc']);
8617 }
8618 if (isset($pl['opt']['mk']['bg']) AND (is_array($pl['opt']['mk']['bg']))) {
8619 $annots .= ' /BG '.TCPDF_COLORS::getColorStringFromArray($pl['opt']['mk']['bg']);
8620 }
8621 if (isset($pl['opt']['mk']['ca'])) {
8622 $annots .= ' /CA '.$pl['opt']['mk']['ca'];
8623 }
8624 if (isset($pl['opt']['mk']['rc'])) {
8625 $annots .= ' /RC '.$pl['opt']['mk']['rc'];
8626 }
8627 if (isset($pl['opt']['mk']['ac'])) {
8628 $annots .= ' /AC '.$pl['opt']['mk']['ac'];
8629 }
8630 if (isset($pl['opt']['mk']['i'])) {
8631 $info = $this->getImageBuffer($pl['opt']['mk']['i']);
8632 if ($info !== false) {
8633 $annots .= ' /I '.$info['n'].' 0 R';
8634 }
8635 }
8636 if (isset($pl['opt']['mk']['ri'])) {
8637 $info = $this->getImageBuffer($pl['opt']['mk']['ri']);
8638 if ($info !== false) {
8639 $annots .= ' /RI '.$info['n'].' 0 R';
8640 }
8641 }
8642 if (isset($pl['opt']['mk']['ix'])) {
8643 $info = $this->getImageBuffer($pl['opt']['mk']['ix']);
8644 if ($info !== false) {
8645 $annots .= ' /IX '.$info['n'].' 0 R';
8646 }
8647 }
8648 if (isset($pl['opt']['mk']['if']) AND (is_array($pl['opt']['mk']['if'])) AND !empty($pl['opt']['mk']['if'])) {
8649 $annots .= ' /IF <<';
8650 $if_sw = array('A', 'B', 'S', 'N');
8651 if (isset($pl['opt']['mk']['if']['sw']) AND in_array($pl['opt']['mk']['if']['sw'], $if_sw)) {
8652 $annots .= ' /SW /'.$pl['opt']['mk']['if']['sw'];
8653 }
8654 $if_s = array('A', 'P');
8655 if (isset($pl['opt']['mk']['if']['s']) AND in_array($pl['opt']['mk']['if']['s'], $if_s)) {
8656 $annots .= ' /S /'.$pl['opt']['mk']['if']['s'];
8657 }
8658 if (isset($pl['opt']['mk']['if']['a']) AND (is_array($pl['opt']['mk']['if']['a'])) AND !empty($pl['opt']['mk']['if']['a'])) {
8659 $annots .= sprintf(' /A [%F %F]', $pl['opt']['mk']['if']['a'][0], $pl['opt']['mk']['if']['a'][1]);
8660 }
8661 if (isset($pl['opt']['mk']['if']['fb']) AND ($pl['opt']['mk']['if']['fb'])) {
8662 $annots .= ' /FB true';
8663 }
8664 $annots .= '>>';
8665 }
8666 if (isset($pl['opt']['mk']['tp']) AND ($pl['opt']['mk']['tp'] >= 0) AND ($pl['opt']['mk']['tp'] <= 6)) {
8667 $annots .= ' /TP '.intval($pl['opt']['mk']['tp']);
8668 }
8669 $annots .= '>>';
8670 } // end MK
8671 // --- Entries for field dictionaries ---
8672 if (isset($this->radiobutton_groups[$n][$pl['txt']])) {
8673 // set parent
8674 $annots .= ' /Parent '.$this->radiobutton_groups[$n][$pl['txt']].' 0 R';
8675 }
8676 if (isset($pl['opt']['t']) AND is_string($pl['opt']['t'])) {
8677 $annots .= ' /T '.$this->_datastring($pl['opt']['t'], $annot_obj_id);
8678 }
8679 if (isset($pl['opt']['tu']) AND is_string($pl['opt']['tu'])) {
8680 $annots .= ' /TU '.$this->_datastring($pl['opt']['tu'], $annot_obj_id);
8681 }
8682 if (isset($pl['opt']['tm']) AND is_string($pl['opt']['tm'])) {
8683 $annots .= ' /TM '.$this->_datastring($pl['opt']['tm'], $annot_obj_id);
8684 }
8685 if (isset($pl['opt']['ff'])) {
8686 if (is_array($pl['opt']['ff'])) {
8687 // array of bit settings
8688 $flag = 0;
8689 foreach($pl['opt']['ff'] as $val) {
8690 $flag += 1 << ($val - 1);
8691 }
8692 } else {
8693 $flag = intval($pl['opt']['ff']);
8694 }
8695 $annots .= ' /Ff '.$flag;
8696 }
8697 if (isset($pl['opt']['maxlen'])) {
8698 $annots .= ' /MaxLen '.intval($pl['opt']['maxlen']);
8699 }
8700 if (isset($pl['opt']['v'])) {
8701 $annots .= ' /V';
8702 if (is_array($pl['opt']['v'])) {
8703 foreach ($pl['opt']['v'] AS $optval) {
8704 if (is_float($optval)) {
8705 $optval = sprintf('%F', $optval);
8706 }
8707 $annots .= ' '.$optval;
8708 }
8709 } else {
8710 $annots .= ' '.$this->_textstring($pl['opt']['v'], $annot_obj_id);
8711 }
8712 }
8713 if (isset($pl['opt']['dv'])) {
8714 $annots .= ' /DV';
8715 if (is_array($pl['opt']['dv'])) {
8716 foreach ($pl['opt']['dv'] AS $optval) {
8717 if (is_float($optval)) {
8718 $optval = sprintf('%F', $optval);
8719 }
8720 $annots .= ' '.$optval;
8721 }
8722 } else {
8723 $annots .= ' '.$this->_textstring($pl['opt']['dv'], $annot_obj_id);
8724 }
8725 }
8726 if (isset($pl['opt']['rv'])) {
8727 $annots .= ' /RV';
8728 if (is_array($pl['opt']['rv'])) {
8729 foreach ($pl['opt']['rv'] AS $optval) {
8730 if (is_float($optval)) {
8731 $optval = sprintf('%F', $optval);
8732 }
8733 $annots .= ' '.$optval;
8734 }
8735 } else {
8736 $annots .= ' '.$this->_textstring($pl['opt']['rv'], $annot_obj_id);
8737 }
8738 }
8739 if (isset($pl['opt']['a']) AND !empty($pl['opt']['a'])) {
8740 $annots .= ' /A << '.$pl['opt']['a'].' >>';
8741 }
8742 if (isset($pl['opt']['aa']) AND !empty($pl['opt']['aa'])) {
8743 $annots .= ' /AA << '.$pl['opt']['aa'].' >>';
8744 }
8745 if (isset($pl['opt']['da']) AND !empty($pl['opt']['da'])) {
8746 $annots .= ' /DA ('.$pl['opt']['da'].')';
8747 }
8748 if (isset($pl['opt']['q']) AND ($pl['opt']['q'] >= 0) AND ($pl['opt']['q'] <= 2)) {
8749 $annots .= ' /Q '.intval($pl['opt']['q']);
8750 }
8751 if (isset($pl['opt']['opt']) AND (is_array($pl['opt']['opt'])) AND !empty($pl['opt']['opt'])) {
8752 $annots .= ' /Opt [';
8753 foreach($pl['opt']['opt'] AS $copt) {
8754 if (is_array($copt)) {
8755 $annots .= ' ['.$this->_textstring($copt[0], $annot_obj_id).' '.$this->_textstring($copt[1], $annot_obj_id).']';
8756 } else {
8757 $annots .= ' '.$this->_textstring($copt, $annot_obj_id);
8758 }
8759 }
8760 $annots .= ']';
8761 }
8762 if (isset($pl['opt']['ti'])) {
8763 $annots .= ' /TI '.intval($pl['opt']['ti']);
8764 }
8765 if (isset($pl['opt']['i']) AND (is_array($pl['opt']['i'])) AND !empty($pl['opt']['i'])) {
8766 $annots .= ' /I [';
8767 foreach($pl['opt']['i'] AS $copt) {
8768 $annots .= intval($copt).' ';
8769 }
8770 $annots .= ']';
8771 }
8772 break;
8773 }
8774 case 'screen': {
8775 break;
8776 }
8777 case 'printermark': {
8778 break;
8779 }
8780 case 'trapnet': {
8781 break;
8782 }
8783 case 'watermark': {
8784 break;
8785 }
8786 case '3d': {
8787 break;
8788 }
8789 default: {
8790 break;
8791 }
8792 }
8793 $annots .= '>>';
8794 // create new annotation object
8795 $this->_out($this->_getobj($annot_obj_id)."\n".$annots."\n".'endobj');
8796 if ($formfield AND !isset($this->radiobutton_groups[$n][$pl['txt']])) {
8797 // store reference of form object
8798 $this->form_obj_id[] = $annot_obj_id;
8799 }
8800 }
8801 }
8802 } // end for each page
8803 }
8804
8805 /**
8806 * Put appearance streams XObject used to define annotation's appearance states.
8807 * @param $w (int) annotation width
8808 * @param $h (int) annotation height
8809 * @param $stream (string) appearance stream
8810 * @return int object ID
8811 * @protected
8812 * @since 4.8.001 (2009-09-09)
8813 */
8814 protected function _putAPXObject($w=0, $h=0, $stream='') {
8815 $stream = trim($stream);
8816 $out = $this->_getobj()."\n";
8817 $this->xobjects['AX'.$this->n] = array('n' => $this->n);
8818 $out .= '<<';
8819 $out .= ' /Type /XObject';
8820 $out .= ' /Subtype /Form';
8821 $out .= ' /FormType 1';
8822 if ($this->compress) {
8823 $stream = gzcompress($stream);
8824 $out .= ' /Filter /FlateDecode';
8825 }
8826 $rect = sprintf('%F %F', $w, $h);
8827 $out .= ' /BBox [0 0 '.$rect.']';
8828 $out .= ' /Matrix [1 0 0 1 0 0]';
8829 $out .= ' /Resources 2 0 R';
8830 $stream = $this->_getrawstream($stream);
8831 $out .= ' /Length '.strlen($stream);
8832 $out .= ' >>';
8833 $out .= ' stream'."\n".$stream."\n".'endstream';
8834 $out .= "\n".'endobj';
8835 $this->_out($out);
8836 return $this->n;
8837 }
8838
8839 /**
8840 * Output fonts.
8841 * @author Nicola Asuni
8842 * @protected
8843 */
8844 protected function _putfonts() {
8845 $nf = $this->n;
8846 foreach ($this->diffs as $diff) {
8847 //Encodings
8848 $this->_newobj();
8849 $this->_out('<< /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences ['.$diff.'] >>'."\n".'endobj');
8850 }
8851 $mqr = TCPDF_STATIC::get_mqr();
8852 TCPDF_STATIC::set_mqr(false);
8853 foreach ($this->FontFiles as $file => $info) {
8854 // search and get font file to embedd
8855 $fontfile = TCPDF_FONTS::getFontFullPath($file, $info['fontdir']);
8856 if (!TCPDF_STATIC::empty_string($fontfile)) {
8857 $font = file_get_contents($fontfile);
8858 $compressed = (substr($file, -2) == '.z');
8859 if ((!$compressed) AND (isset($info['length2']))) {
8860 $header = (ord($font[0]) == 128);
8861 if ($header) {
8862 // strip first binary header
8863 $font = substr($font, 6);
8864 }
8865 if ($header AND (ord($font[$info['length1']]) == 128)) {
8866 // strip second binary header
8867 $font = substr($font, 0, $info['length1']).substr($font, ($info['length1'] + 6));
8868 }
8869 } elseif ($info['subset'] AND ((!$compressed) OR ($compressed AND function_exists('gzcompress')))) {
8870 if ($compressed) {
8871 // uncompress font
8872 $font = gzuncompress($font);
8873 }
8874 // merge subset characters
8875 $subsetchars = array(); // used chars
8876 foreach ($info['fontkeys'] as $fontkey) {
8877 $fontinfo = $this->getFontBuffer($fontkey);
8878 $subsetchars += $fontinfo['subsetchars'];
8879 }
8880 // rebuild a font subset
8881 $font = TCPDF_FONTS::_getTrueTypeFontSubset($font, $subsetchars);
8882 // calculate new font length
8883 $info['length1'] = strlen($font);
8884 if ($compressed) {
8885 // recompress font
8886 $font = gzcompress($font);
8887 }
8888 }
8889 $this->_newobj();
8890 $this->FontFiles[$file]['n'] = $this->n;
8891 $stream = $this->_getrawstream($font);
8892 $out = '<< /Length '.strlen($stream);
8893 if ($compressed) {
8894 $out .= ' /Filter /FlateDecode';
8895 }
8896 $out .= ' /Length1 '.$info['length1'];
8897 if (isset($info['length2'])) {
8898 $out .= ' /Length2 '.$info['length2'].' /Length3 0';
8899 }
8900 $out .= ' >>';
8901 $out .= ' stream'."\n".$stream."\n".'endstream';
8902 $out .= "\n".'endobj';
8903 $this->_out($out);
8904 }
8905 }
8906 TCPDF_STATIC::set_mqr($mqr);
8907 foreach ($this->fontkeys as $k) {
8908 //Font objects
8909 $font = $this->getFontBuffer($k);
8910 $type = $font['type'];
8911 $name = $font['name'];
8912 if ($type == 'core') {
8913 // standard core font
8914 $out = $this->_getobj($this->font_obj_ids[$k])."\n";
8915 $out .= '<</Type /Font';
8916 $out .= ' /Subtype /Type1';
8917 $out .= ' /BaseFont /'.$name;
8918 $out .= ' /Name /F'.$font['i'];
8919 if ((strtolower($name) != 'symbol') AND (strtolower($name) != 'zapfdingbats')) {
8920 $out .= ' /Encoding /WinAnsiEncoding';
8921 }
8922 if ($k == 'helvetica') {
8923 // add default font for annotations
8924 $this->annotation_fonts[$k] = $font['i'];
8925 }
8926 $out .= ' >>';
8927 $out .= "\n".'endobj';
8928 $this->_out($out);
8929 } elseif (($type == 'Type1') OR ($type == 'TrueType')) {
8930 // additional Type1 or TrueType font
8931 $out = $this->_getobj($this->font_obj_ids[$k])."\n";
8932 $out .= '<</Type /Font';
8933 $out .= ' /Subtype /'.$type;
8934 $out .= ' /BaseFont /'.$name;
8935 $out .= ' /Name /F'.$font['i'];
8936 $out .= ' /FirstChar 32 /LastChar 255';
8937 $out .= ' /Widths '.($this->n + 1).' 0 R';
8938 $out .= ' /FontDescriptor '.($this->n + 2).' 0 R';
8939 if ($font['enc']) {
8940 if (isset($font['diff'])) {
8941 $out .= ' /Encoding '.($nf + $font['diff']).' 0 R';
8942 } else {
8943 $out .= ' /Encoding /WinAnsiEncoding';
8944 }
8945 }
8946 $out .= ' >>';
8947 $out .= "\n".'endobj';
8948 $this->_out($out);
8949 // Widths
8950 $this->_newobj();
8951 $s = '[';
8952 for ($i = 32; $i < 256; ++$i) {
8953 if (isset($font['cw'][$i])) {
8954 $s .= $font['cw'][$i].' ';
8955 } else {
8956 $s .= $font['dw'].' ';
8957 }
8958 }
8959 $s .= ']';
8960 $s .= "\n".'endobj';
8961 $this->_out($s);
8962 //Descriptor
8963 $this->_newobj();
8964 $s = '<</Type /FontDescriptor /FontName /'.$name;
8965 foreach ($font['desc'] as $fdk => $fdv) {
8966 if (is_float($fdv)) {
8967 $fdv = sprintf('%F', $fdv);
8968 }
8969 $s .= ' /'.$fdk.' '.$fdv.'';
8970 }
8971 if (!TCPDF_STATIC::empty_string($font['file'])) {
8972 $s .= ' /FontFile'.($type == 'Type1' ? '' : '2').' '.$this->FontFiles[$font['file']]['n'].' 0 R';
8973 }
8974 $s .= '>>';
8975 $s .= "\n".'endobj';
8976 $this->_out($s);
8977 } else {
8978 // additional types
8979 $mtd = '_put'.strtolower($type);
8980 if (!method_exists($this, $mtd)) {
8981 $this->Error('Unsupported font type: '.$type);
8982 }
8983 $this->$mtd($font);
8984 }
8985 }
8986 }
8987
8988 /**
8989 * Adds unicode fonts.<br>
8990 * Based on PDF Reference 1.3 (section 5)
8991 * @param $font (array) font data
8992 * @protected
8993 * @author Nicola Asuni
8994 * @since 1.52.0.TC005 (2005-01-05)
8995 */
8996 protected function _puttruetypeunicode($font) {
8997 $fontname = '';
8998 if ($font['subset']) {
8999 // change name for font subsetting
9000 $subtag = sprintf('%06u', $font['i']);
9001 $subtag = strtr($subtag, '0123456789', 'ABCDEFGHIJ');
9002 $fontname .= $subtag.'+';
9003 }
9004 $fontname .= $font['name'];
9005 // Type0 Font
9006 // A composite font composed of other fonts, organized hierarchically
9007 $out = $this->_getobj($this->font_obj_ids[$font['fontkey']])."\n";
9008 $out .= '<< /Type /Font';
9009 $out .= ' /Subtype /Type0';
9010 $out .= ' /BaseFont /'.$fontname;
9011 $out .= ' /Name /F'.$font['i'];
9012 $out .= ' /Encoding /'.$font['enc'];
9013 $out .= ' /ToUnicode '.($this->n + 1).' 0 R';
9014 $out .= ' /DescendantFonts ['.($this->n + 2).' 0 R]';
9015 $out .= ' >>';
9016 $out .= "\n".'endobj';
9017 $this->_out($out);
9018 // ToUnicode map for Identity-H
9019 $stream = TCPDF_FONT_DATA::$uni_identity_h;
9020 // ToUnicode Object
9021 $this->_newobj();
9022 $stream = ($this->compress) ? gzcompress($stream) : $stream;
9023 $filter = ($this->compress) ? '/Filter /FlateDecode ' : '';
9024 $stream = $this->_getrawstream($stream);
9025 $this->_out('<<'.$filter.'/Length '.strlen($stream).'>> stream'."\n".$stream."\n".'endstream'."\n".'endobj');
9026 // CIDFontType2
9027 // A CIDFont whose glyph descriptions are based on TrueType font technology
9028 $oid = $this->_newobj();
9029 $out = '<< /Type /Font';
9030 $out .= ' /Subtype /CIDFontType2';
9031 $out .= ' /BaseFont /'.$fontname;
9032 // A dictionary containing entries that define the character collection of the CIDFont.
9033 $cidinfo = '/Registry '.$this->_datastring($font['cidinfo']['Registry'], $oid);
9034 $cidinfo .= ' /Ordering '.$this->_datastring($font['cidinfo']['Ordering'], $oid);
9035 $cidinfo .= ' /Supplement '.$font['cidinfo']['Supplement'];
9036 $out .= ' /CIDSystemInfo << '.$cidinfo.' >>';
9037 $out .= ' /FontDescriptor '.($this->n + 1).' 0 R';
9038 $out .= ' /DW '.$font['dw']; // default width
9039 $out .= "\n".TCPDF_FONTS::_putfontwidths($font, 0);
9040 if (isset($font['ctg']) AND (!TCPDF_STATIC::empty_string($font['ctg']))) {
9041 $out .= "\n".'/CIDToGIDMap '.($this->n + 2).' 0 R';
9042 }
9043 $out .= ' >>';
9044 $out .= "\n".'endobj';
9045 $this->_out($out);
9046 // Font descriptor
9047 // A font descriptor describing the CIDFont default metrics other than its glyph widths
9048 $this->_newobj();
9049 $out = '<< /Type /FontDescriptor';
9050 $out .= ' /FontName /'.$fontname;
9051 foreach ($font['desc'] as $key => $value) {
9052 if (is_float($value)) {
9053 $value = sprintf('%F', $value);
9054 }
9055 $out .= ' /'.$key.' '.$value;
9056 }
9057 $fontdir = false;
9058 if (!TCPDF_STATIC::empty_string($font['file'])) {
9059 // A stream containing a TrueType font
9060 $out .= ' /FontFile2 '.$this->FontFiles[$font['file']]['n'].' 0 R';
9061 $fontdir = $this->FontFiles[$font['file']]['fontdir'];
9062 }
9063 $out .= ' >>';
9064 $out .= "\n".'endobj';
9065 $this->_out($out);
9066 if (isset($font['ctg']) AND (!TCPDF_STATIC::empty_string($font['ctg']))) {
9067 $this->_newobj();
9068 // Embed CIDToGIDMap
9069 // A specification of the mapping from CIDs to glyph indices
9070 // search and get CTG font file to embedd
9071 $ctgfile = strtolower($font['ctg']);
9072 // search and get ctg font file to embedd
9073 $fontfile = TCPDF_FONTS::getFontFullPath($ctgfile, $fontdir);
9074 if (TCPDF_STATIC::empty_string($fontfile)) {
9075 $this->Error('Font file not found: '.$ctgfile);
9076 }
9077 $stream = $this->_getrawstream(file_get_contents($fontfile));
9078 $out = '<< /Length '.strlen($stream).'';
9079 if (substr($fontfile, -2) == '.z') { // check file extension
9080 // Decompresses data encoded using the public-domain
9081 // zlib/deflate compression method, reproducing the
9082 // original text or binary data
9083 $out .= ' /Filter /FlateDecode';
9084 }
9085 $out .= ' >>';
9086 $out .= ' stream'."\n".$stream."\n".'endstream';
9087 $out .= "\n".'endobj';
9088 $this->_out($out);
9089 }
9090 }
9091
9092 /**
9093 * Output CID-0 fonts.
9094 * A Type 0 CIDFont contains glyph descriptions based on the Adobe Type 1 font format
9095 * @param $font (array) font data
9096 * @protected
9097 * @author Andrew Whitehead, Nicola Asuni, Yukihiro Nakadaira
9098 * @since 3.2.000 (2008-06-23)
9099 */
9100 protected function _putcidfont0($font) {
9101 $cidoffset = 0;
9102 if (!isset($font['cw'][1])) {
9103 $cidoffset = 31;
9104 }
9105 if (isset($font['cidinfo']['uni2cid'])) {
9106 // convert unicode to cid.
9107 $uni2cid = $font['cidinfo']['uni2cid'];
9108 $cw = array();
9109 foreach ($font['cw'] as $uni => $width) {
9110 if (isset($uni2cid[$uni])) {
9111 $cw[($uni2cid[$uni] + $cidoffset)] = $width;
9112 } elseif ($uni < 256) {
9113 $cw[$uni] = $width;
9114 } // else unknown character
9115 }
9116 $font = array_merge($font, array('cw' => $cw));
9117 }
9118 $name = $font['name'];
9119 $enc = $font['enc'];
9120 if ($enc) {
9121 $longname = $name.'-'.$enc;
9122 } else {
9123 $longname = $name;
9124 }
9125 $out = $this->_getobj($this->font_obj_ids[$font['fontkey']])."\n";
9126 $out .= '<</Type /Font';
9127 $out .= ' /Subtype /Type0';
9128 $out .= ' /BaseFont /'.$longname;
9129 $out .= ' /Name /F'.$font['i'];
9130 if ($enc) {
9131 $out .= ' /Encoding /'.$enc;
9132 }
9133 $out .= ' /DescendantFonts ['.($this->n + 1).' 0 R]';
9134 $out .= ' >>';
9135 $out .= "\n".'endobj';
9136 $this->_out($out);
9137 $oid = $this->_newobj();
9138 $out = '<</Type /Font';
9139 $out .= ' /Subtype /CIDFontType0';
9140 $out .= ' /BaseFont /'.$name;
9141 $cidinfo = '/Registry '.$this->_datastring($font['cidinfo']['Registry'], $oid);
9142 $cidinfo .= ' /Ordering '.$this->_datastring($font['cidinfo']['Ordering'], $oid);
9143 $cidinfo .= ' /Supplement '.$font['cidinfo']['Supplement'];
9144 $out .= ' /CIDSystemInfo <<'.$cidinfo.'>>';
9145 $out .= ' /FontDescriptor '.($this->n + 1).' 0 R';
9146 $out .= ' /DW '.$font['dw'];
9147 $out .= "\n".TCPDF_FONTS::_putfontwidths($font, $cidoffset);
9148 $out .= ' >>';
9149 $out .= "\n".'endobj';
9150 $this->_out($out);
9151 $this->_newobj();
9152 $s = '<</Type /FontDescriptor /FontName /'.$name;
9153 foreach ($font['desc'] as $k => $v) {
9154 if ($k != 'Style') {
9155 if (is_float($v)) {
9156 $v = sprintf('%F', $v);
9157 }
9158 $s .= ' /'.$k.' '.$v.'';
9159 }
9160 }
9161 $s .= '>>';
9162 $s .= "\n".'endobj';
9163 $this->_out($s);
9164 }
9165
9166 /**
9167 * Output images.
9168 * @protected
9169 */
9170 protected function _putimages() {
9171 $filter = ($this->compress) ? '/Filter /FlateDecode ' : '';
9172 foreach ($this->imagekeys as $file) {
9173 $info = $this->getImageBuffer($file);
9174 // set object for alternate images array
9175 if ((!$this->pdfa_mode) AND isset($info['altimgs']) AND !empty($info['altimgs'])) {
9176 $altoid = $this->_newobj();
9177 $out = '[';
9178 foreach ($info['altimgs'] as $altimage) {
9179 if (isset($this->xobjects['I'.$altimage[0]]['n'])) {
9180 $out .= ' << /Image '.$this->xobjects['I'.$altimage[0]]['n'].' 0 R';
9181 $out .= ' /DefaultForPrinting';
9182 if ($altimage[1] === true) {
9183 $out .= ' true';
9184 } else {
9185 $out .= ' false';
9186 }
9187 $out .= ' >>';
9188 }
9189 }
9190 $out .= ' ]';
9191 $out .= "\n".'endobj';
9192 $this->_out($out);
9193 }
9194 // set image object
9195 $oid = $this->_newobj();
9196 $this->xobjects['I'.$info['i']] = array('n' => $oid);
9197 $this->setImageSubBuffer($file, 'n', $this->n);
9198 $out = '<</Type /XObject';
9199 $out .= ' /Subtype /Image';
9200 $out .= ' /Width '.$info['w'];
9201 $out .= ' /Height '.$info['h'];
9202 if (array_key_exists('masked', $info)) {
9203 $out .= ' /SMask '.($this->n - 1).' 0 R';
9204 }
9205 // set color space
9206 $icc = false;
9207 if (isset($info['icc']) AND ($info['icc'] !== false)) {
9208 // ICC Colour Space
9209 $icc = true;
9210 $out .= ' /ColorSpace [/ICCBased '.($this->n + 1).' 0 R]';
9211 } elseif ($info['cs'] == 'Indexed') {
9212 // Indexed Colour Space
9213 $out .= ' /ColorSpace [/Indexed /DeviceRGB '.((strlen($info['pal']) / 3) - 1).' '.($this->n + 1).' 0 R]';
9214 } else {
9215 // Device Colour Space
9216 $out .= ' /ColorSpace /'.$info['cs'];
9217 }
9218 if ($info['cs'] == 'DeviceCMYK') {
9219 $out .= ' /Decode [1 0 1 0 1 0 1 0]';
9220 }
9221 $out .= ' /BitsPerComponent '.$info['bpc'];
9222 if (isset($altoid) AND ($altoid > 0)) {
9223 // reference to alternate images dictionary
9224 $out .= ' /Alternates '.$altoid.' 0 R';
9225 }
9226 if (isset($info['exurl']) AND !empty($info['exurl'])) {
9227 // external stream
9228 $out .= ' /Length 0';
9229 $out .= ' /F << /FS /URL /F '.$this->_datastring($info['exurl'], $oid).' >>';
9230 if (isset($info['f'])) {
9231 $out .= ' /FFilter /'.$info['f'];
9232 }
9233 $out .= ' >>';
9234 $out .= ' stream'."\n".'endstream';
9235 } else {
9236 if (isset($info['f'])) {
9237 $out .= ' /Filter /'.$info['f'];
9238 }
9239 if (isset($info['parms'])) {
9240 $out .= ' '.$info['parms'];
9241 }
9242 if (isset($info['trns']) AND is_array($info['trns'])) {
9243 $trns = '';
9244 $count_info = count($info['trns']);
9245 if ($info['cs'] == 'Indexed') {
9246 $maxval =(pow(2, $info['bpc']) - 1);
9247 for ($i = 0; $i < $count_info; ++$i) {
9248 if (($info['trns'][$i] != 0) AND ($info['trns'][$i] != $maxval)) {
9249 // this is not a binary type mask @TODO: create a SMask
9250 $trns = '';
9251 break;
9252 } elseif (empty($trns) AND ($info['trns'][$i] == 0)) {
9253 // store the first fully transparent value
9254 $trns .= $i.' '.$i.' ';
9255 }
9256 }
9257 } else {
9258 // grayscale or RGB
9259 for ($i = 0; $i < $count_info; ++$i) {
9260 if ($info['trns'][$i] == 0) {
9261 $trns .= $info['trns'][$i].' '.$info['trns'][$i].' ';
9262 }
9263 }
9264 }
9265 // Colour Key Masking
9266 if (!empty($trns)) {
9267 $out .= ' /Mask ['.$trns.']';
9268 }
9269 }
9270 $stream = $this->_getrawstream($info['data']);
9271 $out .= ' /Length '.strlen($stream).' >>';
9272 $out .= ' stream'."\n".$stream."\n".'endstream';
9273 }
9274 $out .= "\n".'endobj';
9275 $this->_out($out);
9276 if ($icc) {
9277 // ICC colour profile
9278 $this->_newobj();
9279 $icc = ($this->compress) ? gzcompress($info['icc']) : $info['icc'];
9280 $icc = $this->_getrawstream($icc);
9281 $this->_out('<</N '.$info['ch'].' /Alternate /'.$info['cs'].' '.$filter.'/Length '.strlen($icc).'>> stream'."\n".$icc."\n".'endstream'."\n".'endobj');
9282 } elseif ($info['cs'] == 'Indexed') {
9283 // colour palette
9284 $this->_newobj();
9285 $pal = ($this->compress) ? gzcompress($info['pal']) : $info['pal'];
9286 $pal = $this->_getrawstream($pal);
9287 $this->_out('<<'.$filter.'/Length '.strlen($pal).'>> stream'."\n".$pal."\n".'endstream'."\n".'endobj');
9288 }
9289 }
9290 }
9291
9292 /**
9293 * Output Form XObjects Templates.
9294 * @author Nicola Asuni
9295 * @since 5.8.017 (2010-08-24)
9296 * @protected
9297 * @see startTemplate(), endTemplate(), printTemplate()
9298 */
9299 protected function _putxobjects() {
9300 foreach ($this->xobjects as $key => $data) {
9301 if (isset($data['outdata'])) {
9302 $stream = str_replace($this->epsmarker, '', trim($data['outdata']));
9303 $out = $this->_getobj($data['n'])."\n";
9304 $out .= '<<';
9305 $out .= ' /Type /XObject';
9306 $out .= ' /Subtype /Form';
9307 $out .= ' /FormType 1';
9308 if ($this->compress) {
9309 $stream = gzcompress($stream);
9310 $out .= ' /Filter /FlateDecode';
9311 }
9312 $out .= sprintf(' /BBox [%F %F %F %F]', ($data['x'] * $this->k), (-$data['y'] * $this->k), (($data['w'] + $data['x']) * $this->k), (($data['h'] - $data['y']) * $this->k));
9313 $out .= ' /Matrix [1 0 0 1 0 0]';
9314 $out .= ' /Resources <<';
9315 $out .= ' /ProcSet [/PDF /Text /ImageB /ImageC /ImageI]';
9316 if (!$this->pdfa_mode) {
9317 // transparency
9318 if (isset($data['extgstates']) AND !empty($data['extgstates'])) {
9319 $out .= ' /ExtGState <<';
9320 foreach ($data['extgstates'] as $k => $extgstate) {
9321 if (isset($this->extgstates[$k]['name'])) {
9322 $out .= ' /'.$this->extgstates[$k]['name'];
9323 } else {
9324 $out .= ' /GS'.$k;
9325 }
9326 $out .= ' '.$this->extgstates[$k]['n'].' 0 R';
9327 }
9328 $out .= ' >>';
9329 }
9330 if (isset($data['gradients']) AND !empty($data['gradients'])) {
9331 $gp = '';
9332 $gs = '';
9333 foreach ($data['gradients'] as $id => $grad) {
9334 // gradient patterns
9335 $gp .= ' /p'.$id.' '.$this->gradients[$id]['pattern'].' 0 R';
9336 // gradient shadings
9337 $gs .= ' /Sh'.$id.' '.$this->gradients[$id]['id'].' 0 R';
9338 }
9339 $out .= ' /Pattern <<'.$gp.' >>';
9340 $out .= ' /Shading <<'.$gs.' >>';
9341 }
9342 }
9343 // spot colors
9344 if (isset($data['spot_colors']) AND !empty($data['spot_colors'])) {
9345 $out .= ' /ColorSpace <<';
9346 foreach ($data['spot_colors'] as $name => $color) {
9347 $out .= ' /CS'.$color['i'].' '.$this->spot_colors[$name]['n'].' 0 R';
9348 }
9349 $out .= ' >>';
9350 }
9351 // fonts
9352 if (!empty($data['fonts'])) {
9353 $out .= ' /Font <<';
9354 foreach ($data['fonts'] as $fontkey => $fontid) {
9355 $out .= ' /F'.$fontid.' '.$this->font_obj_ids[$fontkey].' 0 R';
9356 }
9357 $out .= ' >>';
9358 }
9359 // images or nested xobjects
9360 if (!empty($data['images']) OR !empty($data['xobjects'])) {
9361 $out .= ' /XObject <<';
9362 foreach ($data['images'] as $imgid) {
9363 $out .= ' /I'.$imgid.' '.$this->xobjects['I'.$imgid]['n'].' 0 R';
9364 }
9365 foreach ($data['xobjects'] as $sub_id => $sub_objid) {
9366 $out .= ' /'.$sub_id.' '.$sub_objid['n'].' 0 R';
9367 }
9368 $out .= ' >>';
9369 }
9370 $out .= ' >>'; //end resources
9371 if (isset($data['group']) AND ($data['group'] !== false)) {
9372 // set transparency group
9373 $out .= ' /Group << /Type /Group /S /Transparency';
9374 if (is_array($data['group'])) {
9375 if (isset($data['group']['CS']) AND !empty($data['group']['CS'])) {
9376 $out .= ' /CS /'.$data['group']['CS'];
9377 }
9378 if (isset($data['group']['I'])) {
9379 $out .= ' /I /'.($data['group']['I']===true?'true':'false');
9380 }
9381 if (isset($data['group']['K'])) {
9382 $out .= ' /K /'.($data['group']['K']===true?'true':'false');
9383 }
9384 }
9385 $out .= ' >>';
9386 }
9387 $stream = $this->_getrawstream($stream, $data['n']);
9388 $out .= ' /Length '.strlen($stream);
9389 $out .= ' >>';
9390 $out .= ' stream'."\n".$stream."\n".'endstream';
9391 $out .= "\n".'endobj';
9392 $this->_out($out);
9393 }
9394 }
9395 }
9396
9397 /**
9398 * Output Spot Colors Resources.
9399 * @protected
9400 * @since 4.0.024 (2008-09-12)
9401 */
9402 protected function _putspotcolors() {
9403 foreach ($this->spot_colors as $name => $color) {
9404 $this->_newobj();
9405 $this->spot_colors[$name]['n'] = $this->n;
9406 $out = '[/Separation /'.str_replace(' ', '#20', $name);
9407 $out .= ' /DeviceCMYK <<';
9408 $out .= ' /Range [0 1 0 1 0 1 0 1] /C0 [0 0 0 0]';
9409 $out .= ' '.sprintf('/C1 [%F %F %F %F] ', ($color['C'] / 100), ($color['M'] / 100), ($color['Y'] / 100), ($color['K'] / 100));
9410 $out .= ' /FunctionType 2 /Domain [0 1] /N 1>>]';
9411 $out .= "\n".'endobj';
9412 $this->_out($out);
9413 }
9414 }
9415
9416 /**
9417 * Return XObjects Dictionary.
9418 * @return string XObjects dictionary
9419 * @protected
9420 * @since 5.8.014 (2010-08-23)
9421 */
9422 protected function _getxobjectdict() {
9423 $out = '';
9424 foreach ($this->xobjects as $id => $objid) {
9425 $out .= ' /'.$id.' '.$objid['n'].' 0 R';
9426 }
9427 return $out;
9428 }
9429
9430 /**
9431 * Output Resources Dictionary.
9432 * @protected
9433 */
9434 protected function _putresourcedict() {
9435 $out = $this->_getobj(2)."\n";
9436 $out .= '<< /ProcSet [/PDF /Text /ImageB /ImageC /ImageI]';
9437 $out .= ' /Font <<';
9438 foreach ($this->fontkeys as $fontkey) {
9439 $font = $this->getFontBuffer($fontkey);
9440 $out .= ' /F'.$font['i'].' '.$font['n'].' 0 R';
9441 }
9442 $out .= ' >>';
9443 $out .= ' /XObject <<';
9444 $out .= $this->_getxobjectdict();
9445 $out .= ' >>';
9446 // layers
9447 if (!empty($this->pdflayers)) {
9448 $out .= ' /Properties <<';
9449 foreach ($this->pdflayers as $layer) {
9450 $out .= ' /'.$layer['layer'].' '.$layer['objid'].' 0 R';
9451 }
9452 $out .= ' >>';
9453 }
9454 if (!$this->pdfa_mode) {
9455 // transparency
9456 if (isset($this->extgstates) AND !empty($this->extgstates)) {
9457 $out .= ' /ExtGState <<';
9458 foreach ($this->extgstates as $k => $extgstate) {
9459 if (isset($extgstate['name'])) {
9460 $out .= ' /'.$extgstate['name'];
9461 } else {
9462 $out .= ' /GS'.$k;
9463 }
9464 $out .= ' '.$extgstate['n'].' 0 R';
9465 }
9466 $out .= ' >>';
9467 }
9468 if (isset($this->gradients) AND !empty($this->gradients)) {
9469 $gp = '';
9470 $gs = '';
9471 foreach ($this->gradients as $id => $grad) {
9472 // gradient patterns
9473 $gp .= ' /p'.$id.' '.$grad['pattern'].' 0 R';
9474 // gradient shadings
9475 $gs .= ' /Sh'.$id.' '.$grad['id'].' 0 R';
9476 }
9477 $out .= ' /Pattern <<'.$gp.' >>';
9478 $out .= ' /Shading <<'.$gs.' >>';
9479 }
9480 }
9481 // spot colors
9482 if (isset($this->spot_colors) AND !empty($this->spot_colors)) {
9483 $out .= ' /ColorSpace <<';
9484 foreach ($this->spot_colors as $color) {
9485 $out .= ' /CS'.$color['i'].' '.$color['n'].' 0 R';
9486 }
9487 $out .= ' >>';
9488 }
9489 $out .= ' >>';
9490 $out .= "\n".'endobj';
9491 $this->_out($out);
9492 }
9493
9494 /**
9495 * Output Resources.
9496 * @protected
9497 */
9498 protected function _putresources() {
9499 $this->_putextgstates();
9500 $this->_putocg();
9501 $this->_putfonts();
9502 $this->_putimages();
9503 $this->_putspotcolors();
9504 $this->_putshaders();
9505 $this->_putxobjects();
9506 $this->_putresourcedict();
9507 $this->_putdests();
9508 $this->_putEmbeddedFiles();
9509 $this->_putannotsobjs();
9510 $this->_putjavascript();
9511 $this->_putbookmarks();
9512 $this->_putencryption();
9513 }
9514
9515 /**
9516 * Adds some Metadata information (Document Information Dictionary)
9517 * (see Chapter 14.3.3 Document Information Dictionary of PDF32000_2008.pdf Reference)
9518 * @return int object id
9519 * @protected
9520 */
9521 protected function _putinfo() {
9522 $oid = $this->_newobj();
9523 $out = '<<';
9524 // store current isunicode value
9525 $prev_isunicode = $this->isunicode;
9526 if ($this->docinfounicode) {
9527 $this->isunicode = true;
9528 }
9529 if (!TCPDF_STATIC::empty_string($this->title)) {
9530 // The document's title.
9531 $out .= ' /Title '.$this->_textstring($this->title, $oid);
9532 }
9533 if (!TCPDF_STATIC::empty_string($this->author)) {
9534 // The name of the person who created the document.
9535 $out .= ' /Author '.$this->_textstring($this->author, $oid);
9536 }
9537 if (!TCPDF_STATIC::empty_string($this->subject)) {
9538 // The subject of the document.
9539 $out .= ' /Subject '.$this->_textstring($this->subject, $oid);
9540 }
9541 if (!TCPDF_STATIC::empty_string($this->keywords)) {
9542 // Keywords associated with the document.
9543 $out .= ' /Keywords '.$this->_textstring($this->keywords, $oid);
9544 }
9545 if (!TCPDF_STATIC::empty_string($this->creator)) {
9546 // If the document was converted to PDF from another format, the name of the conforming product that created the original document from which it was converted.
9547 $out .= ' /Creator '.$this->_textstring($this->creator, $oid);
9548 }
9549 // restore previous isunicode value
9550 $this->isunicode = $prev_isunicode;
9551 // default producer
9552 $out .= ' /Producer '.$this->_textstring(TCPDF_STATIC::getTCPDFProducer(), $oid);
9553 // The date and time the document was created, in human-readable form
9554 $out .= ' /CreationDate '.$this->_datestring(0, $this->doc_creation_timestamp);
9555 // The date and time the document was most recently modified, in human-readable form
9556 $out .= ' /ModDate '.$this->_datestring(0, $this->doc_modification_timestamp);
9557 // A name object indicating whether the document has been modified to include trapping information
9558 $out .= ' /Trapped /False';
9559 $out .= ' >>';
9560 $out .= "\n".'endobj';
9561 $this->_out($out);
9562 return $oid;
9563 }
9564
9565 /**
9566 * Set additional XMP data to be added on the default XMP data just before the end of "x:xmpmeta" tag.
9567 * IMPORTANT: This data is added as-is without controls, so you have to validate your data before using this method!
9568 * @param $xmp (string) Custom XMP data.
9569 * @since 5.9.128 (2011-10-06)
9570 * @public
9571 */
9572 public function setExtraXMP($xmp) {
9573 $this->custom_xmp = $xmp;
9574 }
9575
9576 /**
9577 * Put XMP data object and return ID.
9578 * @return (int) The object ID.
9579 * @since 5.9.121 (2011-09-28)
9580 * @protected
9581 */
9582 protected function _putXMP() {
9583 $oid = $this->_newobj();
9584 // store current isunicode value
9585 $prev_isunicode = $this->isunicode;
9586 $this->isunicode = true;
9587 $prev_encrypted = $this->encrypted;
9588 $this->encrypted = false;
9589 // set XMP data
9590 $xmp = '<?xpacket begin="'.TCPDF_FONTS::unichr(0xfeff, $this->isunicode).'" id="W5M0MpCehiHzreSzNTczkc9d"?>'."\n";
9591 $xmp .= '<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 4.2.1-c043 52.372728, 2009/01/18-15:08:04">'."\n";
9592 $xmp .= "\t".'<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">'."\n";
9593 $xmp .= "\t\t".'<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/">'."\n";
9594 $xmp .= "\t\t\t".'<dc:format>application/pdf</dc:format>'."\n";
9595 $xmp .= "\t\t\t".'<dc:title>'."\n";
9596 $xmp .= "\t\t\t\t".'<rdf:Alt>'."\n";
9597 $xmp .= "\t\t\t\t\t".'<rdf:li xml:lang="x-default">'.TCPDF_STATIC::_escapeXML($this->title).'</rdf:li>'."\n";
9598 $xmp .= "\t\t\t\t".'</rdf:Alt>'."\n";
9599 $xmp .= "\t\t\t".'</dc:title>'."\n";
9600 $xmp .= "\t\t\t".'<dc:creator>'."\n";
9601 $xmp .= "\t\t\t\t".'<rdf:Seq>'."\n";
9602 $xmp .= "\t\t\t\t\t".'<rdf:li>'.TCPDF_STATIC::_escapeXML($this->author).'</rdf:li>'."\n";
9603 $xmp .= "\t\t\t\t".'</rdf:Seq>'."\n";
9604 $xmp .= "\t\t\t".'</dc:creator>'."\n";
9605 $xmp .= "\t\t\t".'<dc:description>'."\n";
9606 $xmp .= "\t\t\t\t".'<rdf:Alt>'."\n";
9607 $xmp .= "\t\t\t\t\t".'<rdf:li xml:lang="x-default">'.TCPDF_STATIC::_escapeXML($this->subject).'</rdf:li>'."\n";
9608 $xmp .= "\t\t\t\t".'</rdf:Alt>'."\n";
9609 $xmp .= "\t\t\t".'</dc:description>'."\n";
9610 $xmp .= "\t\t\t".'<dc:subject>'."\n";
9611 $xmp .= "\t\t\t\t".'<rdf:Bag>'."\n";
9612 $xmp .= "\t\t\t\t\t".'<rdf:li>'.TCPDF_STATIC::_escapeXML($this->keywords).'</rdf:li>'."\n";
9613 $xmp .= "\t\t\t\t".'</rdf:Bag>'."\n";
9614 $xmp .= "\t\t\t".'</dc:subject>'."\n";
9615 $xmp .= "\t\t".'</rdf:Description>'."\n";
9616 // convert doc creation date format
9617 $dcdate = TCPDF_STATIC::getFormattedDate($this->doc_creation_timestamp);
9618 $doccreationdate = substr($dcdate, 0, 4).'-'.substr($dcdate, 4, 2).'-'.substr($dcdate, 6, 2);
9619 $doccreationdate .= 'T'.substr($dcdate, 8, 2).':'.substr($dcdate, 10, 2).':'.substr($dcdate, 12, 2);
9620 $doccreationdate .= '+'.substr($dcdate, 15, 2).':'.substr($dcdate, 18, 2);
9621 $doccreationdate = TCPDF_STATIC::_escapeXML($doccreationdate);
9622 // convert doc modification date format
9623 $dmdate = TCPDF_STATIC::getFormattedDate($this->doc_modification_timestamp);
9624 $docmoddate = substr($dmdate, 0, 4).'-'.substr($dmdate, 4, 2).'-'.substr($dmdate, 6, 2);
9625 $docmoddate .= 'T'.substr($dmdate, 8, 2).':'.substr($dmdate, 10, 2).':'.substr($dmdate, 12, 2);
9626 $docmoddate .= '+'.substr($dmdate, 15, 2).':'.substr($dmdate, 18, 2);
9627 $docmoddate = TCPDF_STATIC::_escapeXML($docmoddate);
9628 $xmp .= "\t\t".'<rdf:Description rdf:about="" xmlns:xmp="http://ns.adobe.com/xap/1.0/">'."\n";
9629 $xmp .= "\t\t\t".'<xmp:CreateDate>'.$doccreationdate.'</xmp:CreateDate>'."\n";
9630 $xmp .= "\t\t\t".'<xmp:CreatorTool>'.$this->creator.'</xmp:CreatorTool>'."\n";
9631 $xmp .= "\t\t\t".'<xmp:ModifyDate>'.$docmoddate.'</xmp:ModifyDate>'."\n";
9632 $xmp .= "\t\t\t".'<xmp:MetadataDate>'.$doccreationdate.'</xmp:MetadataDate>'."\n";
9633 $xmp .= "\t\t".'</rdf:Description>'."\n";
9634 $xmp .= "\t\t".'<rdf:Description rdf:about="" xmlns:pdf="http://ns.adobe.com/pdf/1.3/">'."\n";
9635 $xmp .= "\t\t\t".'<pdf:Keywords>'.TCPDF_STATIC::_escapeXML($this->keywords).'</pdf:Keywords>'."\n";
9636 $xmp .= "\t\t\t".'<pdf:Producer>'.TCPDF_STATIC::_escapeXML(TCPDF_STATIC::getTCPDFProducer()).'</pdf:Producer>'."\n";
9637 $xmp .= "\t\t".'</rdf:Description>'."\n";
9638 $xmp .= "\t\t".'<rdf:Description rdf:about="" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/">'."\n";
9639 $uuid = 'uuid:'.substr($this->file_id, 0, 8).'-'.substr($this->file_id, 8, 4).'-'.substr($this->file_id, 12, 4).'-'.substr($this->file_id, 16, 4).'-'.substr($this->file_id, 20, 12);
9640 $xmp .= "\t\t\t".'<xmpMM:DocumentID>'.$uuid.'</xmpMM:DocumentID>'."\n";
9641 $xmp .= "\t\t\t".'<xmpMM:InstanceID>'.$uuid.'</xmpMM:InstanceID>'."\n";
9642 $xmp .= "\t\t".'</rdf:Description>'."\n";
9643 if ($this->pdfa_mode) {
9644 $xmp .= "\t\t".'<rdf:Description rdf:about="" xmlns:pdfaid="http://www.aiim.org/pdfa/ns/id/">'."\n";
9645 $xmp .= "\t\t\t".'<pdfaid:part>1</pdfaid:part>'."\n";
9646 $xmp .= "\t\t\t".'<pdfaid:conformance>B</pdfaid:conformance>'."\n";
9647 $xmp .= "\t\t".'</rdf:Description>'."\n";
9648 }
9649 // XMP extension schemas
9650 $xmp .= "\t\t".'<rdf:Description rdf:about="" xmlns:pdfaExtension="http://www.aiim.org/pdfa/ns/extension/" xmlns:pdfaSchema="http://www.aiim.org/pdfa/ns/schema#" xmlns:pdfaProperty="http://www.aiim.org/pdfa/ns/property#">'."\n";
9651 $xmp .= "\t\t\t".'<pdfaExtension:schemas>'."\n";
9652 $xmp .= "\t\t\t\t".'<rdf:Bag>'."\n";
9653 $xmp .= "\t\t\t\t\t".'<rdf:li rdf:parseType="Resource">'."\n";
9654 $xmp .= "\t\t\t\t\t\t".'<pdfaSchema:namespaceURI>http://ns.adobe.com/pdf/1.3/</pdfaSchema:namespaceURI>'."\n";
9655 $xmp .= "\t\t\t\t\t\t".'<pdfaSchema:prefix>pdf</pdfaSchema:prefix>'."\n";
9656 $xmp .= "\t\t\t\t\t\t".'<pdfaSchema:schema>Adobe PDF Schema</pdfaSchema:schema>'."\n";
9657 $xmp .= "\t\t\t\t\t".'</rdf:li>'."\n";
9658 $xmp .= "\t\t\t\t\t".'<rdf:li rdf:parseType="Resource">'."\n";
9659 $xmp .= "\t\t\t\t\t\t".'<pdfaSchema:namespaceURI>http://ns.adobe.com/xap/1.0/mm/</pdfaSchema:namespaceURI>'."\n";
9660 $xmp .= "\t\t\t\t\t\t".'<pdfaSchema:prefix>xmpMM</pdfaSchema:prefix>'."\n";
9661 $xmp .= "\t\t\t\t\t\t".'<pdfaSchema:schema>XMP Media Management Schema</pdfaSchema:schema>'."\n";
9662 $xmp .= "\t\t\t\t\t\t".'<pdfaSchema:property>'."\n";
9663 $xmp .= "\t\t\t\t\t\t\t".'<rdf:Seq>'."\n";
9664 $xmp .= "\t\t\t\t\t\t\t\t".'<rdf:li rdf:parseType="Resource">'."\n";
9665 $xmp .= "\t\t\t\t\t\t\t\t\t".'<pdfaProperty:category>internal</pdfaProperty:category>'."\n";
9666 $xmp .= "\t\t\t\t\t\t\t\t\t".'<pdfaProperty:description>UUID based identifier for specific incarnation of a document</pdfaProperty:description>'."\n";
9667 $xmp .= "\t\t\t\t\t\t\t\t\t".'<pdfaProperty:name>InstanceID</pdfaProperty:name>'."\n";
9668 $xmp .= "\t\t\t\t\t\t\t\t\t".'<pdfaProperty:valueType>URI</pdfaProperty:valueType>'."\n";
9669 $xmp .= "\t\t\t\t\t\t\t\t".'</rdf:li>'."\n";
9670 $xmp .= "\t\t\t\t\t\t\t".'</rdf:Seq>'."\n";
9671 $xmp .= "\t\t\t\t\t\t".'</pdfaSchema:property>'."\n";
9672 $xmp .= "\t\t\t\t\t".'</rdf:li>'."\n";
9673 $xmp .= "\t\t\t\t\t".'<rdf:li rdf:parseType="Resource">'."\n";
9674 $xmp .= "\t\t\t\t\t\t".'<pdfaSchema:namespaceURI>http://www.aiim.org/pdfa/ns/id/</pdfaSchema:namespaceURI>'."\n";
9675 $xmp .= "\t\t\t\t\t\t".'<pdfaSchema:prefix>pdfaid</pdfaSchema:prefix>'."\n";
9676 $xmp .= "\t\t\t\t\t\t".'<pdfaSchema:schema>PDF/A ID Schema</pdfaSchema:schema>'."\n";
9677 $xmp .= "\t\t\t\t\t\t".'<pdfaSchema:property>'."\n";
9678 $xmp .= "\t\t\t\t\t\t\t".'<rdf:Seq>'."\n";
9679 $xmp .= "\t\t\t\t\t\t\t\t".'<rdf:li rdf:parseType="Resource">'."\n";
9680 $xmp .= "\t\t\t\t\t\t\t\t\t".'<pdfaProperty:category>internal</pdfaProperty:category>'."\n";
9681 $xmp .= "\t\t\t\t\t\t\t\t\t".'<pdfaProperty:description>Part of PDF/A standard</pdfaProperty:description>'."\n";
9682 $xmp .= "\t\t\t\t\t\t\t\t\t".'<pdfaProperty:name>part</pdfaProperty:name>'."\n";
9683 $xmp .= "\t\t\t\t\t\t\t\t\t".'<pdfaProperty:valueType>Integer</pdfaProperty:valueType>'."\n";
9684 $xmp .= "\t\t\t\t\t\t\t\t".'</rdf:li>'."\n";
9685 $xmp .= "\t\t\t\t\t\t\t\t".'<rdf:li rdf:parseType="Resource">'."\n";
9686 $xmp .= "\t\t\t\t\t\t\t\t\t".'<pdfaProperty:category>internal</pdfaProperty:category>'."\n";
9687 $xmp .= "\t\t\t\t\t\t\t\t\t".'<pdfaProperty:description>Amendment of PDF/A standard</pdfaProperty:description>'."\n";
9688 $xmp .= "\t\t\t\t\t\t\t\t\t".'<pdfaProperty:name>amd</pdfaProperty:name>'."\n";
9689 $xmp .= "\t\t\t\t\t\t\t\t\t".'<pdfaProperty:valueType>Text</pdfaProperty:valueType>'."\n";
9690 $xmp .= "\t\t\t\t\t\t\t\t".'</rdf:li>'."\n";
9691 $xmp .= "\t\t\t\t\t\t\t\t".'<rdf:li rdf:parseType="Resource">'."\n";
9692 $xmp .= "\t\t\t\t\t\t\t\t\t".'<pdfaProperty:category>internal</pdfaProperty:category>'."\n";
9693 $xmp .= "\t\t\t\t\t\t\t\t\t".'<pdfaProperty:description>Conformance level of PDF/A standard</pdfaProperty:description>'."\n";
9694 $xmp .= "\t\t\t\t\t\t\t\t\t".'<pdfaProperty:name>conformance</pdfaProperty:name>'."\n";
9695 $xmp .= "\t\t\t\t\t\t\t\t\t".'<pdfaProperty:valueType>Text</pdfaProperty:valueType>'."\n";
9696 $xmp .= "\t\t\t\t\t\t\t\t".'</rdf:li>'."\n";
9697 $xmp .= "\t\t\t\t\t\t\t".'</rdf:Seq>'."\n";
9698 $xmp .= "\t\t\t\t\t\t".'</pdfaSchema:property>'."\n";
9699 $xmp .= "\t\t\t\t\t".'</rdf:li>'."\n";
9700 $xmp .= "\t\t\t\t".'</rdf:Bag>'."\n";
9701 $xmp .= "\t\t\t".'</pdfaExtension:schemas>'."\n";
9702 $xmp .= "\t\t".'</rdf:Description>'."\n";
9703 $xmp .= "\t".'</rdf:RDF>'."\n";
9704 $xmp .= $this->custom_xmp;
9705 $xmp .= '</x:xmpmeta>'."\n";
9706 $xmp .= '<?xpacket end="w"?>';
9707 $out = '<< /Type /Metadata /Subtype /XML /Length '.strlen($xmp).' >> stream'."\n".$xmp."\n".'endstream'."\n".'endobj';
9708 // restore previous isunicode value
9709 $this->isunicode = $prev_isunicode;
9710 $this->encrypted = $prev_encrypted;
9711 $this->_out($out);
9712 return $oid;
9713 }
9714
9715 /**
9716 * Output Catalog.
9717 * @return int object id
9718 * @protected
9719 */
9720 protected function _putcatalog() {
9721 // put XMP
9722 $xmpobj = $this->_putXMP();
9723 // if required, add standard sRGB_IEC61966-2.1 blackscaled ICC colour profile
9724 if ($this->pdfa_mode OR $this->force_srgb) {
9725 $iccobj = $this->_newobj();
9726 $icc = file_get_contents(dirname(__FILE__).'/include/sRGB.icc');
9727 $filter = '';
9728 if ($this->compress) {
9729 $filter = ' /Filter /FlateDecode';
9730 $icc = gzcompress($icc);
9731 }
9732 $icc = $this->_getrawstream($icc);
9733 $this->_out('<</N 3 '.$filter.'/Length '.strlen($icc).'>> stream'."\n".$icc."\n".'endstream'."\n".'endobj');
9734 }
9735 // start catalog
9736 $oid = $this->_newobj();
9737 $out = '<< /Type /Catalog';
9738 $out .= ' /Version /'.$this->PDFVersion;
9739 //$out .= ' /Extensions <<>>';
9740 $out .= ' /Pages 1 0 R';
9741 //$out .= ' /PageLabels ' //...;
9742 $out .= ' /Names <<';
9743 if ((!$this->pdfa_mode) AND !empty($this->n_js)) {
9744 $out .= ' /JavaScript '.$this->n_js;
9745 }
9746 if (!empty($this->efnames)) {
9747 $out .= ' /EmbeddedFiles <</Names [';
9748 foreach ($this->efnames AS $fn => $fref) {
9749 $out .= ' '.$this->_datastring($fn).' '.$fref;
9750 }
9751 $out .= ' ]>>';
9752 }
9753 $out .= ' >>';
9754 if (!empty($this->dests)) {
9755 $out .= ' /Dests '.($this->n_dests).' 0 R';
9756 }
9757 $out .= $this->_putviewerpreferences();
9758 if (isset($this->LayoutMode) AND (!TCPDF_STATIC::empty_string($this->LayoutMode))) {
9759 $out .= ' /PageLayout /'.$this->LayoutMode;
9760 }
9761 if (isset($this->PageMode) AND (!TCPDF_STATIC::empty_string($this->PageMode))) {
9762 $out .= ' /PageMode /'.$this->PageMode;
9763 }
9764 if (count($this->outlines) > 0) {
9765 $out .= ' /Outlines '.$this->OutlineRoot.' 0 R';
9766 $out .= ' /PageMode /UseOutlines';
9767 }
9768 //$out .= ' /Threads []';
9769 if ($this->ZoomMode == 'fullpage') {
9770 $out .= ' /OpenAction ['.$this->page_obj_id[1].' 0 R /Fit]';
9771 } elseif ($this->ZoomMode == 'fullwidth') {
9772 $out .= ' /OpenAction ['.$this->page_obj_id[1].' 0 R /FitH null]';
9773 } elseif ($this->ZoomMode == 'real') {
9774 $out .= ' /OpenAction ['.$this->page_obj_id[1].' 0 R /XYZ null null 1]';
9775 } elseif (!is_string($this->ZoomMode)) {
9776 $out .= sprintf(' /OpenAction ['.$this->page_obj_id[1].' 0 R /XYZ null null %F]', ($this->ZoomMode / 100));
9777 }
9778 //$out .= ' /AA <<>>';
9779 //$out .= ' /URI <<>>';
9780 $out .= ' /Metadata '.$xmpobj.' 0 R';
9781 //$out .= ' /StructTreeRoot <<>>';
9782 //$out .= ' /MarkInfo <<>>';
9783 if (isset($this->l['a_meta_language'])) {
9784 $out .= ' /Lang '.$this->_textstring($this->l['a_meta_language'], $oid);
9785 }
9786 //$out .= ' /SpiderInfo <<>>';
9787 // set OutputIntent to sRGB IEC61966-2.1 if required
9788 if ($this->pdfa_mode OR $this->force_srgb) {
9789 $out .= ' /OutputIntents [<<';
9790 $out .= ' /Type /OutputIntent';
9791 $out .= ' /S /GTS_PDFA1';
9792 $out .= ' /OutputCondition '.$this->_textstring('sRGB IEC61966-2.1', $oid);
9793 $out .= ' /OutputConditionIdentifier '.$this->_textstring('sRGB IEC61966-2.1', $oid);
9794 $out .= ' /RegistryName '.$this->_textstring('http://www.color.org', $oid);
9795 $out .= ' /Info '.$this->_textstring('sRGB IEC61966-2.1', $oid);
9796 $out .= ' /DestOutputProfile '.$iccobj.' 0 R';
9797 $out .= ' >>]';
9798 }
9799 //$out .= ' /PieceInfo <<>>';
9800 if (!empty($this->pdflayers)) {
9801 $lyrobjs = '';
9802 $lyrobjs_off = '';
9803 $lyrobjs_lock = '';
9804 foreach ($this->pdflayers as $layer) {
9805 $layer_obj_ref = ' '.$layer['objid'].' 0 R';
9806 $lyrobjs .= $layer_obj_ref;
9807 if ($layer['view'] === false) {
9808 $lyrobjs_off .= $layer_obj_ref;
9809 }
9810 if ($layer['lock']) {
9811 $lyrobjs_lock .= $layer_obj_ref;
9812 }
9813 }
9814 $out .= ' /OCProperties << /OCGs ['.$lyrobjs.']';
9815 $out .= ' /D <<';
9816 $out .= ' /Name '.$this->_textstring('Layers', $oid);
9817 $out .= ' /Creator '.$this->_textstring('TCPDF', $oid);
9818 $out .= ' /BaseState /ON';
9819 $out .= ' /OFF ['.$lyrobjs_off.']';
9820 $out .= ' /Locked ['.$lyrobjs_lock.']';
9821 $out .= ' /Intent /View';
9822 $out .= ' /AS [';
9823 $out .= ' << /Event /Print /OCGs ['.$lyrobjs.'] /Category [/Print] >>';
9824 $out .= ' << /Event /View /OCGs ['.$lyrobjs.'] /Category [/View] >>';
9825 $out .= ' ]';
9826 $out .= ' /Order ['.$lyrobjs.']';
9827 $out .= ' /ListMode /AllPages';
9828 //$out .= ' /RBGroups ['..']';
9829 //$out .= ' /Locked ['..']';
9830 $out .= ' >>';
9831 $out .= ' >>';
9832 }
9833 // AcroForm
9834 if (!empty($this->form_obj_id)
9835 OR ($this->sign AND isset($this->signature_data['cert_type']))
9836 OR !empty($this->empty_signature_appearance)) {
9837 $out .= ' /AcroForm <<';
9838 $objrefs = '';
9839 if ($this->sign AND isset($this->signature_data['cert_type'])) {
9840 // set reference for signature object
9841 $objrefs .= $this->sig_obj_id.' 0 R';
9842 }
9843 if (!empty($this->empty_signature_appearance)) {
9844 foreach ($this->empty_signature_appearance as $esa) {
9845 // set reference for empty signature objects
9846 $objrefs .= ' '.$esa['objid'].' 0 R';
9847 }
9848 }
9849 if (!empty($this->form_obj_id)) {
9850 foreach($this->form_obj_id as $objid) {
9851 $objrefs .= ' '.$objid.' 0 R';
9852 }
9853 }
9854 $out .= ' /Fields ['.$objrefs.']';
9855 // It's better to turn off this value and set the appearance stream for each annotation (/AP) to avoid conflicts with signature fields.
9856 if (empty($this->signature_data['approval']) OR ($this->signature_data['approval'] != 'A')) {
9857 $out .= ' /NeedAppearances false';
9858 }
9859 if ($this->sign AND isset($this->signature_data['cert_type'])) {
9860 if ($this->signature_data['cert_type'] > 0) {
9861 $out .= ' /SigFlags 3';
9862 } else {
9863 $out .= ' /SigFlags 1';
9864 }
9865 }
9866 //$out .= ' /CO ';
9867 if (isset($this->annotation_fonts) AND !empty($this->annotation_fonts)) {
9868 $out .= ' /DR <<';
9869 $out .= ' /Font <<';
9870 foreach ($this->annotation_fonts as $fontkey => $fontid) {
9871 $out .= ' /F'.$fontid.' '.$this->font_obj_ids[$fontkey].' 0 R';
9872 }
9873 $out .= ' >> >>';
9874 }
9875 $font = $this->getFontBuffer('helvetica');
9876 $out .= ' /DA (/F'.$font['i'].' 0 Tf 0 g)';
9877 $out .= ' /Q '.(($this->rtl)?'2':'0');
9878 //$out .= ' /XFA ';
9879 $out .= ' >>';
9880 // signatures
9881 if ($this->sign AND isset($this->signature_data['cert_type'])
9882 AND (empty($this->signature_data['approval']) OR ($this->signature_data['approval'] != 'A'))) {
9883 if ($this->signature_data['cert_type'] > 0) {
9884 $out .= ' /Perms << /DocMDP '.($this->sig_obj_id + 1).' 0 R >>';
9885 } else {
9886 $out .= ' /Perms << /UR3 '.($this->sig_obj_id + 1).' 0 R >>';
9887 }
9888 }
9889 }
9890 //$out .= ' /Legal <<>>';
9891 //$out .= ' /Requirements []';
9892 //$out .= ' /Collection <<>>';
9893 //$out .= ' /NeedsRendering true';
9894 $out .= ' >>';
9895 $out .= "\n".'endobj';
9896 $this->_out($out);
9897 return $oid;
9898 }
9899
9900 /**
9901 * Output viewer preferences.
9902 * @return string for viewer preferences
9903 * @author Nicola asuni
9904 * @since 3.1.000 (2008-06-09)
9905 * @protected
9906 */
9907 protected function _putviewerpreferences() {
9908 $vp = $this->viewer_preferences;
9909 $out = ' /ViewerPreferences <<';
9910 if ($this->rtl) {
9911 $out .= ' /Direction /R2L';
9912 } else {
9913 $out .= ' /Direction /L2R';
9914 }
9915 if (isset($vp['HideToolbar']) AND ($vp['HideToolbar'])) {
9916 $out .= ' /HideToolbar true';
9917 }
9918 if (isset($vp['HideMenubar']) AND ($vp['HideMenubar'])) {
9919 $out .= ' /HideMenubar true';
9920 }
9921 if (isset($vp['HideWindowUI']) AND ($vp['HideWindowUI'])) {
9922 $out .= ' /HideWindowUI true';
9923 }
9924 if (isset($vp['FitWindow']) AND ($vp['FitWindow'])) {
9925 $out .= ' /FitWindow true';
9926 }
9927 if (isset($vp['CenterWindow']) AND ($vp['CenterWindow'])) {
9928 $out .= ' /CenterWindow true';
9929 }
9930 if (isset($vp['DisplayDocTitle']) AND ($vp['DisplayDocTitle'])) {
9931 $out .= ' /DisplayDocTitle true';
9932 }
9933 if (isset($vp['NonFullScreenPageMode'])) {
9934 $out .= ' /NonFullScreenPageMode /'.$vp['NonFullScreenPageMode'];
9935 }
9936 if (isset($vp['ViewArea'])) {
9937 $out .= ' /ViewArea /'.$vp['ViewArea'];
9938 }
9939 if (isset($vp['ViewClip'])) {
9940 $out .= ' /ViewClip /'.$vp['ViewClip'];
9941 }
9942 if (isset($vp['PrintArea'])) {
9943 $out .= ' /PrintArea /'.$vp['PrintArea'];
9944 }
9945 if (isset($vp['PrintClip'])) {
9946 $out .= ' /PrintClip /'.$vp['PrintClip'];
9947 }
9948 if (isset($vp['PrintScaling'])) {
9949 $out .= ' /PrintScaling /'.$vp['PrintScaling'];
9950 }
9951 if (isset($vp['Duplex']) AND (!TCPDF_STATIC::empty_string($vp['Duplex']))) {
9952 $out .= ' /Duplex /'.$vp['Duplex'];
9953 }
9954 if (isset($vp['PickTrayByPDFSize'])) {
9955 if ($vp['PickTrayByPDFSize']) {
9956 $out .= ' /PickTrayByPDFSize true';
9957 } else {
9958 $out .= ' /PickTrayByPDFSize false';
9959 }
9960 }
9961 if (isset($vp['PrintPageRange'])) {
9962 $PrintPageRangeNum = '';
9963 foreach ($vp['PrintPageRange'] as $k => $v) {
9964 $PrintPageRangeNum .= ' '.($v - 1).'';
9965 }
9966 $out .= ' /PrintPageRange ['.substr($PrintPageRangeNum,1).']';
9967 }
9968 if (isset($vp['NumCopies'])) {
9969 $out .= ' /NumCopies '.intval($vp['NumCopies']);
9970 }
9971 $out .= ' >>';
9972 return $out;
9973 }
9974
9975 /**
9976 * Output PDF File Header (7.5.2).
9977 * @protected
9978 */
9979 protected function _putheader() {
9980 $this->_out('%PDF-'.$this->PDFVersion);
9981 $this->_out('%'.chr(0xe2).chr(0xe3).chr(0xcf).chr(0xd3));
9982 }
9983
9984 /**
9985 * Output end of document (EOF).
9986 * @protected
9987 */
9988 protected function _enddoc() {
9989 if (isset($this->CurrentFont['fontkey']) AND isset($this->CurrentFont['subsetchars'])) {
9990 // save subset chars of the previous font
9991 $this->setFontSubBuffer($this->CurrentFont['fontkey'], 'subsetchars', $this->CurrentFont['subsetchars']);
9992 }
9993 $this->state = 1;
9994 $this->_putheader();
9995 $this->_putpages();
9996 $this->_putresources();
9997 // empty signature fields
9998 if (!empty($this->empty_signature_appearance)) {
9999 foreach ($this->empty_signature_appearance as $key => $esa) {
10000 // widget annotation for empty signature
10001 $out = $this->_getobj($esa['objid'])."\n";
10002 $out .= '<< /Type /Annot';
10003 $out .= ' /Subtype /Widget';
10004 $out .= ' /Rect ['.$esa['rect'].']';
10005 $out .= ' /P '.$this->page_obj_id[($esa['page'])].' 0 R'; // link to signature appearance page
10006 $out .= ' /F 4';
10007 $out .= ' /FT /Sig';
10008 $signame = $esa['name'].sprintf(' [%03d]', ($key + 1));
10009 $out .= ' /T '.$this->_textstring($signame, $esa['objid']);
10010 $out .= ' /Ff 0';
10011 $out .= ' >>';
10012 $out .= "\n".'endobj';
10013 $this->_out($out);
10014 }
10015 }
10016 // Signature
10017 if ($this->sign AND isset($this->signature_data['cert_type'])) {
10018 // widget annotation for signature
10019 $out = $this->_getobj($this->sig_obj_id)."\n";
10020 $out .= '<< /Type /Annot';
10021 $out .= ' /Subtype /Widget';
10022 $out .= ' /Rect ['.$this->signature_appearance['rect'].']';
10023 $out .= ' /P '.$this->page_obj_id[($this->signature_appearance['page'])].' 0 R'; // link to signature appearance page
10024 $out .= ' /F 4';
10025 $out .= ' /FT /Sig';
10026 $out .= ' /T '.$this->_textstring($this->signature_appearance['name'], $this->sig_obj_id);
10027 $out .= ' /Ff 0';
10028 $out .= ' /V '.($this->sig_obj_id + 1).' 0 R';
10029 $out .= ' >>';
10030 $out .= "\n".'endobj';
10031 $this->_out($out);
10032 // signature
10033 $this->_putsignature();
10034 }
10035 // Info
10036 $objid_info = $this->_putinfo();
10037 // Catalog
10038 $objid_catalog = $this->_putcatalog();
10039 // Cross-ref
10040 $o = $this->bufferlen;
10041 // XREF section
10042 $this->_out('xref');
10043 $this->_out('0 '.($this->n + 1));
10044 $this->_out('0000000000 65535 f ');
10045 $freegen = ($this->n + 2);
10046 for ($i=1; $i <= $this->n; ++$i) {
10047 if (!isset($this->offsets[$i]) AND ($i > 1)) {
10048 $this->_out(sprintf('0000000000 %05d f ', $freegen));
10049 ++$freegen;
10050 } else {
10051 $this->_out(sprintf('%010d 00000 n ', $this->offsets[$i]));
10052 }
10053 }
10054 // TRAILER
10055 $out = 'trailer'."\n";
10056 $out .= '<<';
10057 $out .= ' /Size '.($this->n + 1);
10058 $out .= ' /Root '.$objid_catalog.' 0 R';
10059 $out .= ' /Info '.$objid_info.' 0 R';
10060 if ($this->encrypted) {
10061 $out .= ' /Encrypt '.$this->encryptdata['objid'].' 0 R';
10062 }
10063 $out .= ' /ID [ <'.$this->file_id.'> <'.$this->file_id.'> ]';
10064 $out .= ' >>';
10065 $this->_out($out);
10066 $this->_out('startxref');
10067 $this->_out($o);
10068 $this->_out('%%EOF');
10069 $this->state = 3; // end-of-doc
10070 if ($this->diskcache) {
10071 // remove temporary files used for images
10072 foreach ($this->imagekeys as $key) {
10073 // remove temporary files
10074 unlink($this->images[$key]);
10075 }
10076 foreach ($this->fontkeys as $key) {
10077 // remove temporary files
10078 unlink($this->fonts[$key]);
10079 }
10080 }
10081 }
10082
10083 /**
10084 * Initialize a new page.
10085 * @param $orientation (string) page orientation. Possible values are (case insensitive):<ul><li>P or PORTRAIT (default)</li><li>L or LANDSCAPE</li></ul>
10086 * @param $format (mixed) The format used for pages. It can be either: one of the string values specified at getPageSizeFromFormat() or an array of parameters specified at setPageFormat().
10087 * @protected
10088 * @see getPageSizeFromFormat(), setPageFormat()
10089 */
10090 protected function _beginpage($orientation='', $format='') {
10091 ++$this->page;
10092 $this->pageobjects[$this->page] = array();
10093 $this->setPageBuffer($this->page, '');
10094 // initialize array for graphics tranformation positions inside a page buffer
10095 $this->transfmrk[$this->page] = array();
10096 $this->state = 2;
10097 if (TCPDF_STATIC::empty_string($orientation)) {
10098 if (isset($this->CurOrientation)) {
10099 $orientation = $this->CurOrientation;
10100 } elseif ($this->fwPt > $this->fhPt) {
10101 // landscape
10102 $orientation = 'L';
10103 } else {
10104 // portrait
10105 $orientation = 'P';
10106 }
10107 }
10108 if (TCPDF_STATIC::empty_string($format)) {
10109 $this->pagedim[$this->page] = $this->pagedim[($this->page - 1)];
10110 $this->setPageOrientation($orientation);
10111 } else {
10112 $this->setPageFormat($format, $orientation);
10113 }
10114 if ($this->rtl) {
10115 $this->x = $this->w - $this->rMargin;
10116 } else {
10117 $this->x = $this->lMargin;
10118 }
10119 $this->y = $this->tMargin;
10120 if (isset($this->newpagegroup[$this->page])) {
10121 // start a new group
10122 $this->currpagegroup = $this->newpagegroup[$this->page];
10123 $this->pagegroups[$this->currpagegroup] = 1;
10124 } elseif (isset($this->currpagegroup) AND ($this->currpagegroup > 0)) {
10125 ++$this->pagegroups[$this->currpagegroup];
10126 }
10127 }
10128
10129 /**
10130 * Mark end of page.
10131 * @protected
10132 */
10133 protected function _endpage() {
10134 $this->setVisibility('all');
10135 $this->state = 1;
10136 }
10137
10138 /**
10139 * Begin a new object and return the object number.
10140 * @return int object number
10141 * @protected
10142 */
10143 protected function _newobj() {
10144 $this->_out($this->_getobj());
10145 return $this->n;
10146 }
10147
10148 /**
10149 * Return the starting object string for the selected object ID.
10150 * @param $objid (int) Object ID (leave empty to get a new ID).
10151 * @return string the starting object string
10152 * @protected
10153 * @since 5.8.009 (2010-08-20)
10154 */
10155 protected function _getobj($objid='') {
10156 if ($objid === '') {
10157 ++$this->n;
10158 $objid = $this->n;
10159 }
10160 $this->offsets[$objid] = $this->bufferlen;
10161 $this->pageobjects[$this->page][] = $objid;
10162 return $objid.' 0 obj';
10163 }
10164
10165 /**
10166 * Underline text.
10167 * @param $x (int) X coordinate
10168 * @param $y (int) Y coordinate
10169 * @param $txt (string) text to underline
10170 * @protected
10171 */
10172 protected function _dounderline($x, $y, $txt) {
10173 $w = $this->GetStringWidth($txt);
10174 return $this->_dounderlinew($x, $y, $w);
10175 }
10176
10177 /**
10178 * Underline for rectangular text area.
10179 * @param $x (int) X coordinate
10180 * @param $y (int) Y coordinate
10181 * @param $w (int) width to underline
10182 * @protected
10183 * @since 4.8.008 (2009-09-29)
10184 */
10185 protected function _dounderlinew($x, $y, $w) {
10186 $linew = - $this->CurrentFont['ut'] / 1000 * $this->FontSizePt;
10187 return sprintf('%F %F %F %F re f', $x * $this->k, ((($this->h - $y) * $this->k) + $linew), $w * $this->k, $linew);
10188 }
10189
10190 /**
10191 * Line through text.
10192 * @param $x (int) X coordinate
10193 * @param $y (int) Y coordinate
10194 * @param $txt (string) text to linethrough
10195 * @protected
10196 */
10197 protected function _dolinethrough($x, $y, $txt) {
10198 $w = $this->GetStringWidth($txt);
10199 return $this->_dolinethroughw($x, $y, $w);
10200 }
10201
10202 /**
10203 * Line through for rectangular text area.
10204 * @param $x (int) X coordinate
10205 * @param $y (int) Y coordinate
10206 * @param $w (int) line length (width)
10207 * @protected
10208 * @since 4.9.008 (2009-09-29)
10209 */
10210 protected function _dolinethroughw($x, $y, $w) {
10211 $linew = - $this->CurrentFont['ut'] / 1000 * $this->FontSizePt;
10212 return sprintf('%F %F %F %F re f', $x * $this->k, ((($this->h - $y) * $this->k) + $linew + ($this->FontSizePt / 3)), $w * $this->k, $linew);
10213 }
10214
10215 /**
10216 * Overline text.
10217 * @param $x (int) X coordinate
10218 * @param $y (int) Y coordinate
10219 * @param $txt (string) text to overline
10220 * @protected
10221 * @since 4.9.015 (2010-04-19)
10222 */
10223 protected function _dooverline($x, $y, $txt) {
10224 $w = $this->GetStringWidth($txt);
10225 return $this->_dooverlinew($x, $y, $w);
10226 }
10227
10228 /**
10229 * Overline for rectangular text area.
10230 * @param $x (int) X coordinate
10231 * @param $y (int) Y coordinate
10232 * @param $w (int) width to overline
10233 * @protected
10234 * @since 4.9.015 (2010-04-19)
10235 */
10236 protected function _dooverlinew($x, $y, $w) {
10237 $linew = - $this->CurrentFont['ut'] / 1000 * $this->FontSizePt;
10238 return sprintf('%F %F %F %F re f', $x * $this->k, (($this->h - $y + $this->FontAscent) * $this->k) - $linew, $w * $this->k, $linew);
10239
10240 }
10241
10242 /**
10243 * Format a data string for meta information
10244 * @param $s (string) data string to escape.
10245 * @param $n (int) object ID
10246 * @return string escaped string.
10247 * @protected
10248 */
10249 protected function _datastring($s, $n=0) {
10250 if ($n == 0) {
10251 $n = $this->n;
10252 }
10253 $s = $this->_encrypt_data($n, $s);
10254 return '('. TCPDF_STATIC::_escape($s).')';
10255 }
10256
10257 /**
10258 * Set the document creation timestamp
10259 * @param $time (mixed) Document creation timestamp in seconds or date-time string.
10260 * @public
10261 * @since 5.9.152 (2012-03-23)
10262 */
10263 public function setDocCreationTimestamp($time) {
10264 if (is_string($time)) {
10265 $time = TCPDF_STATIC::getTimestamp($time);
10266 }
10267 $this->doc_creation_timestamp = intval($time);
10268 }
10269
10270 /**
10271 * Set the document modification timestamp
10272 * @param $time (mixed) Document modification timestamp in seconds or date-time string.
10273 * @public
10274 * @since 5.9.152 (2012-03-23)
10275 */
10276 public function setDocModificationTimestamp($time) {
10277 if (is_string($time)) {
10278 $time = TCPDF_STATIC::getTimestamp($time);
10279 }
10280 $this->doc_modification_timestamp = intval($time);
10281 }
10282
10283 /**
10284 * Returns document creation timestamp in seconds.
10285 * @return (int) Creation timestamp in seconds.
10286 * @public
10287 * @since 5.9.152 (2012-03-23)
10288 */
10289 public function getDocCreationTimestamp() {
10290 return $this->doc_creation_timestamp;
10291 }
10292
10293 /**
10294 * Returns document modification timestamp in seconds.
10295 * @return (int) Modfication timestamp in seconds.
10296 * @public
10297 * @since 5.9.152 (2012-03-23)
10298 */
10299 public function getDocModificationTimestamp() {
10300 return $this->doc_modification_timestamp;
10301 }
10302
10303 /**
10304 * Returns a formatted date for meta information
10305 * @param $n (int) Object ID.
10306 * @param $timestamp (int) Timestamp to convert.
10307 * @return string escaped date string.
10308 * @protected
10309 * @since 4.6.028 (2009-08-25)
10310 */
10311 protected function _datestring($n=0, $timestamp=0) {
10312 if ((empty($timestamp)) OR ($timestamp < 0)) {
10313 $timestamp = $this->doc_creation_timestamp;
10314 }
10315 return $this->_datastring('D:'.TCPDF_STATIC::getFormattedDate($timestamp), $n);
10316 }
10317
10318 /**
10319 * Format a text string for meta information
10320 * @param $s (string) string to escape.
10321 * @param $n (int) object ID
10322 * @return string escaped string.
10323 * @protected
10324 */
10325 protected function _textstring($s, $n=0) {
10326 if ($this->isunicode) {
10327 //Convert string to UTF-16BE
10328 $s = TCPDF_FONTS::UTF8ToUTF16BE($s, true, $this->isunicode, $this->CurrentFont);
10329 }
10330 return $this->_datastring($s, $n);
10331 }
10332
10333 /**
10334 * THIS METHOD IS DEPRECATED
10335 * Format a text string
10336 * @param $s (string) string to escape.
10337 * @return string escaped string.
10338 * @protected
10339 * @deprecated
10340 */
10341 protected function _escapetext($s) {
10342 if ($this->isunicode) {
10343 if (($this->CurrentFont['type'] == 'core') OR ($this->CurrentFont['type'] == 'TrueType') OR ($this->CurrentFont['type'] == 'Type1')) {
10344 $s = TCPDF_FONTS::UTF8ToLatin1($s, $this->isunicode, $this->CurrentFont);
10345 } else {
10346 //Convert string to UTF-16BE and reverse RTL language
10347 $s = TCPDF_FONTS::utf8StrRev($s, false, $this->tmprtl, $this->isunicode, $this->CurrentFont);
10348 }
10349 }
10350 return TCPDF_STATIC::_escape($s);
10351 }
10352
10353 /**
10354 * get raw output stream.
10355 * @param $s (string) string to output.
10356 * @param $n (int) object reference for encryption mode
10357 * @protected
10358 * @author Nicola Asuni
10359 * @since 5.5.000 (2010-06-22)
10360 */
10361 protected function _getrawstream($s, $n=0) {
10362 if ($n <= 0) {
10363 // default to current object
10364 $n = $this->n;
10365 }
10366 return $this->_encrypt_data($n, $s);
10367 }
10368
10369 /**
10370 * Format output stream (DEPRECATED).
10371 * @param $s (string) string to output.
10372 * @param $n (int) object reference for encryption mode
10373 * @protected
10374 * @deprecated
10375 */
10376 protected function _getstream($s, $n=0) {
10377 return 'stream'."\n".$this->_getrawstream($s, $n)."\n".'endstream';
10378 }
10379
10380 /**
10381 * Output a stream (DEPRECATED).
10382 * @param $s (string) string to output.
10383 * @param $n (int) object reference for encryption mode
10384 * @protected
10385 * @deprecated
10386 */
10387 protected function _putstream($s, $n=0) {
10388 $this->_out($this->_getstream($s, $n));
10389 }
10390
10391 /**
10392 * Output a string to the document.
10393 * @param $s (string) string to output.
10394 * @protected
10395 */
10396 protected function _out($s) {
10397 if ($this->state == 2) {
10398 if ($this->inxobj) {
10399 // we are inside an XObject template
10400 $this->xobjects[$this->xobjid]['outdata'] .= $s."\n";
10401 } elseif ((!$this->InFooter) AND isset($this->footerlen[$this->page]) AND ($this->footerlen[$this->page] > 0)) {
10402 // puts data before page footer
10403 $pagebuff = $this->getPageBuffer($this->page);
10404 $page = substr($pagebuff, 0, -$this->footerlen[$this->page]);
10405 $footer = substr($pagebuff, -$this->footerlen[$this->page]);
10406 $this->setPageBuffer($this->page, $page.$s."\n".$footer);
10407 // update footer position
10408 $this->footerpos[$this->page] += strlen($s."\n");
10409 } else {
10410 // set page data
10411 $this->setPageBuffer($this->page, $s."\n", true);
10412 }
10413 } elseif ($this->state > 0) {
10414 // set general data
10415 $this->setBuffer($s."\n");
10416 }
10417 }
10418
10419 /**
10420 * Set header font.
10421 * @param $font (array) Array describing the basic font parameters: (family, style, size).
10422 * @public
10423 * @since 1.1
10424 */
10425 public function setHeaderFont($font) {
10426 $this->header_font = $font;
10427 }
10428
10429 /**
10430 * Get header font.
10431 * @return array() Array describing the basic font parameters: (family, style, size).
10432 * @public
10433 * @since 4.0.012 (2008-07-24)
10434 */
10435 public function getHeaderFont() {
10436 return $this->header_font;
10437 }
10438
10439 /**
10440 * Set footer font.
10441 * @param $font (array) Array describing the basic font parameters: (family, style, size).
10442 * @public
10443 * @since 1.1
10444 */
10445 public function setFooterFont($font) {
10446 $this->footer_font = $font;
10447 }
10448
10449 /**
10450 * Get Footer font.
10451 * @return array() Array describing the basic font parameters: (family, style, size).
10452 * @public
10453 * @since 4.0.012 (2008-07-24)
10454 */
10455 public function getFooterFont() {
10456 return $this->footer_font;
10457 }
10458
10459 /**
10460 * Set language array.
10461 * @param $language (array)
10462 * @public
10463 * @since 1.1
10464 */
10465 public function setLanguageArray($language) {
10466 $this->l = $language;
10467 if (isset($this->l['a_meta_dir'])) {
10468 $this->rtl = $this->l['a_meta_dir']=='rtl' ? true : false;
10469 } else {
10470 $this->rtl = false;
10471 }
10472 }
10473
10474 /**
10475 * Returns the PDF data.
10476 * @public
10477 */
10478 public function getPDFData() {
10479 if ($this->state < 3) {
10480 $this->Close();
10481 }
10482 return $this->buffer;
10483 }
10484
10485 /**
10486 * Output anchor link.
10487 * @param $url (string) link URL or internal link (i.e.: &lt;a href="#23,4.5"&gt;link to page 23 at 4.5 Y position&lt;/a&gt;)
10488 * @param $name (string) link name
10489 * @param $fill (boolean) Indicates if the cell background must be painted (true) or transparent (false).
10490 * @param $firstline (boolean) if true prints only the first line and return the remaining string.
10491 * @param $color (array) array of RGB text color
10492 * @param $style (string) font style (U, D, B, I)
10493 * @param $firstblock (boolean) if true the string is the starting of a line.
10494 * @return the number of cells used or the remaining text if $firstline = true;
10495 * @public
10496 */
10497 public function addHtmlLink($url, $name, $fill=false, $firstline=false, $color='', $style=-1, $firstblock=false) {
10498 if (isset($url[1]) AND ($url[0] == '#')) {
10499 // convert url to internal link
10500 $lnkdata = explode(',', $url);
10501 if (isset($lnkdata[0]) ) {
10502 $page = substr($lnkdata[0], 1);
10503 if (isset($lnkdata[1]) AND (strlen($lnkdata[1]) > 0)) {
10504 $lnky = floatval($lnkdata[1]);
10505 } else {
10506 $lnky = 0;
10507 }
10508 $url = $this->AddLink();
10509 $this->SetLink($url, $lnky, $page);
10510 }
10511 }
10512 // store current settings
10513 $prevcolor = $this->fgcolor;
10514 $prevstyle = $this->FontStyle;
10515 if (empty($color)) {
10516 $this->SetTextColorArray($this->htmlLinkColorArray);
10517 } else {
10518 $this->SetTextColorArray($color);
10519 }
10520 if ($style == -1) {
10521 $this->SetFont('', $this->FontStyle.$this->htmlLinkFontStyle);
10522 } else {
10523 $this->SetFont('', $this->FontStyle.$style);
10524 }
10525 $ret = $this->Write($this->lasth, $name, $url, $fill, '', false, 0, $firstline, $firstblock, 0);
10526 // restore settings
10527 $this->SetFont('', $prevstyle);
10528 $this->SetTextColorArray($prevcolor);
10529 return $ret;
10530 }
10531
10532 /**
10533 * Converts pixels to User's Units.
10534 * @param $px (int) pixels
10535 * @return float value in user's unit
10536 * @public
10537 * @see setImageScale(), getImageScale()
10538 */
10539 public function pixelsToUnits($px) {
10540 return ($px / ($this->imgscale * $this->k));
10541 }
10542
10543 /**
10544 * Reverse function for htmlentities.
10545 * Convert entities in UTF-8.
10546 * @param $text_to_convert (string) Text to convert.
10547 * @return string converted text string
10548 * @public
10549 */
10550 public function unhtmlentities($text_to_convert) {
10551 return @html_entity_decode($text_to_convert, ENT_QUOTES, $this->encoding);
10552 }
10553
10554 // ENCRYPTION METHODS ----------------------------------
10555
10556 /**
10557 * Compute encryption key depending on object number where the encrypted data is stored.
10558 * This is used for all strings and streams without crypt filter specifier.
10559 * @param $n (int) object number
10560 * @return int object key
10561 * @protected
10562 * @author Nicola Asuni
10563 * @since 2.0.000 (2008-01-02)
10564 */
10565 protected function _objectkey($n) {
10566 $objkey = $this->encryptdata['key'].pack('VXxx', $n);
10567 if ($this->encryptdata['mode'] == 2) { // AES-128
10568 // AES padding
10569 $objkey .= "\x73\x41\x6C\x54"; // sAlT
10570 }
10571 $objkey = substr(TCPDF_STATIC::_md5_16($objkey), 0, (($this->encryptdata['Length'] / 8) + 5));
10572 $objkey = substr($objkey, 0, 16);
10573 return $objkey;
10574 }
10575
10576 /**
10577 * Encrypt the input string.
10578 * @param $n (int) object number
10579 * @param $s (string) data string to encrypt
10580 * @return encrypted string
10581 * @protected
10582 * @author Nicola Asuni
10583 * @since 5.0.005 (2010-05-11)
10584 */
10585 protected function _encrypt_data($n, $s) {
10586 if (!$this->encrypted) {
10587 return $s;
10588 }
10589 switch ($this->encryptdata['mode']) {
10590 case 0: // RC4-40
10591 case 1: { // RC4-128
10592 $s = TCPDF_STATIC::_RC4($this->_objectkey($n), $s, $this->last_enc_key, $this->last_enc_key_c);
10593 break;
10594 }
10595 case 2: { // AES-128
10596 $s = TCPDF_STATIC::_AES($this->_objectkey($n), $s);
10597 break;
10598 }
10599 case 3: { // AES-256
10600 $s = TCPDF_STATIC::_AES($this->encryptdata['key'], $s);
10601 break;
10602 }
10603 }
10604 return $s;
10605 }
10606
10607 /**
10608 * Put encryption on PDF document.
10609 * @protected
10610 * @author Nicola Asuni
10611 * @since 2.0.000 (2008-01-02)
10612 */
10613 protected function _putencryption() {
10614 if (!$this->encrypted) {
10615 return;
10616 }
10617 $this->encryptdata['objid'] = $this->_newobj();
10618 $out = '<<';
10619 if (!isset($this->encryptdata['Filter']) OR empty($this->encryptdata['Filter'])) {
10620 $this->encryptdata['Filter'] = 'Standard';
10621 }
10622 $out .= ' /Filter /'.$this->encryptdata['Filter'];
10623 if (isset($this->encryptdata['SubFilter']) AND !empty($this->encryptdata['SubFilter'])) {
10624 $out .= ' /SubFilter /'.$this->encryptdata['SubFilter'];
10625 }
10626 if (!isset($this->encryptdata['V']) OR empty($this->encryptdata['V'])) {
10627 $this->encryptdata['V'] = 1;
10628 }
10629 // V is a code specifying the algorithm to be used in encrypting and decrypting the document
10630 $out .= ' /V '.$this->encryptdata['V'];
10631 if (isset($this->encryptdata['Length']) AND !empty($this->encryptdata['Length'])) {
10632 // The length of the encryption key, in bits. The value shall be a multiple of 8, in the range 40 to 256
10633 $out .= ' /Length '.$this->encryptdata['Length'];
10634 } else {
10635 $out .= ' /Length 40';
10636 }
10637 if ($this->encryptdata['V'] >= 4) {
10638 if (!isset($this->encryptdata['StmF']) OR empty($this->encryptdata['StmF'])) {
10639 $this->encryptdata['StmF'] = 'Identity';
10640 }
10641 if (!isset($this->encryptdata['StrF']) OR empty($this->encryptdata['StrF'])) {
10642 // The name of the crypt filter that shall be used when decrypting all strings in the document.
10643 $this->encryptdata['StrF'] = 'Identity';
10644 }
10645 // A dictionary whose keys shall be crypt filter names and whose values shall be the corresponding crypt filter dictionaries.
10646 if (isset($this->encryptdata['CF']) AND !empty($this->encryptdata['CF'])) {
10647 $out .= ' /CF <<';
10648 $out .= ' /'.$this->encryptdata['StmF'].' <<';
10649 $out .= ' /Type /CryptFilter';
10650 if (isset($this->encryptdata['CF']['CFM']) AND !empty($this->encryptdata['CF']['CFM'])) {
10651 // The method used
10652 $out .= ' /CFM /'.$this->encryptdata['CF']['CFM'];
10653 if ($this->encryptdata['pubkey']) {
10654 $out .= ' /Recipients [';
10655 foreach ($this->encryptdata['Recipients'] as $rec) {
10656 $out .= ' <'.$rec.'>';
10657 }
10658 $out .= ' ]';
10659 if (isset($this->encryptdata['CF']['EncryptMetadata']) AND (!$this->encryptdata['CF']['EncryptMetadata'])) {
10660 $out .= ' /EncryptMetadata false';
10661 } else {
10662 $out .= ' /EncryptMetadata true';
10663 }
10664 }
10665 } else {
10666 $out .= ' /CFM /None';
10667 }
10668 if (isset($this->encryptdata['CF']['AuthEvent']) AND !empty($this->encryptdata['CF']['AuthEvent'])) {
10669 // The event to be used to trigger the authorization that is required to access encryption keys used by this filter.
10670 $out .= ' /AuthEvent /'.$this->encryptdata['CF']['AuthEvent'];
10671 } else {
10672 $out .= ' /AuthEvent /DocOpen';
10673 }
10674 if (isset($this->encryptdata['CF']['Length']) AND !empty($this->encryptdata['CF']['Length'])) {
10675 // The bit length of the encryption key.
10676 $out .= ' /Length '.$this->encryptdata['CF']['Length'];
10677 }
10678 $out .= ' >> >>';
10679 }
10680 // The name of the crypt filter that shall be used by default when decrypting streams.
10681 $out .= ' /StmF /'.$this->encryptdata['StmF'];
10682 // The name of the crypt filter that shall be used when decrypting all strings in the document.
10683 $out .= ' /StrF /'.$this->encryptdata['StrF'];
10684 if (isset($this->encryptdata['EFF']) AND !empty($this->encryptdata['EFF'])) {
10685 // The name of the crypt filter that shall be used when encrypting embedded file streams that do not have their own crypt filter specifier.
10686 $out .= ' /EFF /'.$this->encryptdata[''];
10687 }
10688 }
10689 // Additional encryption dictionary entries for the standard security handler
10690 if ($this->encryptdata['pubkey']) {
10691 if (($this->encryptdata['V'] < 4) AND isset($this->encryptdata['Recipients']) AND !empty($this->encryptdata['Recipients'])) {
10692 $out .= ' /Recipients [';
10693 foreach ($this->encryptdata['Recipients'] as $rec) {
10694 $out .= ' <'.$rec.'>';
10695 }
10696 $out .= ' ]';
10697 }
10698 } else {
10699 $out .= ' /R';
10700 if ($this->encryptdata['V'] == 5) { // AES-256
10701 $out .= ' 5';
10702 $out .= ' /OE ('.TCPDF_STATIC::_escape($this->encryptdata['OE']).')';
10703 $out .= ' /UE ('.TCPDF_STATIC::_escape($this->encryptdata['UE']).')';
10704 $out .= ' /Perms ('.TCPDF_STATIC::_escape($this->encryptdata['perms']).')';
10705 } elseif ($this->encryptdata['V'] == 4) { // AES-128
10706 $out .= ' 4';
10707 } elseif ($this->encryptdata['V'] < 2) { // RC-40
10708 $out .= ' 2';
10709 } else { // RC-128
10710 $out .= ' 3';
10711 }
10712 $out .= ' /O ('.TCPDF_STATIC::_escape($this->encryptdata['O']).')';
10713 $out .= ' /U ('.TCPDF_STATIC::_escape($this->encryptdata['U']).')';
10714 $out .= ' /P '.$this->encryptdata['P'];
10715 if (isset($this->encryptdata['EncryptMetadata']) AND (!$this->encryptdata['EncryptMetadata'])) {
10716 $out .= ' /EncryptMetadata false';
10717 } else {
10718 $out .= ' /EncryptMetadata true';
10719 }
10720 }
10721 $out .= ' >>';
10722 $out .= "\n".'endobj';
10723 $this->_out($out);
10724 }
10725
10726 /**
10727 * Compute U value (used for encryption)
10728 * @return string U value
10729 * @protected
10730 * @since 2.0.000 (2008-01-02)
10731 * @author Nicola Asuni
10732 */
10733 protected function _Uvalue() {
10734 if ($this->encryptdata['mode'] == 0) { // RC4-40
10735 return TCPDF_STATIC::_RC4($this->encryptdata['key'], TCPDF_STATIC::$enc_padding, $this->last_enc_key, $this->last_enc_key_c);
10736 } elseif ($this->encryptdata['mode'] < 3) { // RC4-128, AES-128
10737 $tmp = TCPDF_STATIC::_md5_16(TCPDF_STATIC::$enc_padding.$this->encryptdata['fileid']);
10738 $enc = TCPDF_STATIC::_RC4($this->encryptdata['key'], $tmp, $this->last_enc_key, $this->last_enc_key_c);
10739 $len = strlen($tmp);
10740 for ($i = 1; $i <= 19; ++$i) {
10741 $ek = '';
10742 for ($j = 0; $j < $len; ++$j) {
10743 $ek .= chr(ord($this->encryptdata['key'][$j]) ^ $i);
10744 }
10745 $enc = TCPDF_STATIC::_RC4($ek, $enc, $this->last_enc_key, $this->last_enc_key_c);
10746 }
10747 $enc .= str_repeat("\x00", 16);
10748 return substr($enc, 0, 32);
10749 } elseif ($this->encryptdata['mode'] == 3) { // AES-256
10750 $seed = TCPDF_STATIC::_md5_16(TCPDF_STATIC::getRandomSeed());
10751 // User Validation Salt
10752 $this->encryptdata['UVS'] = substr($seed, 0, 8);
10753 // User Key Salt
10754 $this->encryptdata['UKS'] = substr($seed, 8, 16);
10755 return hash('sha256', $this->encryptdata['user_password'].$this->encryptdata['UVS'], true).$this->encryptdata['UVS'].$this->encryptdata['UKS'];
10756 }
10757 }
10758
10759 /**
10760 * Compute UE value (used for encryption)
10761 * @return string UE value
10762 * @protected
10763 * @since 5.9.006 (2010-10-19)
10764 * @author Nicola Asuni
10765 */
10766 protected function _UEvalue() {
10767 $hashkey = hash('sha256', $this->encryptdata['user_password'].$this->encryptdata['UKS'], true);
10768 $iv = str_repeat("\x00", mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC));
10769 return mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $hashkey, $this->encryptdata['key'], MCRYPT_MODE_CBC, $iv);
10770 }
10771
10772 /**
10773 * Compute O value (used for encryption)
10774 * @return string O value
10775 * @protected
10776 * @since 2.0.000 (2008-01-02)
10777 * @author Nicola Asuni
10778 */
10779 protected function _Ovalue() {
10780 if ($this->encryptdata['mode'] < 3) { // RC4-40, RC4-128, AES-128
10781 $tmp = TCPDF_STATIC::_md5_16($this->encryptdata['owner_password']);
10782 if ($this->encryptdata['mode'] > 0) {
10783 for ($i = 0; $i < 50; ++$i) {
10784 $tmp = TCPDF_STATIC::_md5_16($tmp);
10785 }
10786 }
10787 $owner_key = substr($tmp, 0, ($this->encryptdata['Length'] / 8));
10788 $enc = TCPDF_STATIC::_RC4($owner_key, $this->encryptdata['user_password'], $this->last_enc_key, $this->last_enc_key_c);
10789 if ($this->encryptdata['mode'] > 0) {
10790 $len = strlen($owner_key);
10791 for ($i = 1; $i <= 19; ++$i) {
10792 $ek = '';
10793 for ($j = 0; $j < $len; ++$j) {
10794 $ek .= chr(ord($owner_key[$j]) ^ $i);
10795 }
10796 $enc = TCPDF_STATIC::_RC4($ek, $enc, $this->last_enc_key, $this->last_enc_key_c);
10797 }
10798 }
10799 return $enc;
10800 } elseif ($this->encryptdata['mode'] == 3) { // AES-256
10801 $seed = TCPDF_STATIC::_md5_16(TCPDF_STATIC::getRandomSeed());
10802 // Owner Validation Salt
10803 $this->encryptdata['OVS'] = substr($seed, 0, 8);
10804 // Owner Key Salt
10805 $this->encryptdata['OKS'] = substr($seed, 8, 16);
10806 return hash('sha256', $this->encryptdata['owner_password'].$this->encryptdata['OVS'].$this->encryptdata['U'], true).$this->encryptdata['OVS'].$this->encryptdata['OKS'];
10807 }
10808 }
10809
10810 /**
10811 * Compute OE value (used for encryption)
10812 * @return string OE value
10813 * @protected
10814 * @since 5.9.006 (2010-10-19)
10815 * @author Nicola Asuni
10816 */
10817 protected function _OEvalue() {
10818 $hashkey = hash('sha256', $this->encryptdata['owner_password'].$this->encryptdata['OKS'].$this->encryptdata['U'], true);
10819 $iv = str_repeat("\x00", mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC));
10820 return mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $hashkey, $this->encryptdata['key'], MCRYPT_MODE_CBC, $iv);
10821 }
10822
10823 /**
10824 * Convert password for AES-256 encryption mode
10825 * @param $password (string) password
10826 * @return string password
10827 * @protected
10828 * @since 5.9.006 (2010-10-19)
10829 * @author Nicola Asuni
10830 */
10831 protected function _fixAES256Password($password) {
10832 $psw = ''; // password to be returned
10833 $psw_array = TCPDF_FONTS::utf8Bidi(TCPDF_FONTS::UTF8StringToArray($password, $this->isunicode, $this->CurrentFont), $password, $this->rtl, $this->isunicode, $this->CurrentFont);
10834 foreach ($psw_array as $c) {
10835 $psw .= TCPDF_FONTS::unichr($c, $this->isunicode);
10836 }
10837 return substr($psw, 0, 127);
10838 }
10839
10840 /**
10841 * Compute encryption key
10842 * @protected
10843 * @since 2.0.000 (2008-01-02)
10844 * @author Nicola Asuni
10845 */
10846 protected function _generateencryptionkey() {
10847 $keybytelen = ($this->encryptdata['Length'] / 8);
10848 if (!$this->encryptdata['pubkey']) { // standard mode
10849 if ($this->encryptdata['mode'] == 3) { // AES-256
10850 // generate 256 bit random key
10851 $this->encryptdata['key'] = substr(hash('sha256', TCPDF_STATIC::getRandomSeed(), true), 0, $keybytelen);
10852 // truncate passwords
10853 $this->encryptdata['user_password'] = $this->_fixAES256Password($this->encryptdata['user_password']);
10854 $this->encryptdata['owner_password'] = $this->_fixAES256Password($this->encryptdata['owner_password']);
10855 // Compute U value
10856 $this->encryptdata['U'] = $this->_Uvalue();
10857 // Compute UE value
10858 $this->encryptdata['UE'] = $this->_UEvalue();
10859 // Compute O value
10860 $this->encryptdata['O'] = $this->_Ovalue();
10861 // Compute OE value
10862 $this->encryptdata['OE'] = $this->_OEvalue();
10863 // Compute P value
10864 $this->encryptdata['P'] = $this->encryptdata['protection'];
10865 // Computing the encryption dictionary's Perms (permissions) value
10866 $perms = TCPDF_STATIC::getEncPermissionsString($this->encryptdata['protection']); // bytes 0-3
10867 $perms .= chr(255).chr(255).chr(255).chr(255); // bytes 4-7
10868 if (isset($this->encryptdata['CF']['EncryptMetadata']) AND (!$this->encryptdata['CF']['EncryptMetadata'])) { // byte 8
10869 $perms .= 'F';
10870 } else {
10871 $perms .= 'T';
10872 }
10873 $perms .= 'adb'; // bytes 9-11
10874 $perms .= 'nick'; // bytes 12-15
10875 $iv = str_repeat("\x00", mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB));
10876 $this->encryptdata['perms'] = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $this->encryptdata['key'], $perms, MCRYPT_MODE_ECB, $iv);
10877 } else { // RC4-40, RC4-128, AES-128
10878 // Pad passwords
10879 $this->encryptdata['user_password'] = substr($this->encryptdata['user_password'].TCPDF_STATIC::$enc_padding, 0, 32);
10880 $this->encryptdata['owner_password'] = substr($this->encryptdata['owner_password'].TCPDF_STATIC::$enc_padding, 0, 32);
10881 // Compute O value
10882 $this->encryptdata['O'] = $this->_Ovalue();
10883 // get default permissions (reverse byte order)
10884 $permissions = TCPDF_STATIC::getEncPermissionsString($this->encryptdata['protection']);
10885 // Compute encryption key
10886 $tmp = TCPDF_STATIC::_md5_16($this->encryptdata['user_password'].$this->encryptdata['O'].$permissions.$this->encryptdata['fileid']);
10887 if ($this->encryptdata['mode'] > 0) {
10888 for ($i = 0; $i < 50; ++$i) {
10889 $tmp = TCPDF_STATIC::_md5_16(substr($tmp, 0, $keybytelen));
10890 }
10891 }
10892 $this->encryptdata['key'] = substr($tmp, 0, $keybytelen);
10893 // Compute U value
10894 $this->encryptdata['U'] = $this->_Uvalue();
10895 // Compute P value
10896 $this->encryptdata['P'] = $this->encryptdata['protection'];
10897 }
10898 } else { // Public-Key mode
10899 // random 20-byte seed
10900 $seed = sha1(TCPDF_STATIC::getRandomSeed(), true);
10901 $recipient_bytes = '';
10902 foreach ($this->encryptdata['pubkeys'] as $pubkey) {
10903 // for each public certificate
10904 if (isset($pubkey['p'])) {
10905 $pkprotection = TCPDF_STATIC::getUserPermissionCode($pubkey['p'], $this->encryptdata['mode']);
10906 } else {
10907 $pkprotection = $this->encryptdata['protection'];
10908 }
10909 // get default permissions (reverse byte order)
10910 $pkpermissions = TCPDF_STATIC::getEncPermissionsString($pkprotection);
10911 // envelope data
10912 $envelope = $seed.$pkpermissions;
10913 // write the envelope data to a temporary file
10914 $tempkeyfile = TCPDF_STATIC::getObjFilename('key');
10915 $f = fopen($tempkeyfile, 'wb');
10916 if (!$f) {
10917 $this->Error('Unable to create temporary key file: '.$tempkeyfile);
10918 }
10919 $envelope_length = strlen($envelope);
10920 fwrite($f, $envelope, $envelope_length);
10921 fclose($f);
10922 $tempencfile = TCPDF_STATIC::getObjFilename('enc');
10923 if (!openssl_pkcs7_encrypt($tempkeyfile, $tempencfile, $pubkey['c'], array(), PKCS7_BINARY | PKCS7_DETACHED)) {
10924 $this->Error('Unable to encrypt the file: '.$tempkeyfile);
10925 }
10926 unlink($tempkeyfile);
10927 // read encryption signature
10928 $signature = file_get_contents($tempencfile, false, null, $envelope_length);
10929 unlink($tempencfile);
10930 // extract signature
10931 $signature = substr($signature, strpos($signature, 'Content-Disposition'));
10932 $tmparr = explode("\n\n", $signature);
10933 $signature = trim($tmparr[1]);
10934 unset($tmparr);
10935 // decode signature
10936 $signature = base64_decode($signature);
10937 // convert signature to hex
10938 $hexsignature = current(unpack('H*', $signature));
10939 // store signature on recipients array
10940 $this->encryptdata['Recipients'][] = $hexsignature;
10941 // The bytes of each item in the Recipients array of PKCS#7 objects in the order in which they appear in the array
10942 $recipient_bytes .= $signature;
10943 }
10944 // calculate encryption key
10945 if ($this->encryptdata['mode'] == 3) { // AES-256
10946 $this->encryptdata['key'] = substr(hash('sha256', $seed.$recipient_bytes, true), 0, $keybytelen);
10947 } else { // RC4-40, RC4-128, AES-128
10948 $this->encryptdata['key'] = substr(sha1($seed.$recipient_bytes, true), 0, $keybytelen);
10949 }
10950 }
10951 }
10952
10953 /**
10954 * Set document protection
10955 * Remark: the protection against modification is for people who have the full Acrobat product.
10956 * If you don't set any password, the document will open as usual. If you set a user password, the PDF viewer will ask for it before displaying the document. The master password, if different from the user one, can be used to get full access.
10957 * Note: protecting a document requires to encrypt it, which increases the processing time a lot. This can cause a PHP time-out in some cases, especially if the document contains images or fonts.
10958 * @param $permissions (Array) the set of permissions (specify the ones you want to block):<ul><li>print : Print the document;</li><li>modify : Modify the contents of the document by operations other than those controlled by 'fill-forms', 'extract' and 'assemble';</li><li>copy : Copy or otherwise extract text and graphics from the document;</li><li>annot-forms : Add or modify text annotations, fill in interactive form fields, and, if 'modify' is also set, create or modify interactive form fields (including signature fields);</li><li>fill-forms : Fill in existing interactive form fields (including signature fields), even if 'annot-forms' is not specified;</li><li>extract : Extract text and graphics (in support of accessibility to users with disabilities or for other purposes);</li><li>assemble : Assemble the document (insert, rotate, or delete pages and create bookmarks or thumbnail images), even if 'modify' is not set;</li><li>print-high : Print the document to a representation from which a faithful digital copy of the PDF content could be generated. When this is not set, printing is limited to a low-level representation of the appearance, possibly of degraded quality.</li><li>owner : (inverted logic - only for public-key) when set permits change of encryption and enables all other permissions.</li></ul>
10959 * @param $user_pass (String) user password. Empty by default.
10960 * @param $owner_pass (String) owner password. If not specified, a random value is used.
10961 * @param $mode (int) encryption strength: 0 = RC4 40 bit; 1 = RC4 128 bit; 2 = AES 128 bit; 3 = AES 256 bit.
10962 * @param $pubkeys (String) array of recipients containing public-key certificates ('c') and permissions ('p'). For example: array(array('c' => 'file://../examples/data/cert/tcpdf.crt', 'p' => array('print')))
10963 * @public
10964 * @since 2.0.000 (2008-01-02)
10965 * @author Nicola Asuni
10966 */
10967 public function SetProtection($permissions=array('print', 'modify', 'copy', 'annot-forms', 'fill-forms', 'extract', 'assemble', 'print-high'), $user_pass='', $owner_pass=null, $mode=0, $pubkeys=null) {
10968 if ($this->pdfa_mode) {
10969 // encryption is not allowed in PDF/A mode
10970 return;
10971 }
10972 $this->encryptdata['protection'] = TCPDF_STATIC::getUserPermissionCode($permissions, $mode);
10973 if (($pubkeys !== null) AND (is_array($pubkeys))) {
10974 // public-key mode
10975 $this->encryptdata['pubkeys'] = $pubkeys;
10976 if ($mode == 0) {
10977 // public-Key Security requires at least 128 bit
10978 $mode = 1;
10979 }
10980 if (!function_exists('openssl_pkcs7_encrypt')) {
10981 $this->Error('Public-Key Security requires openssl library.');
10982 }
10983 // Set Public-Key filter (availabe are: Entrust.PPKEF, Adobe.PPKLite, Adobe.PubSec)
10984 $this->encryptdata['pubkey'] = true;
10985 $this->encryptdata['Filter'] = 'Adobe.PubSec';
10986 $this->encryptdata['StmF'] = 'DefaultCryptFilter';
10987 $this->encryptdata['StrF'] = 'DefaultCryptFilter';
10988 } else {
10989 // standard mode (password mode)
10990 $this->encryptdata['pubkey'] = false;
10991 $this->encryptdata['Filter'] = 'Standard';
10992 $this->encryptdata['StmF'] = 'StdCF';
10993 $this->encryptdata['StrF'] = 'StdCF';
10994 }
10995 if ($mode > 1) { // AES
10996 if (!extension_loaded('mcrypt')) {
10997 $this->Error('AES encryption requires mcrypt library (http://www.php.net/manual/en/mcrypt.requirements.php).');
10998 }
10999 if (mcrypt_get_cipher_name(MCRYPT_RIJNDAEL_128) === false) {
11000 $this->Error('AES encryption requires MCRYPT_RIJNDAEL_128 cypher.');
11001 }
11002 if (($mode == 3) AND !function_exists('hash')) {
11003 // the Hash extension requires no external libraries and is enabled by default as of PHP 5.1.2.
11004 $this->Error('AES 256 encryption requires HASH Message Digest Framework (http://www.php.net/manual/en/book.hash.php).');
11005 }
11006 }
11007 if ($owner_pass === null) {
11008 $owner_pass = md5(TCPDF_STATIC::getRandomSeed());
11009 }
11010 $this->encryptdata['user_password'] = $user_pass;
11011 $this->encryptdata['owner_password'] = $owner_pass;
11012 $this->encryptdata['mode'] = $mode;
11013 switch ($mode) {
11014 case 0: { // RC4 40 bit
11015 $this->encryptdata['V'] = 1;
11016 $this->encryptdata['Length'] = 40;
11017 $this->encryptdata['CF']['CFM'] = 'V2';
11018 break;
11019 }
11020 case 1: { // RC4 128 bit
11021 $this->encryptdata['V'] = 2;
11022 $this->encryptdata['Length'] = 128;
11023 $this->encryptdata['CF']['CFM'] = 'V2';
11024 if ($this->encryptdata['pubkey']) {
11025 $this->encryptdata['SubFilter'] = 'adbe.pkcs7.s4';
11026 $this->encryptdata['Recipients'] = array();
11027 }
11028 break;
11029 }
11030 case 2: { // AES 128 bit
11031 $this->encryptdata['V'] = 4;
11032 $this->encryptdata['Length'] = 128;
11033 $this->encryptdata['CF']['CFM'] = 'AESV2';
11034 $this->encryptdata['CF']['Length'] = 128;
11035 if ($this->encryptdata['pubkey']) {
11036 $this->encryptdata['SubFilter'] = 'adbe.pkcs7.s5';
11037 $this->encryptdata['Recipients'] = array();
11038 }
11039 break;
11040 }
11041 case 3: { // AES 256 bit
11042 $this->encryptdata['V'] = 5;
11043 $this->encryptdata['Length'] = 256;
11044 $this->encryptdata['CF']['CFM'] = 'AESV3';
11045 $this->encryptdata['CF']['Length'] = 256;
11046 if ($this->encryptdata['pubkey']) {
11047 $this->encryptdata['SubFilter'] = 'adbe.pkcs7.s5';
11048 $this->encryptdata['Recipients'] = array();
11049 }
11050 break;
11051 }
11052 }
11053 $this->encrypted = true;
11054 $this->encryptdata['fileid'] = TCPDF_STATIC::convertHexStringToString($this->file_id);
11055 $this->_generateencryptionkey();
11056 }
11057
11058 // END OF ENCRYPTION FUNCTIONS -------------------------
11059
11060 // START TRANSFORMATIONS SECTION -----------------------
11061
11062 /**
11063 * Starts a 2D tranformation saving current graphic state.
11064 * This function must be called before scaling, mirroring, translation, rotation and skewing.
11065 * Use StartTransform() before, and StopTransform() after the transformations to restore the normal behavior.
11066 * @public
11067 * @since 2.1.000 (2008-01-07)
11068 * @see StartTransform(), StopTransform()
11069 */
11070 public function StartTransform() {
11071 if ($this->state != 2) {
11072 return;
11073 }
11074 $this->_outSaveGraphicsState();
11075 if ($this->inxobj) {
11076 // we are inside an XObject template
11077 $this->xobjects[$this->xobjid]['transfmrk'][] = strlen($this->xobjects[$this->xobjid]['outdata']);
11078 } else {
11079 $this->transfmrk[$this->page][] = $this->pagelen[$this->page];
11080 }
11081 ++$this->transfmatrix_key;
11082 $this->transfmatrix[$this->transfmatrix_key] = array();
11083 }
11084
11085 /**
11086 * Stops a 2D tranformation restoring previous graphic state.
11087 * This function must be called after scaling, mirroring, translation, rotation and skewing.
11088 * Use StartTransform() before, and StopTransform() after the transformations to restore the normal behavior.
11089 * @public
11090 * @since 2.1.000 (2008-01-07)
11091 * @see StartTransform(), StopTransform()
11092 */
11093 public function StopTransform() {
11094 if ($this->state != 2) {
11095 return;
11096 }
11097 $this->_outRestoreGraphicsState();
11098 if (isset($this->transfmatrix[$this->transfmatrix_key])) {
11099 array_pop($this->transfmatrix[$this->transfmatrix_key]);
11100 --$this->transfmatrix_key;
11101 }
11102 if ($this->inxobj) {
11103 // we are inside an XObject template
11104 array_pop($this->xobjects[$this->xobjid]['transfmrk']);
11105 } else {
11106 array_pop($this->transfmrk[$this->page]);
11107 }
11108 }
11109 /**
11110 * Horizontal Scaling.
11111 * @param $s_x (float) scaling factor for width as percent. 0 is not allowed.
11112 * @param $x (int) abscissa of the scaling center. Default is current x position
11113 * @param $y (int) ordinate of the scaling center. Default is current y position
11114 * @public
11115 * @since 2.1.000 (2008-01-07)
11116 * @see StartTransform(), StopTransform()
11117 */
11118 public function ScaleX($s_x, $x='', $y='') {
11119 $this->Scale($s_x, 100, $x, $y);
11120 }
11121
11122 /**
11123 * Vertical Scaling.
11124 * @param $s_y (float) scaling factor for height as percent. 0 is not allowed.
11125 * @param $x (int) abscissa of the scaling center. Default is current x position
11126 * @param $y (int) ordinate of the scaling center. Default is current y position
11127 * @public
11128 * @since 2.1.000 (2008-01-07)
11129 * @see StartTransform(), StopTransform()
11130 */
11131 public function ScaleY($s_y, $x='', $y='') {
11132 $this->Scale(100, $s_y, $x, $y);
11133 }
11134
11135 /**
11136 * Vertical and horizontal proportional Scaling.
11137 * @param $s (float) scaling factor for width and height as percent. 0 is not allowed.
11138 * @param $x (int) abscissa of the scaling center. Default is current x position
11139 * @param $y (int) ordinate of the scaling center. Default is current y position
11140 * @public
11141 * @since 2.1.000 (2008-01-07)
11142 * @see StartTransform(), StopTransform()
11143 */
11144 public function ScaleXY($s, $x='', $y='') {
11145 $this->Scale($s, $s, $x, $y);
11146 }
11147
11148 /**
11149 * Vertical and horizontal non-proportional Scaling.
11150 * @param $s_x (float) scaling factor for width as percent. 0 is not allowed.
11151 * @param $s_y (float) scaling factor for height as percent. 0 is not allowed.
11152 * @param $x (int) abscissa of the scaling center. Default is current x position
11153 * @param $y (int) ordinate of the scaling center. Default is current y position
11154 * @public
11155 * @since 2.1.000 (2008-01-07)
11156 * @see StartTransform(), StopTransform()
11157 */
11158 public function Scale($s_x, $s_y, $x='', $y='') {
11159 if ($x === '') {
11160 $x = $this->x;
11161 }
11162 if ($y === '') {
11163 $y = $this->y;
11164 }
11165 if (($s_x == 0) OR ($s_y == 0)) {
11166 $this->Error('Please do not use values equal to zero for scaling');
11167 }
11168 $y = ($this->h - $y) * $this->k;
11169 $x *= $this->k;
11170 //calculate elements of transformation matrix
11171 $s_x /= 100;
11172 $s_y /= 100;
11173 $tm = array();
11174 $tm[0] = $s_x;
11175 $tm[1] = 0;
11176 $tm[2] = 0;
11177 $tm[3] = $s_y;
11178 $tm[4] = $x * (1 - $s_x);
11179 $tm[5] = $y * (1 - $s_y);
11180 //scale the coordinate system
11181 $this->Transform($tm);
11182 }
11183
11184 /**
11185 * Horizontal Mirroring.
11186 * @param $x (int) abscissa of the point. Default is current x position
11187 * @public
11188 * @since 2.1.000 (2008-01-07)
11189 * @see StartTransform(), StopTransform()
11190 */
11191 public function MirrorH($x='') {
11192 $this->Scale(-100, 100, $x);
11193 }
11194
11195 /**
11196 * Verical Mirroring.
11197 * @param $y (int) ordinate of the point. Default is current y position
11198 * @public
11199 * @since 2.1.000 (2008-01-07)
11200 * @see StartTransform(), StopTransform()
11201 */
11202 public function MirrorV($y='') {
11203 $this->Scale(100, -100, '', $y);
11204 }
11205
11206 /**
11207 * Point reflection mirroring.
11208 * @param $x (int) abscissa of the point. Default is current x position
11209 * @param $y (int) ordinate of the point. Default is current y position
11210 * @public
11211 * @since 2.1.000 (2008-01-07)
11212 * @see StartTransform(), StopTransform()
11213 */
11214 public function MirrorP($x='',$y='') {
11215 $this->Scale(-100, -100, $x, $y);
11216 }
11217
11218 /**
11219 * Reflection against a straight line through point (x, y) with the gradient angle (angle).
11220 * @param $angle (float) gradient angle of the straight line. Default is 0 (horizontal line).
11221 * @param $x (int) abscissa of the point. Default is current x position
11222 * @param $y (int) ordinate of the point. Default is current y position
11223 * @public
11224 * @since 2.1.000 (2008-01-07)
11225 * @see StartTransform(), StopTransform()
11226 */
11227 public function MirrorL($angle=0, $x='',$y='') {
11228 $this->Scale(-100, 100, $x, $y);
11229 $this->Rotate(-2*($angle-90), $x, $y);
11230 }
11231
11232 /**
11233 * Translate graphic object horizontally.
11234 * @param $t_x (int) movement to the right (or left for RTL)
11235 * @public
11236 * @since 2.1.000 (2008-01-07)
11237 * @see StartTransform(), StopTransform()
11238 */
11239 public function TranslateX($t_x) {
11240 $this->Translate($t_x, 0);
11241 }
11242
11243 /**
11244 * Translate graphic object vertically.
11245 * @param $t_y (int) movement to the bottom
11246 * @public
11247 * @since 2.1.000 (2008-01-07)
11248 * @see StartTransform(), StopTransform()
11249 */
11250 public function TranslateY($t_y) {
11251 $this->Translate(0, $t_y);
11252 }
11253
11254 /**
11255 * Translate graphic object horizontally and vertically.
11256 * @param $t_x (int) movement to the right
11257 * @param $t_y (int) movement to the bottom
11258 * @public
11259 * @since 2.1.000 (2008-01-07)
11260 * @see StartTransform(), StopTransform()
11261 */
11262 public function Translate($t_x, $t_y) {
11263 //calculate elements of transformation matrix
11264 $tm = array();
11265 $tm[0] = 1;
11266 $tm[1] = 0;
11267 $tm[2] = 0;
11268 $tm[3] = 1;
11269 $tm[4] = $t_x * $this->k;
11270 $tm[5] = -$t_y * $this->k;
11271 //translate the coordinate system
11272 $this->Transform($tm);
11273 }
11274
11275 /**
11276 * Rotate object.
11277 * @param $angle (float) angle in degrees for counter-clockwise rotation
11278 * @param $x (int) abscissa of the rotation center. Default is current x position
11279 * @param $y (int) ordinate of the rotation center. Default is current y position
11280 * @public
11281 * @since 2.1.000 (2008-01-07)
11282 * @see StartTransform(), StopTransform()
11283 */
11284 public function Rotate($angle, $x='', $y='') {
11285 if ($x === '') {
11286 $x = $this->x;
11287 }
11288 if ($y === '') {
11289 $y = $this->y;
11290 }
11291 $y = ($this->h - $y) * $this->k;
11292 $x *= $this->k;
11293 //calculate elements of transformation matrix
11294 $tm = array();
11295 $tm[0] = cos(deg2rad($angle));
11296 $tm[1] = sin(deg2rad($angle));
11297 $tm[2] = -$tm[1];
11298 $tm[3] = $tm[0];
11299 $tm[4] = $x + ($tm[1] * $y) - ($tm[0] * $x);
11300 $tm[5] = $y - ($tm[0] * $y) - ($tm[1] * $x);
11301 //rotate the coordinate system around ($x,$y)
11302 $this->Transform($tm);
11303 }
11304
11305 /**
11306 * Skew horizontally.
11307 * @param $angle_x (float) angle in degrees between -90 (skew to the left) and 90 (skew to the right)
11308 * @param $x (int) abscissa of the skewing center. default is current x position
11309 * @param $y (int) ordinate of the skewing center. default is current y position
11310 * @public
11311 * @since 2.1.000 (2008-01-07)
11312 * @see StartTransform(), StopTransform()
11313 */
11314 public function SkewX($angle_x, $x='', $y='') {
11315 $this->Skew($angle_x, 0, $x, $y);
11316 }
11317
11318 /**
11319 * Skew vertically.
11320 * @param $angle_y (float) angle in degrees between -90 (skew to the bottom) and 90 (skew to the top)
11321 * @param $x (int) abscissa of the skewing center. default is current x position
11322 * @param $y (int) ordinate of the skewing center. default is current y position
11323 * @public
11324 * @since 2.1.000 (2008-01-07)
11325 * @see StartTransform(), StopTransform()
11326 */
11327 public function SkewY($angle_y, $x='', $y='') {
11328 $this->Skew(0, $angle_y, $x, $y);
11329 }
11330
11331 /**
11332 * Skew.
11333 * @param $angle_x (float) angle in degrees between -90 (skew to the left) and 90 (skew to the right)
11334 * @param $angle_y (float) angle in degrees between -90 (skew to the bottom) and 90 (skew to the top)
11335 * @param $x (int) abscissa of the skewing center. default is current x position
11336 * @param $y (int) ordinate of the skewing center. default is current y position
11337 * @public
11338 * @since 2.1.000 (2008-01-07)
11339 * @see StartTransform(), StopTransform()
11340 */
11341 public function Skew($angle_x, $angle_y, $x='', $y='') {
11342 if ($x === '') {
11343 $x = $this->x;
11344 }
11345 if ($y === '') {
11346 $y = $this->y;
11347 }
11348 if (($angle_x <= -90) OR ($angle_x >= 90) OR ($angle_y <= -90) OR ($angle_y >= 90)) {
11349 $this->Error('Please use values between -90 and +90 degrees for Skewing.');
11350 }
11351 $x *= $this->k;
11352 $y = ($this->h - $y) * $this->k;
11353 //calculate elements of transformation matrix
11354 $tm = array();
11355 $tm[0] = 1;
11356 $tm[1] = tan(deg2rad($angle_y));
11357 $tm[2] = tan(deg2rad($angle_x));
11358 $tm[3] = 1;
11359 $tm[4] = -$tm[2] * $y;
11360 $tm[5] = -$tm[1] * $x;
11361 //skew the coordinate system
11362 $this->Transform($tm);
11363 }
11364
11365 /**
11366 * Apply graphic transformations.
11367 * @param $tm (array) transformation matrix
11368 * @protected
11369 * @since 2.1.000 (2008-01-07)
11370 * @see StartTransform(), StopTransform()
11371 */
11372 protected function Transform($tm) {
11373 if ($this->state != 2) {
11374 return;
11375 }
11376 $this->_out(sprintf('%F %F %F %F %F %F cm', $tm[0], $tm[1], $tm[2], $tm[3], $tm[4], $tm[5]));
11377 // add tranformation matrix
11378 $this->transfmatrix[$this->transfmatrix_key][] = array('a' => $tm[0], 'b' => $tm[1], 'c' => $tm[2], 'd' => $tm[3], 'e' => $tm[4], 'f' => $tm[5]);
11379 // update transformation mark
11380 if ($this->inxobj) {
11381 // we are inside an XObject template
11382 if (end($this->xobjects[$this->xobjid]['transfmrk']) !== false) {
11383 $key = key($this->xobjects[$this->xobjid]['transfmrk']);
11384 $this->xobjects[$this->xobjid]['transfmrk'][$key] = strlen($this->xobjects[$this->xobjid]['outdata']);
11385 }
11386 } elseif (end($this->transfmrk[$this->page]) !== false) {
11387 $key = key($this->transfmrk[$this->page]);
11388 $this->transfmrk[$this->page][$key] = $this->pagelen[$this->page];
11389 }
11390 }
11391
11392 // END TRANSFORMATIONS SECTION -------------------------
11393
11394 // START GRAPHIC FUNCTIONS SECTION ---------------------
11395 // The following section is based on the code provided by David Hernandez Sanz
11396
11397 /**
11398 * Defines the line width. By default, the value equals 0.2 mm. The method can be called before the first page is created and the value is retained from page to page.
11399 * @param $width (float) The width.
11400 * @public
11401 * @since 1.0
11402 * @see Line(), Rect(), Cell(), MultiCell()
11403 */
11404 public function SetLineWidth($width) {
11405 //Set line width
11406 $this->LineWidth = $width;
11407 $this->linestyleWidth = sprintf('%F w', ($width * $this->k));
11408 if ($this->state == 2) {
11409 $this->_out($this->linestyleWidth);
11410 }
11411 }
11412
11413 /**
11414 * Returns the current the line width.
11415 * @return int Line width
11416 * @public
11417 * @since 2.1.000 (2008-01-07)
11418 * @see Line(), SetLineWidth()
11419 */
11420 public function GetLineWidth() {
11421 return $this->LineWidth;
11422 }
11423
11424 /**
11425 * Set line style.
11426 * @param $style (array) Line style. Array with keys among the following:
11427 * <ul>
11428 * <li>width (float): Width of the line in user units.</li>
11429 * <li>cap (string): Type of cap to put on the line. Possible values are:
11430 * butt, round, square. The difference between "square" and "butt" is that
11431 * "square" projects a flat end past the end of the line.</li>
11432 * <li>join (string): Type of join. Possible values are: miter, round,
11433 * bevel.</li>
11434 * <li>dash (mixed): Dash pattern. Is 0 (without dash) or string with
11435 * series of length values, which are the lengths of the on and off dashes.
11436 * For example: "2" represents 2 on, 2 off, 2 on, 2 off, ...; "2,1" is 2 on,
11437 * 1 off, 2 on, 1 off, ...</li>
11438 * <li>phase (integer): Modifier on the dash pattern which is used to shift
11439 * the point at which the pattern starts.</li>
11440 * <li>color (array): Draw color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K) or array(C,M,Y,K,SpotColorName).</li>
11441 * </ul>
11442 * @param $ret (boolean) if true do not send the command.
11443 * @return string the PDF command
11444 * @public
11445 * @since 2.1.000 (2008-01-08)
11446 */
11447 public function SetLineStyle($style, $ret=false) {
11448 $s = ''; // string to be returned
11449 if (!is_array($style)) {
11450 return;
11451 }
11452 if (isset($style['width'])) {
11453 $this->LineWidth = $style['width'];
11454 $this->linestyleWidth = sprintf('%F w', ($style['width'] * $this->k));
11455 $s .= $this->linestyleWidth.' ';
11456 }
11457 if (isset($style['cap'])) {
11458 $ca = array('butt' => 0, 'round'=> 1, 'square' => 2);
11459 if (isset($ca[$style['cap']])) {
11460 $this->linestyleCap = $ca[$style['cap']].' J';
11461 $s .= $this->linestyleCap.' ';
11462 }
11463 }
11464 if (isset($style['join'])) {
11465 $ja = array('miter' => 0, 'round' => 1, 'bevel' => 2);
11466 if (isset($ja[$style['join']])) {
11467 $this->linestyleJoin = $ja[$style['join']].' j';
11468 $s .= $this->linestyleJoin.' ';
11469 }
11470 }
11471 if (isset($style['dash'])) {
11472 $dash_string = '';
11473 if ($style['dash']) {
11474 if (preg_match('/^.+,/', $style['dash']) > 0) {
11475 $tab = explode(',', $style['dash']);
11476 } else {
11477 $tab = array($style['dash']);
11478 }
11479 $dash_string = '';
11480 foreach ($tab as $i => $v) {
11481 if ($i) {
11482 $dash_string .= ' ';
11483 }
11484 $dash_string .= sprintf('%F', $v);
11485 }
11486 }
11487 if (!isset($style['phase']) OR !$style['dash']) {
11488 $style['phase'] = 0;
11489 }
11490 $this->linestyleDash = sprintf('[%s] %F d', $dash_string, $style['phase']);
11491 $s .= $this->linestyleDash.' ';
11492 }
11493 if (isset($style['color'])) {
11494 $s .= $this->SetDrawColorArray($style['color'], true).' ';
11495 }
11496 if (!$ret AND ($this->state == 2)) {
11497 $this->_out($s);
11498 }
11499 return $s;
11500 }
11501
11502 /**
11503 * Begin a new subpath by moving the current point to coordinates (x, y), omitting any connecting line segment.
11504 * @param $x (float) Abscissa of point.
11505 * @param $y (float) Ordinate of point.
11506 * @protected
11507 * @since 2.1.000 (2008-01-08)
11508 */
11509 protected function _outPoint($x, $y) {
11510 if ($this->state == 2) {
11511 $this->_out(sprintf('%F %F m', ($x * $this->k), (($this->h - $y) * $this->k)));
11512 }
11513 }
11514
11515 /**
11516 * Append a straight line segment from the current point to the point (x, y).
11517 * The new current point shall be (x, y).
11518 * @param $x (float) Abscissa of end point.
11519 * @param $y (float) Ordinate of end point.
11520 * @protected
11521 * @since 2.1.000 (2008-01-08)
11522 */
11523 protected function _outLine($x, $y) {
11524 if ($this->state == 2) {
11525 $this->_out(sprintf('%F %F l', ($x * $this->k), (($this->h - $y) * $this->k)));
11526 }
11527 }
11528
11529 /**
11530 * Append a rectangle to the current path as a complete subpath, with lower-left corner (x, y) and dimensions widthand height in user space.
11531 * @param $x (float) Abscissa of upper-left corner.
11532 * @param $y (float) Ordinate of upper-left corner.
11533 * @param $w (float) Width.
11534 * @param $h (float) Height.
11535 * @param $op (string) options
11536 * @protected
11537 * @since 2.1.000 (2008-01-08)
11538 */
11539 protected function _outRect($x, $y, $w, $h, $op) {
11540 if ($this->state == 2) {
11541 $this->_out(sprintf('%F %F %F %F re %s', ($x * $this->k), (($this->h - $y) * $this->k), ($w * $this->k), (-$h * $this->k), $op));
11542 }
11543 }
11544
11545 /**
11546 * Append a cubic Bezier curve to the current path. The curve shall extend from the current point to the point (x3, y3), using (x1, y1) and (x2, y2) as the Bezier control points.
11547 * The new current point shall be (x3, y3).
11548 * @param $x1 (float) Abscissa of control point 1.
11549 * @param $y1 (float) Ordinate of control point 1.
11550 * @param $x2 (float) Abscissa of control point 2.
11551 * @param $y2 (float) Ordinate of control point 2.
11552 * @param $x3 (float) Abscissa of end point.
11553 * @param $y3 (float) Ordinate of end point.
11554 * @protected
11555 * @since 2.1.000 (2008-01-08)
11556 */
11557 protected function _outCurve($x1, $y1, $x2, $y2, $x3, $y3) {
11558 if ($this->state == 2) {
11559 $this->_out(sprintf('%F %F %F %F %F %F c', ($x1 * $this->k), (($this->h - $y1) * $this->k), ($x2 * $this->k), (($this->h - $y2) * $this->k), ($x3 * $this->k), (($this->h - $y3) * $this->k)));
11560 }
11561 }
11562
11563 /**
11564 * Append a cubic Bezier curve to the current path. The curve shall extend from the current point to the point (x3, y3), using the current point and (x2, y2) as the Bezier control points.
11565 * The new current point shall be (x3, y3).
11566 * @param $x2 (float) Abscissa of control point 2.
11567 * @param $y2 (float) Ordinate of control point 2.
11568 * @param $x3 (float) Abscissa of end point.
11569 * @param $y3 (float) Ordinate of end point.
11570 * @protected
11571 * @since 4.9.019 (2010-04-26)
11572 */
11573 protected function _outCurveV($x2, $y2, $x3, $y3) {
11574 if ($this->state == 2) {
11575 $this->_out(sprintf('%F %F %F %F v', ($x2 * $this->k), (($this->h - $y2) * $this->k), ($x3 * $this->k), (($this->h - $y3) * $this->k)));
11576 }
11577 }
11578
11579 /**
11580 * Append a cubic Bezier curve to the current path. The curve shall extend from the current point to the point (x3, y3), using (x1, y1) and (x3, y3) as the Bezier control points.
11581 * The new current point shall be (x3, y3).
11582 * @param $x1 (float) Abscissa of control point 1.
11583 * @param $y1 (float) Ordinate of control point 1.
11584 * @param $x3 (float) Abscissa of end point.
11585 * @param $y3 (float) Ordinate of end point.
11586 * @protected
11587 * @since 2.1.000 (2008-01-08)
11588 */
11589 protected function _outCurveY($x1, $y1, $x3, $y3) {
11590 if ($this->state == 2) {
11591 $this->_out(sprintf('%F %F %F %F y', ($x1 * $this->k), (($this->h - $y1) * $this->k), ($x3 * $this->k), (($this->h - $y3) * $this->k)));
11592 }
11593 }
11594
11595 /**
11596 * Draws a line between two points.
11597 * @param $x1 (float) Abscissa of first point.
11598 * @param $y1 (float) Ordinate of first point.
11599 * @param $x2 (float) Abscissa of second point.
11600 * @param $y2 (float) Ordinate of second point.
11601 * @param $style (array) Line style. Array like for SetLineStyle(). Default value: default line style (empty array).
11602 * @public
11603 * @since 1.0
11604 * @see SetLineWidth(), SetDrawColor(), SetLineStyle()
11605 */
11606 public function Line($x1, $y1, $x2, $y2, $style=array()) {
11607 if ($this->state != 2) {
11608 return;
11609 }
11610 if (is_array($style)) {
11611 $this->SetLineStyle($style);
11612 }
11613 $this->_outPoint($x1, $y1);
11614 $this->_outLine($x2, $y2);
11615 $this->_out('S');
11616 }
11617
11618 /**
11619 * Draws a rectangle.
11620 * @param $x (float) Abscissa of upper-left corner.
11621 * @param $y (float) Ordinate of upper-left corner.
11622 * @param $w (float) Width.
11623 * @param $h (float) Height.
11624 * @param $style (string) Style of rendering. See the getPathPaintOperator() function for more information.
11625 * @param $border_style (array) Border style of rectangle. Array with keys among the following:
11626 * <ul>
11627 * <li>all: Line style of all borders. Array like for SetLineStyle().</li>
11628 * <li>L, T, R, B or combinations: Line style of left, top, right or bottom border. Array like for SetLineStyle().</li>
11629 * </ul>
11630 * If a key is not present or is null, the correspondent border is not drawn. Default value: default line style (empty array).
11631 * @param $fill_color (array) Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K) or array(C,M,Y,K,SpotColorName). Default value: default color (empty array).
11632 * @public
11633 * @since 1.0
11634 * @see SetLineStyle()
11635 */
11636 public function Rect($x, $y, $w, $h, $style='', $border_style=array(), $fill_color=array()) {
11637 if ($this->state != 2) {
11638 return;
11639 }
11640 if (empty($style)) {
11641 $style = 'S';
11642 }
11643 if (!(strpos($style, 'F') === false) AND !empty($fill_color)) {
11644 // set background color
11645 $this->SetFillColorArray($fill_color);
11646 }
11647 if (!empty($border_style)) {
11648 if (isset($border_style['all']) AND !empty($border_style['all'])) {
11649 //set global style for border
11650 $this->SetLineStyle($border_style['all']);
11651 $border_style = array();
11652 } else {
11653 // remove stroke operator from style
11654 $opnostroke = array('S' => '', 'D' => '', 's' => '', 'd' => '', 'B' => 'F', 'FD' => 'F', 'DF' => 'F', 'B*' => 'F*', 'F*D' => 'F*', 'DF*' => 'F*', 'b' => 'f', 'fd' => 'f', 'df' => 'f', 'b*' => 'f*', 'f*d' => 'f*', 'df*' => 'f*' );
11655 if (isset($opnostroke[$style])) {
11656 $style = $opnostroke[$style];
11657 }
11658 }
11659 }
11660 if (!empty($style)) {
11661 $op = TCPDF_STATIC::getPathPaintOperator($style);
11662 $this->_outRect($x, $y, $w, $h, $op);
11663 }
11664 if (!empty($border_style)) {
11665 $border_style2 = array();
11666 foreach ($border_style as $line => $value) {
11667 $length = strlen($line);
11668 for ($i = 0; $i < $length; ++$i) {
11669 $border_style2[$line[$i]] = $value;
11670 }
11671 }
11672 $border_style = $border_style2;
11673 if (isset($border_style['L']) AND $border_style['L']) {
11674 $this->Line($x, $y, $x, $y + $h, $border_style['L']);
11675 }
11676 if (isset($border_style['T']) AND $border_style['T']) {
11677 $this->Line($x, $y, $x + $w, $y, $border_style['T']);
11678 }
11679 if (isset($border_style['R']) AND $border_style['R']) {
11680 $this->Line($x + $w, $y, $x + $w, $y + $h, $border_style['R']);
11681 }
11682 if (isset($border_style['B']) AND $border_style['B']) {
11683 $this->Line($x, $y + $h, $x + $w, $y + $h, $border_style['B']);
11684 }
11685 }
11686 }
11687
11688 /**
11689 * Draws a Bezier curve.
11690 * The Bezier curve is a tangent to the line between the control points at
11691 * either end of the curve.
11692 * @param $x0 (float) Abscissa of start point.
11693 * @param $y0 (float) Ordinate of start point.
11694 * @param $x1 (float) Abscissa of control point 1.
11695 * @param $y1 (float) Ordinate of control point 1.
11696 * @param $x2 (float) Abscissa of control point 2.
11697 * @param $y2 (float) Ordinate of control point 2.
11698 * @param $x3 (float) Abscissa of end point.
11699 * @param $y3 (float) Ordinate of end point.
11700 * @param $style (string) Style of rendering. See the getPathPaintOperator() function for more information.
11701 * @param $line_style (array) Line style of curve. Array like for SetLineStyle(). Default value: default line style (empty array).
11702 * @param $fill_color (array) Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K) or array(C,M,Y,K,SpotColorName). Default value: default color (empty array).
11703 * @public
11704 * @see SetLineStyle()
11705 * @since 2.1.000 (2008-01-08)
11706 */
11707 public function Curve($x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3, $style='', $line_style=array(), $fill_color=array()) {
11708 if ($this->state != 2) {
11709 return;
11710 }
11711 if (!(false === strpos($style, 'F')) AND isset($fill_color)) {
11712 $this->SetFillColorArray($fill_color);
11713 }
11714 $op = TCPDF_STATIC::getPathPaintOperator($style);
11715 if ($line_style) {
11716 $this->SetLineStyle($line_style);
11717 }
11718 $this->_outPoint($x0, $y0);
11719 $this->_outCurve($x1, $y1, $x2, $y2, $x3, $y3);
11720 $this->_out($op);
11721 }
11722
11723 /**
11724 * Draws a poly-Bezier curve.
11725 * Each Bezier curve segment is a tangent to the line between the control points at
11726 * either end of the curve.
11727 * @param $x0 (float) Abscissa of start point.
11728 * @param $y0 (float) Ordinate of start point.
11729 * @param $segments (float) An array of bezier descriptions. Format: array(x1, y1, x2, y2, x3, y3).
11730 * @param $style (string) Style of rendering. See the getPathPaintOperator() function for more information.
11731 * @param $line_style (array) Line style of curve. Array like for SetLineStyle(). Default value: default line style (empty array).
11732 * @param $fill_color (array) Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K) or array(C,M,Y,K,SpotColorName). Default value: default color (empty array).
11733 * @public
11734 * @see SetLineStyle()
11735 * @since 3.0008 (2008-05-12)
11736 */
11737 public function Polycurve($x0, $y0, $segments, $style='', $line_style=array(), $fill_color=array()) {
11738 if ($this->state != 2) {
11739 return;
11740 }
11741 if (!(false === strpos($style, 'F')) AND isset($fill_color)) {
11742 $this->SetFillColorArray($fill_color);
11743 }
11744 $op = TCPDF_STATIC::getPathPaintOperator($style);
11745 if ($op == 'f') {
11746 $line_style = array();
11747 }
11748 if ($line_style) {
11749 $this->SetLineStyle($line_style);
11750 }
11751 $this->_outPoint($x0, $y0);
11752 foreach ($segments as $segment) {
11753 list($x1, $y1, $x2, $y2, $x3, $y3) = $segment;
11754 $this->_outCurve($x1, $y1, $x2, $y2, $x3, $y3);
11755 }
11756 $this->_out($op);
11757 }
11758
11759 /**
11760 * Draws an ellipse.
11761 * An ellipse is formed from n Bezier curves.
11762 * @param $x0 (float) Abscissa of center point.
11763 * @param $y0 (float) Ordinate of center point.
11764 * @param $rx (float) Horizontal radius.
11765 * @param $ry (float) Vertical radius (if ry = 0 then is a circle, see Circle()). Default value: 0.
11766 * @param $angle: (float) Angle oriented (anti-clockwise). Default value: 0.
11767 * @param $astart: (float) Angle start of draw line. Default value: 0.
11768 * @param $afinish: (float) Angle finish of draw line. Default value: 360.
11769 * @param $style (string) Style of rendering. See the getPathPaintOperator() function for more information.
11770 * @param $line_style (array) Line style of ellipse. Array like for SetLineStyle(). Default value: default line style (empty array).
11771 * @param $fill_color (array) Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K) or array(C,M,Y,K,SpotColorName). Default value: default color (empty array).
11772 * @param $nc (integer) Number of curves used to draw a 90 degrees portion of ellipse.
11773 * @author Nicola Asuni
11774 * @public
11775 * @since 2.1.000 (2008-01-08)
11776 */
11777 public function Ellipse($x0, $y0, $rx, $ry='', $angle=0, $astart=0, $afinish=360, $style='', $line_style=array(), $fill_color=array(), $nc=2) {
11778 if ($this->state != 2) {
11779 return;
11780 }
11781 if (TCPDF_STATIC::empty_string($ry) OR ($ry == 0)) {
11782 $ry = $rx;
11783 }
11784 if (!(false === strpos($style, 'F')) AND isset($fill_color)) {
11785 $this->SetFillColorArray($fill_color);
11786 }
11787 $op = TCPDF_STATIC::getPathPaintOperator($style);
11788 if ($op == 'f') {
11789 $line_style = array();
11790 }
11791 if ($line_style) {
11792 $this->SetLineStyle($line_style);
11793 }
11794 $this->_outellipticalarc($x0, $y0, $rx, $ry, $angle, $astart, $afinish, false, $nc, true, true, false);
11795 $this->_out($op);
11796 }
11797
11798 /**
11799 * Append an elliptical arc to the current path.
11800 * An ellipse is formed from n Bezier curves.
11801 * @param $xc (float) Abscissa of center point.
11802 * @param $yc (float) Ordinate of center point.
11803 * @param $rx (float) Horizontal radius.
11804 * @param $ry (float) Vertical radius (if ry = 0 then is a circle, see Circle()). Default value: 0.
11805 * @param $xang: (float) Angle between the X-axis and the major axis of the ellipse. Default value: 0.
11806 * @param $angs: (float) Angle start of draw line. Default value: 0.
11807 * @param $angf: (float) Angle finish of draw line. Default value: 360.
11808 * @param $pie (boolean) if true do not mark the border point (used to draw pie sectors).
11809 * @param $nc (integer) Number of curves used to draw a 90 degrees portion of ellipse.
11810 * @param $startpoint (boolean) if true output a starting point.
11811 * @param $ccw (boolean) if true draws in counter-clockwise.
11812 * @param $svg (boolean) if true the angles are in svg mode (already calculated).
11813 * @return array bounding box coordinates (x min, y min, x max, y max)
11814 * @author Nicola Asuni
11815 * @protected
11816 * @since 4.9.019 (2010-04-26)
11817 */
11818 protected function _outellipticalarc($xc, $yc, $rx, $ry, $xang=0, $angs=0, $angf=360, $pie=false, $nc=2, $startpoint=true, $ccw=true, $svg=false) {
11819 if (($rx <= 0) OR ($ry < 0)) {
11820 return;
11821 }
11822 $k = $this->k;
11823 if ($nc < 2) {
11824 $nc = 2;
11825 }
11826 $xmin = 2147483647;
11827 $ymin = 2147483647;
11828 $xmax = 0;
11829 $ymax = 0;
11830 if ($pie) {
11831 // center of the arc
11832 $this->_outPoint($xc, $yc);
11833 }
11834 $xang = deg2rad((float) $xang);
11835 $angs = deg2rad((float) $angs);
11836 $angf = deg2rad((float) $angf);
11837 if ($svg) {
11838 $as = $angs;
11839 $af = $angf;
11840 } else {
11841 $as = atan2((sin($angs) / $ry), (cos($angs) / $rx));
11842 $af = atan2((sin($angf) / $ry), (cos($angf) / $rx));
11843 }
11844 if ($as < 0) {
11845 $as += (2 * M_PI);
11846 }
11847 if ($af < 0) {
11848 $af += (2 * M_PI);
11849 }
11850 if ($ccw AND ($as > $af)) {
11851 // reverse rotation
11852 $as -= (2 * M_PI);
11853 } elseif (!$ccw AND ($as < $af)) {
11854 // reverse rotation
11855 $af -= (2 * M_PI);
11856 }
11857 $total_angle = ($af - $as);
11858 if ($nc < 2) {
11859 $nc = 2;
11860 }
11861 // total arcs to draw
11862 $nc *= (2 * abs($total_angle) / M_PI);
11863 $nc = round($nc) + 1;
11864 // angle of each arc
11865 $arcang = ($total_angle / $nc);
11866 // center point in PDF coordinates
11867 $x0 = $xc;
11868 $y0 = ($this->h - $yc);
11869 // starting angle
11870 $ang = $as;
11871 $alpha = sin($arcang) * ((sqrt(4 + (3 * pow(tan(($arcang) / 2), 2))) - 1) / 3);
11872 $cos_xang = cos($xang);
11873 $sin_xang = sin($xang);
11874 $cos_ang = cos($ang);
11875 $sin_ang = sin($ang);
11876 // first arc point
11877 $px1 = $x0 + ($rx * $cos_xang * $cos_ang) - ($ry * $sin_xang * $sin_ang);
11878 $py1 = $y0 + ($rx * $sin_xang * $cos_ang) + ($ry * $cos_xang * $sin_ang);
11879 // first Bezier control point
11880 $qx1 = ($alpha * ((-$rx * $cos_xang * $sin_ang) - ($ry * $sin_xang * $cos_ang)));
11881 $qy1 = ($alpha * ((-$rx * $sin_xang * $sin_ang) + ($ry * $cos_xang * $cos_ang)));
11882 if ($pie) {
11883 // line from center to arc starting point
11884 $this->_outLine($px1, $this->h - $py1);
11885 } elseif ($startpoint) {
11886 // arc starting point
11887 $this->_outPoint($px1, $this->h - $py1);
11888 }
11889 // draw arcs
11890 for ($i = 1; $i <= $nc; ++$i) {
11891 // starting angle
11892 $ang = $as + ($i * $arcang);
11893 if ($i == $nc) {
11894 $ang = $af;
11895 }
11896 $cos_ang = cos($ang);
11897 $sin_ang = sin($ang);
11898 // second arc point
11899 $px2 = $x0 + ($rx * $cos_xang * $cos_ang) - ($ry * $sin_xang * $sin_ang);
11900 $py2 = $y0 + ($rx * $sin_xang * $cos_ang) + ($ry * $cos_xang * $sin_ang);
11901 // second Bezier control point
11902 $qx2 = ($alpha * ((-$rx * $cos_xang * $sin_ang) - ($ry * $sin_xang * $cos_ang)));
11903 $qy2 = ($alpha * ((-$rx * $sin_xang * $sin_ang) + ($ry * $cos_xang * $cos_ang)));
11904 // draw arc
11905 $cx1 = ($px1 + $qx1);
11906 $cy1 = ($this->h - ($py1 + $qy1));
11907 $cx2 = ($px2 - $qx2);
11908 $cy2 = ($this->h - ($py2 - $qy2));
11909 $cx3 = $px2;
11910 $cy3 = ($this->h - $py2);
11911 $this->_outCurve($cx1, $cy1, $cx2, $cy2, $cx3, $cy3);
11912 // get bounding box coordinates
11913 $xmin = min($xmin, $cx1, $cx2, $cx3);
11914 $ymin = min($ymin, $cy1, $cy2, $cy3);
11915 $xmax = max($xmax, $cx1, $cx2, $cx3);
11916 $ymax = max($ymax, $cy1, $cy2, $cy3);
11917 // move to next point
11918 $px1 = $px2;
11919 $py1 = $py2;
11920 $qx1 = $qx2;
11921 $qy1 = $qy2;
11922 }
11923 if ($pie) {
11924 $this->_outLine($xc, $yc);
11925 // get bounding box coordinates
11926 $xmin = min($xmin, $xc);
11927 $ymin = min($ymin, $yc);
11928 $xmax = max($xmax, $xc);
11929 $ymax = max($ymax, $yc);
11930 }
11931 return array($xmin, $ymin, $xmax, $ymax);
11932 }
11933
11934 /**
11935 * Draws a circle.
11936 * A circle is formed from n Bezier curves.
11937 * @param $x0 (float) Abscissa of center point.
11938 * @param $y0 (float) Ordinate of center point.
11939 * @param $r (float) Radius.
11940 * @param $angstr: (float) Angle start of draw line. Default value: 0.
11941 * @param $angend: (float) Angle finish of draw line. Default value: 360.
11942 * @param $style (string) Style of rendering. See the getPathPaintOperator() function for more information.
11943 * @param $line_style (array) Line style of circle. Array like for SetLineStyle(). Default value: default line style (empty array).
11944 * @param $fill_color (array) Fill color. Format: array(red, green, blue). Default value: default color (empty array).
11945 * @param $nc (integer) Number of curves used to draw a 90 degrees portion of circle.
11946 * @public
11947 * @since 2.1.000 (2008-01-08)
11948 */
11949 public function Circle($x0, $y0, $r, $angstr=0, $angend=360, $style='', $line_style=array(), $fill_color=array(), $nc=2) {
11950 $this->Ellipse($x0, $y0, $r, $r, 0, $angstr, $angend, $style, $line_style, $fill_color, $nc);
11951 }
11952
11953 /**
11954 * Draws a polygonal line
11955 * @param $p (array) Points 0 to ($np - 1). Array with values (x0, y0, x1, y1,..., x(np-1), y(np - 1))
11956 * @param $style (string) Style of rendering. See the getPathPaintOperator() function for more information.
11957 * @param $line_style (array) Line style of polygon. Array with keys among the following:
11958 * <ul>
11959 * <li>all: Line style of all lines. Array like for SetLineStyle().</li>
11960 * <li>0 to ($np - 1): Line style of each line. Array like for SetLineStyle().</li>
11961 * </ul>
11962 * If a key is not present or is null, not draws the line. Default value is default line style (empty array).
11963 * @param $fill_color (array) Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K) or array(C,M,Y,K,SpotColorName). Default value: default color (empty array).
11964 * @since 4.8.003 (2009-09-15)
11965 * @public
11966 */
11967 public function PolyLine($p, $style='', $line_style=array(), $fill_color=array()) {
11968 $this->Polygon($p, $style, $line_style, $fill_color, false);
11969 }
11970
11971 /**
11972 * Draws a polygon.
11973 * @param $p (array) Points 0 to ($np - 1). Array with values (x0, y0, x1, y1,..., x(np-1), y(np - 1))
11974 * @param $style (string) Style of rendering. See the getPathPaintOperator() function for more information.
11975 * @param $line_style (array) Line style of polygon. Array with keys among the following:
11976 * <ul>
11977 * <li>all: Line style of all lines. Array like for SetLineStyle().</li>
11978 * <li>0 to ($np - 1): Line style of each line. Array like for SetLineStyle().</li>
11979 * </ul>
11980 * If a key is not present or is null, not draws the line. Default value is default line style (empty array).
11981 * @param $fill_color (array) Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K) or array(C,M,Y,K,SpotColorName). Default value: default color (empty array).
11982 * @param $closed (boolean) if true the polygon is closes, otherwise will remain open
11983 * @public
11984 * @since 2.1.000 (2008-01-08)
11985 */
11986 public function Polygon($p, $style='', $line_style=array(), $fill_color=array(), $closed=true) {
11987 if ($this->state != 2) {
11988 return;
11989 }
11990 $nc = count($p); // number of coordinates
11991 $np = $nc / 2; // number of points
11992 if ($closed) {
11993 // close polygon by adding the first 2 points at the end (one line)
11994 for ($i = 0; $i < 4; ++$i) {
11995 $p[$nc + $i] = $p[$i];
11996 }
11997 // copy style for the last added line
11998 if (isset($line_style[0])) {
11999 $line_style[$np] = $line_style[0];
12000 }
12001 $nc += 4;
12002 }
12003 if (!(false === strpos($style, 'F')) AND isset($fill_color)) {
12004 $this->SetFillColorArray($fill_color);
12005 }
12006 $op = TCPDF_STATIC::getPathPaintOperator($style);
12007 if ($op == 'f') {
12008 $line_style = array();
12009 }
12010 $draw = true;
12011 if ($line_style) {
12012 if (isset($line_style['all'])) {
12013 $this->SetLineStyle($line_style['all']);
12014 } else {
12015 $draw = false;
12016 if ($op == 'B') {
12017 // draw fill
12018 $op = 'f';
12019 $this->_outPoint($p[0], $p[1]);
12020 for ($i = 2; $i < $nc; $i = $i + 2) {
12021 $this->_outLine($p[$i], $p[$i + 1]);
12022 }
12023 $this->_out($op);
12024 }
12025 // draw outline
12026 $this->_outPoint($p[0], $p[1]);
12027 for ($i = 2; $i < $nc; $i = $i + 2) {
12028 $line_num = ($i / 2) - 1;
12029 if (isset($line_style[$line_num])) {
12030 if ($line_style[$line_num] != 0) {
12031 if (is_array($line_style[$line_num])) {
12032 $this->_out('S');
12033 $this->SetLineStyle($line_style[$line_num]);
12034 $this->_outPoint($p[$i - 2], $p[$i - 1]);
12035 $this->_outLine($p[$i], $p[$i + 1]);
12036 $this->_out('S');
12037 $this->_outPoint($p[$i], $p[$i + 1]);
12038 } else {
12039 $this->_outLine($p[$i], $p[$i + 1]);
12040 }
12041 }
12042 } else {
12043 $this->_outLine($p[$i], $p[$i + 1]);
12044 }
12045 }
12046 $this->_out($op);
12047 }
12048 }
12049 if ($draw) {
12050 $this->_outPoint($p[0], $p[1]);
12051 for ($i = 2; $i < $nc; $i = $i + 2) {
12052 $this->_outLine($p[$i], $p[$i + 1]);
12053 }
12054 $this->_out($op);
12055 }
12056 }
12057
12058 /**
12059 * Draws a regular polygon.
12060 * @param $x0 (float) Abscissa of center point.
12061 * @param $y0 (float) Ordinate of center point.
12062 * @param $r: (float) Radius of inscribed circle.
12063 * @param $ns (integer) Number of sides.
12064 * @param $angle (float) Angle oriented (anti-clockwise). Default value: 0.
12065 * @param $draw_circle (boolean) Draw inscribed circle or not. Default value: false.
12066 * @param $style (string) Style of rendering. See the getPathPaintOperator() function for more information.
12067 * @param $line_style (array) Line style of polygon sides. Array with keys among the following:
12068 * <ul>
12069 * <li>all: Line style of all sides. Array like for SetLineStyle().</li>
12070 * <li>0 to ($ns - 1): Line style of each side. Array like for SetLineStyle().</li>
12071 * </ul>
12072 * If a key is not present or is null, not draws the side. Default value is default line style (empty array).
12073 * @param $fill_color (array) Fill color. Format: array(red, green, blue). Default value: default color (empty array).
12074 * @param $circle_style (string) Style of rendering of inscribed circle (if draws). Possible values are:
12075 * <ul>
12076 * <li>D or empty string: Draw (default).</li>
12077 * <li>F: Fill.</li>
12078 * <li>DF or FD: Draw and fill.</li>
12079 * <li>CNZ: Clipping mode (using the even-odd rule to determine which regions lie inside the clipping path).</li>
12080 * <li>CEO: Clipping mode (using the nonzero winding number rule to determine which regions lie inside the clipping path).</li>
12081 * </ul>
12082 * @param $circle_outLine_style (array) Line style of inscribed circle (if draws). Array like for SetLineStyle(). Default value: default line style (empty array).
12083 * @param $circle_fill_color (array) Fill color of inscribed circle (if draws). Format: array(red, green, blue). Default value: default color (empty array).
12084 * @public
12085 * @since 2.1.000 (2008-01-08)
12086 */
12087 public function RegularPolygon($x0, $y0, $r, $ns, $angle=0, $draw_circle=false, $style='', $line_style=array(), $fill_color=array(), $circle_style='', $circle_outLine_style=array(), $circle_fill_color=array()) {
12088 if (3 > $ns) {
12089 $ns = 3;
12090 }
12091 if ($draw_circle) {
12092 $this->Circle($x0, $y0, $r, 0, 360, $circle_style, $circle_outLine_style, $circle_fill_color);
12093 }
12094 $p = array();
12095 for ($i = 0; $i < $ns; ++$i) {
12096 $a = $angle + ($i * 360 / $ns);
12097 $a_rad = deg2rad((float) $a);
12098 $p[] = $x0 + ($r * sin($a_rad));
12099 $p[] = $y0 + ($r * cos($a_rad));
12100 }
12101 $this->Polygon($p, $style, $line_style, $fill_color);
12102 }
12103
12104 /**
12105 * Draws a star polygon
12106 * @param $x0 (float) Abscissa of center point.
12107 * @param $y0 (float) Ordinate of center point.
12108 * @param $r (float) Radius of inscribed circle.
12109 * @param $nv (integer) Number of vertices.
12110 * @param $ng (integer) Number of gap (if ($ng % $nv = 1) then is a regular polygon).
12111 * @param $angle: (float) Angle oriented (anti-clockwise). Default value: 0.
12112 * @param $draw_circle: (boolean) Draw inscribed circle or not. Default value is false.
12113 * @param $style (string) Style of rendering. See the getPathPaintOperator() function for more information.
12114 * @param $line_style (array) Line style of polygon sides. Array with keys among the following:
12115 * <ul>
12116 * <li>all: Line style of all sides. Array like for
12117 * SetLineStyle().</li>
12118 * <li>0 to (n - 1): Line style of each side. Array like for SetLineStyle().</li>
12119 * </ul>
12120 * If a key is not present or is null, not draws the side. Default value is default line style (empty array).
12121 * @param $fill_color (array) Fill color. Format: array(red, green, blue). Default value: default color (empty array).
12122 * @param $circle_style (string) Style of rendering of inscribed circle (if draws). Possible values are:
12123 * <ul>
12124 * <li>D or empty string: Draw (default).</li>
12125 * <li>F: Fill.</li>
12126 * <li>DF or FD: Draw and fill.</li>
12127 * <li>CNZ: Clipping mode (using the even-odd rule to determine which regions lie inside the clipping path).</li>
12128 * <li>CEO: Clipping mode (using the nonzero winding number rule to determine which regions lie inside the clipping path).</li>
12129 * </ul>
12130 * @param $circle_outLine_style (array) Line style of inscribed circle (if draws). Array like for SetLineStyle(). Default value: default line style (empty array).
12131 * @param $circle_fill_color (array) Fill color of inscribed circle (if draws). Format: array(red, green, blue). Default value: default color (empty array).
12132 * @public
12133 * @since 2.1.000 (2008-01-08)
12134 */
12135 public function StarPolygon($x0, $y0, $r, $nv, $ng, $angle=0, $draw_circle=false, $style='', $line_style=array(), $fill_color=array(), $circle_style='', $circle_outLine_style=array(), $circle_fill_color=array()) {
12136 if ($nv < 2) {
12137 $nv = 2;
12138 }
12139 if ($draw_circle) {
12140 $this->Circle($x0, $y0, $r, 0, 360, $circle_style, $circle_outLine_style, $circle_fill_color);
12141 }
12142 $p2 = array();
12143 $visited = array();
12144 for ($i = 0; $i < $nv; ++$i) {
12145 $a = $angle + ($i * 360 / $nv);
12146 $a_rad = deg2rad((float) $a);
12147 $p2[] = $x0 + ($r * sin($a_rad));
12148 $p2[] = $y0 + ($r * cos($a_rad));
12149 $visited[] = false;
12150 }
12151 $p = array();
12152 $i = 0;
12153 do {
12154 $p[] = $p2[$i * 2];
12155 $p[] = $p2[($i * 2) + 1];
12156 $visited[$i] = true;
12157 $i += $ng;
12158 $i %= $nv;
12159 } while (!$visited[$i]);
12160 $this->Polygon($p, $style, $line_style, $fill_color);
12161 }
12162
12163 /**
12164 * Draws a rounded rectangle.
12165 * @param $x (float) Abscissa of upper-left corner.
12166 * @param $y (float) Ordinate of upper-left corner.
12167 * @param $w (float) Width.
12168 * @param $h (float) Height.
12169 * @param $r (float) the radius of the circle used to round off the corners of the rectangle.
12170 * @param $round_corner (string) Draws rounded corner or not. String with a 0 (not rounded i-corner) or 1 (rounded i-corner) in i-position. Positions are, in order and begin to 0: top right, bottom right, bottom left and top left. Default value: all rounded corner ("1111").
12171 * @param $style (string) Style of rendering. See the getPathPaintOperator() function for more information.
12172 * @param $border_style (array) Border style of rectangle. Array like for SetLineStyle(). Default value: default line style (empty array).
12173 * @param $fill_color (array) Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K) or array(C,M,Y,K,SpotColorName). Default value: default color (empty array).
12174 * @public
12175 * @since 2.1.000 (2008-01-08)
12176 */
12177 public function RoundedRect($x, $y, $w, $h, $r, $round_corner='1111', $style='', $border_style=array(), $fill_color=array()) {
12178 $this->RoundedRectXY($x, $y, $w, $h, $r, $r, $round_corner, $style, $border_style, $fill_color);
12179 }
12180
12181 /**
12182 * Draws a rounded rectangle.
12183 * @param $x (float) Abscissa of upper-left corner.
12184 * @param $y (float) Ordinate of upper-left corner.
12185 * @param $w (float) Width.
12186 * @param $h (float) Height.
12187 * @param $rx (float) the x-axis radius of the ellipse used to round off the corners of the rectangle.
12188 * @param $ry (float) the y-axis radius of the ellipse used to round off the corners of the rectangle.
12189 * @param $round_corner (string) Draws rounded corner or not. String with a 0 (not rounded i-corner) or 1 (rounded i-corner) in i-position. Positions are, in order and begin to 0: top right, bottom right, bottom left and top left. Default value: all rounded corner ("1111").
12190 * @param $style (string) Style of rendering. See the getPathPaintOperator() function for more information.
12191 * @param $border_style (array) Border style of rectangle. Array like for SetLineStyle(). Default value: default line style (empty array).
12192 * @param $fill_color (array) Fill color. Format: array(GREY) or array(R,G,B) or array(C,M,Y,K) or array(C,M,Y,K,SpotColorName). Default value: default color (empty array).
12193 * @public
12194 * @since 4.9.019 (2010-04-22)
12195 */
12196 public function RoundedRectXY($x, $y, $w, $h, $rx, $ry, $round_corner='1111', $style='', $border_style=array(), $fill_color=array()) {
12197 if ($this->state != 2) {
12198 return;
12199 }
12200 if (($round_corner == '0000') OR (($rx == $ry) AND ($rx == 0))) {
12201 // Not rounded
12202 $this->Rect($x, $y, $w, $h, $style, $border_style, $fill_color);
12203 return;
12204 }
12205 // Rounded
12206 if (!(false === strpos($style, 'F')) AND isset($fill_color)) {
12207 $this->SetFillColorArray($fill_color);
12208 }
12209 $op = TCPDF_STATIC::getPathPaintOperator($style);
12210 if ($op == 'f') {
12211 $border_style = array();
12212 }
12213 if ($border_style) {
12214 $this->SetLineStyle($border_style);
12215 }
12216 $MyArc = 4 / 3 * (sqrt(2) - 1);
12217 $this->_outPoint($x + $rx, $y);
12218 $xc = $x + $w - $rx;
12219 $yc = $y + $ry;
12220 $this->_outLine($xc, $y);
12221 if ($round_corner[0]) {
12222 $this->_outCurve($xc + ($rx * $MyArc), $yc - $ry, $xc + $rx, $yc - ($ry * $MyArc), $xc + $rx, $yc);
12223 } else {
12224 $this->_outLine($x + $w, $y);
12225 }
12226 $xc = $x + $w - $rx;
12227 $yc = $y + $h - $ry;
12228 $this->_outLine($x + $w, $yc);
12229 if ($round_corner[1]) {
12230 $this->_outCurve($xc + $rx, $yc + ($ry * $MyArc), $xc + ($rx * $MyArc), $yc + $ry, $xc, $yc + $ry);
12231 } else {
12232 $this->_outLine($x + $w, $y + $h);
12233 }
12234 $xc = $x + $rx;
12235 $yc = $y + $h - $ry;
12236 $this->_outLine($xc, $y + $h);
12237 if ($round_corner[2]) {
12238 $this->_outCurve($xc - ($rx * $MyArc), $yc + $ry, $xc - $rx, $yc + ($ry * $MyArc), $xc - $rx, $yc);
12239 } else {
12240 $this->_outLine($x, $y + $h);
12241 }
12242 $xc = $x + $rx;
12243 $yc = $y + $ry;
12244 $this->_outLine($x, $yc);
12245 if ($round_corner[3]) {
12246 $this->_outCurve($xc - $rx, $yc - ($ry * $MyArc), $xc - ($rx * $MyArc), $yc - $ry, $xc, $yc - $ry);
12247 } else {
12248 $this->_outLine($x, $y);
12249 $this->_outLine($x + $rx, $y);
12250 }
12251 $this->_out($op);
12252 }
12253
12254 /**
12255 * Draws a grahic arrow.
12256 * @param $x0 (float) Abscissa of first point.
12257 * @param $y0 (float) Ordinate of first point.
12258 * @param $x1 (float) Abscissa of second point.
12259 * @param $y1 (float) Ordinate of second point.
12260 * @param $head_style (int) (0 = draw only arrowhead arms, 1 = draw closed arrowhead, but no fill, 2 = closed and filled arrowhead, 3 = filled arrowhead)
12261 * @param $arm_size (float) length of arrowhead arms
12262 * @param $arm_angle (int) angle between an arm and the shaft
12263 * @author Piotr Galecki, Nicola Asuni, Andy Meier
12264 * @since 4.6.018 (2009-07-10)
12265 */
12266 public function Arrow($x0, $y0, $x1, $y1, $head_style=0, $arm_size=5, $arm_angle=15) {
12267 // getting arrow direction angle
12268 // 0 deg angle is when both arms go along X axis. angle grows clockwise.
12269 $dir_angle = atan2(($y0 - $y1), ($x0 - $x1));
12270 if ($dir_angle < 0) {
12271 $dir_angle += (2 * M_PI);
12272 }
12273 $arm_angle = deg2rad($arm_angle);
12274 $sx1 = $x1;
12275 $sy1 = $y1;
12276 if ($head_style > 0) {
12277 // calculate the stopping point for the arrow shaft
12278 $sx1 = $x1 + (($arm_size - $this->LineWidth) * cos($dir_angle));
12279 $sy1 = $y1 + (($arm_size - $this->LineWidth) * sin($dir_angle));
12280 }
12281 // main arrow line / shaft
12282 $this->Line($x0, $y0, $sx1, $sy1);
12283 // left arrowhead arm tip
12284 $x2L = $x1 + ($arm_size * cos($dir_angle + $arm_angle));
12285 $y2L = $y1 + ($arm_size * sin($dir_angle + $arm_angle));
12286 // right arrowhead arm tip
12287 $x2R = $x1 + ($arm_size * cos($dir_angle - $arm_angle));
12288 $y2R = $y1 + ($arm_size * sin($dir_angle - $arm_angle));
12289 $mode = 'D';
12290 $style = array();
12291 switch ($head_style) {
12292 case 0: {
12293 // draw only arrowhead arms
12294 $mode = 'D';
12295 $style = array(1, 1, 0);
12296 break;
12297 }
12298 case 1: {
12299 // draw closed arrowhead, but no fill
12300 $mode = 'D';
12301 break;
12302 }
12303 case 2: {
12304 // closed and filled arrowhead
12305 $mode = 'DF';
12306 break;
12307 }
12308 case 3: {
12309 // filled arrowhead
12310 $mode = 'F';
12311 break;
12312 }
12313 }
12314 $this->Polygon(array($x2L, $y2L, $x1, $y1, $x2R, $y2R), $mode, $style, array());
12315 }
12316
12317 // END GRAPHIC FUNCTIONS SECTION -----------------------
12318
12319 /**
12320 * Add a Named Destination.
12321 * NOTE: destination names are unique, so only last entry will be saved.
12322 * @param $name (string) Destination name.
12323 * @param $y (float) Y position in user units of the destiantion on the selected page (default = -1 = current position; 0 = page start;).
12324 * @param $page (int|string) Target page number (leave empty for current page). If you prefix a page number with the * character, then this page will not be changed when adding/deleting/moving pages.
12325 * @param $x (float) X position in user units of the destiantion on the selected page (default = -1 = current position;).
12326 * @return (string) Stripped named destination identifier or false in case of error.
12327 * @public
12328 * @author Christian Deligant, Nicola Asuni
12329 * @since 5.9.097 (2011-06-23)
12330 */
12331 public function setDestination($name, $y=-1, $page='', $x=-1) {
12332 // remove unsupported characters
12333 $name = TCPDF_STATIC::encodeNameObject($name);
12334 if (TCPDF_STATIC::empty_string($name)) {
12335 return false;
12336 }
12337 if ($y == -1) {
12338 $y = $this->GetY();
12339 } elseif ($y < 0) {
12340 $y = 0;
12341 } elseif ($y > $this->h) {
12342 $y = $this->h;
12343 }
12344 if ($x == -1) {
12345 $x = $this->GetX();
12346 } elseif ($x < 0) {
12347 $x = 0;
12348 } elseif ($x > $this->w) {
12349 $x = $this->w;
12350 }
12351 $fixed = false;
12352 if (!empty($page) AND ($page[0] == '*')) {
12353 $page = intval(substr($page, 1));
12354 // this page number will not be changed when moving/add/deleting pages
12355 $fixed = true;
12356 }
12357 if (empty($page)) {
12358 $page = $this->PageNo();
12359 if (empty($page)) {
12360 return;
12361 }
12362 }
12363 $this->dests[$name] = array('x' => $x, 'y' => $y, 'p' => $page, 'f' => $fixed);
12364 return $name;
12365 }
12366
12367 /**
12368 * Return the Named Destination array.
12369 * @return (array) Named Destination array.
12370 * @public
12371 * @author Nicola Asuni
12372 * @since 5.9.097 (2011-06-23)
12373 */
12374 public function getDestination() {
12375 return $this->dests;
12376 }
12377
12378 /**
12379 * Insert Named Destinations.
12380 * @protected
12381 * @author Johannes G\FCntert, Nicola Asuni
12382 * @since 5.9.098 (2011-06-23)
12383 */
12384 protected function _putdests() {
12385 if (empty($this->dests)) {
12386 return;
12387 }
12388 $this->n_dests = $this->_newobj();
12389 $out = ' <<';
12390 foreach($this->dests as $name => $o) {
12391 $out .= ' /'.$name.' '.sprintf('[%u 0 R /XYZ %F %F null]', $this->page_obj_id[($o['p'])], ($o['x'] * $this->k), ($this->pagedim[$o['p']]['h'] - ($o['y'] * $this->k)));
12392 }
12393 $out .= ' >>';
12394 $out .= "\n".'endobj';
12395 $this->_out($out);
12396 }
12397
12398 /**
12399 * Adds a bookmark - alias for Bookmark().
12400 * @param $txt (string) Bookmark description.
12401 * @param $level (int) Bookmark level (minimum value is 0).
12402 * @param $y (float) Y position in user units of the bookmark on the selected page (default = -1 = current position; 0 = page start;).
12403 * @param $page (int|string) Target page number (leave empty for current page). If you prefix a page number with the * character, then this page will not be changed when adding/deleting/moving pages.
12404 * @param $style (string) Font style: B = Bold, I = Italic, BI = Bold + Italic.
12405 * @param $color (array) RGB color array (values from 0 to 255).
12406 * @param $x (float) X position in user units of the bookmark on the selected page (default = -1 = current position;).
12407 * @param $link (mixed) URL, or numerical link ID, or named destination (# character followed by the destination name), or embedded file (* character followed by the file name).
12408 * @public
12409 */
12410 public function setBookmark($txt, $level=0, $y=-1, $page='', $style='', $color=array(0,0,0), $x=-1, $link='') {
12411 $this->Bookmark($txt, $level, $y, $page, $style, $color, $x, $link);
12412 }
12413
12414 /**
12415 * Adds a bookmark.
12416 * @param $txt (string) Bookmark description.
12417 * @param $level (int) Bookmark level (minimum value is 0).
12418 * @param $y (float) Y position in user units of the bookmark on the selected page (default = -1 = current position; 0 = page start;).
12419 * @param $page (int|string) Target page number (leave empty for current page). If you prefix a page number with the * character, then this page will not be changed when adding/deleting/moving pages.
12420 * @param $style (string) Font style: B = Bold, I = Italic, BI = Bold + Italic.
12421 * @param $color (array) RGB color array (values from 0 to 255).
12422 * @param $x (float) X position in user units of the bookmark on the selected page (default = -1 = current position;).
12423 * @param $link (mixed) URL, or numerical link ID, or named destination (# character followed by the destination name), or embedded file (* character followed by the file name).
12424 * @public
12425 * @since 2.1.002 (2008-02-12)
12426 */
12427 public function Bookmark($txt, $level=0, $y=-1, $page='', $style='', $color=array(0,0,0), $x=-1, $link='') {
12428 if ($level < 0) {
12429 $level = 0;
12430 }
12431 if (isset($this->outlines[0])) {
12432 $lastoutline = end($this->outlines);
12433 $maxlevel = $lastoutline['l'] + 1;
12434 } else {
12435 $maxlevel = 0;
12436 }
12437 if ($level > $maxlevel) {
12438 $level = $maxlevel;
12439 }
12440 if ($y == -1) {
12441 $y = $this->GetY();
12442 } elseif ($y < 0) {
12443 $y = 0;
12444 } elseif ($y > $this->h) {
12445 $y = $this->h;
12446 }
12447 if ($x == -1) {
12448 $x = $this->GetX();
12449 } elseif ($x < 0) {
12450 $x = 0;
12451 } elseif ($x > $this->w) {
12452 $x = $this->w;
12453 }
12454 $fixed = false;
12455 if (!empty($page) AND ($page[0] == '*')) {
12456 $page = intval(substr($page, 1));
12457 // this page number will not be changed when moving/add/deleting pages
12458 $fixed = true;
12459 }
12460 if (empty($page)) {
12461 $page = $this->PageNo();
12462 if (empty($page)) {
12463 return;
12464 }
12465 }
12466 $this->outlines[] = array('t' => $txt, 'l' => $level, 'x' => $x, 'y' => $y, 'p' => $page, 'f' => $fixed, 's' => strtoupper($style), 'c' => $color, 'u' => $link);
12467 }
12468
12469 /**
12470 * Sort bookmarks for page and key.
12471 * @protected
12472 * @since 5.9.119 (2011-09-19)
12473 */
12474 protected function sortBookmarks() {
12475 // get sorting columns
12476 $outline_p = array();
12477 $outline_y = array();
12478 foreach ($this->outlines as $key => $row) {
12479 $outline_p[$key] = $row['p'];
12480 $outline_k[$key] = $key;
12481 }
12482 // sort outlines by page and original position
12483 array_multisort($outline_p, SORT_NUMERIC, SORT_ASC, $outline_k, SORT_NUMERIC, SORT_ASC, $this->outlines);
12484 }
12485
12486 /**
12487 * Create a bookmark PDF string.
12488 * @protected
12489 * @author Olivier Plathey, Nicola Asuni
12490 * @since 2.1.002 (2008-02-12)
12491 */
12492 protected function _putbookmarks() {
12493 $nb = count($this->outlines);
12494 if ($nb == 0) {
12495 return;
12496 }
12497 // sort bookmarks
12498 $this->sortBookmarks();
12499 $lru = array();
12500 $level = 0;
12501 foreach ($this->outlines as $i => $o) {
12502 if ($o['l'] > 0) {
12503 $parent = $lru[($o['l'] - 1)];
12504 //Set parent and last pointers
12505 $this->outlines[$i]['parent'] = $parent;
12506 $this->outlines[$parent]['last'] = $i;
12507 if ($o['l'] > $level) {
12508 //Level increasing: set first pointer
12509 $this->outlines[$parent]['first'] = $i;
12510 }
12511 } else {
12512 $this->outlines[$i]['parent'] = $nb;
12513 }
12514 if (($o['l'] <= $level) AND ($i > 0)) {
12515 //Set prev and next pointers
12516 $prev = $lru[$o['l']];
12517 $this->outlines[$prev]['next'] = $i;
12518 $this->outlines[$i]['prev'] = $prev;
12519 }
12520 $lru[$o['l']] = $i;
12521 $level = $o['l'];
12522 }
12523 //Outline items
12524 $n = $this->n + 1;
12525 $nltags = '/<br[\s]?\/>|<\/(blockquote|dd|dl|div|dt|h1|h2|h3|h4|h5|h6|hr|li|ol|p|pre|ul|tcpdf|table|tr|td)>/si';
12526 foreach ($this->outlines as $i => $o) {
12527 $oid = $this->_newobj();
12528 // covert HTML title to string
12529 $title = preg_replace($nltags, "\n", $o['t']);
12530 $title = preg_replace("/[\r]+/si", '', $title);
12531 $title = preg_replace("/[\n]+/si", "\n", $title);
12532 $title = strip_tags($title);
12533 $title = $this->stringTrim($title);
12534 $out = '<</Title '.$this->_textstring($title, $oid);
12535 $out .= ' /Parent '.($n + $o['parent']).' 0 R';
12536 if (isset($o['prev'])) {
12537 $out .= ' /Prev '.($n + $o['prev']).' 0 R';
12538 }
12539 if (isset($o['next'])) {
12540 $out .= ' /Next '.($n + $o['next']).' 0 R';
12541 }
12542 if (isset($o['first'])) {
12543 $out .= ' /First '.($n + $o['first']).' 0 R';
12544 }
12545 if (isset($o['last'])) {
12546 $out .= ' /Last '.($n + $o['last']).' 0 R';
12547 }
12548 if (isset($o['u']) AND !empty($o['u'])) {
12549 // link
12550 if (is_string($o['u'])) {
12551 if ($o['u'][0] == '#') {
12552 // internal destination
12553 $out .= ' /Dest /'.TCPDF_STATIC::encodeNameObject(substr($o['u'], 1));
12554 } elseif ($o['u'][0] == '%') {
12555 // embedded PDF file
12556 $filename = basename(substr($o['u'], 1));
12557 $out .= ' /A <</S /GoToE /D [0 /Fit] /NewWindow true /T << /R /C /P '.($o['p'] - 1).' /A '.$this->embeddedfiles[$filename]['a'].' >> >>';
12558 } elseif ($o['u'][0] == '*') {
12559 // embedded generic file
12560 $filename = basename(substr($o['u'], 1));
12561 $jsa = 'var D=event.target.doc;var MyData=D.dataObjects;for (var i in MyData) if (MyData[i].path=="'.$filename.'") D.exportDataObject( { cName : MyData[i].name, nLaunch : 2});';
12562 $out .= ' /A <</S /JavaScript /JS '.$this->_textstring($jsa, $oid).'>>';
12563 } else {
12564 // external URI link
12565 $out .= ' /A <</S /URI /URI '.$this->_datastring($this->unhtmlentities($o['u']), $oid).'>>';
12566 }
12567 } elseif (isset($this->links[$o['u']])) {
12568 // internal link ID
12569 $l = $this->links[$o['u']];
12570 if (isset($this->page_obj_id[($l['p'])])) {
12571 $out .= sprintf(' /Dest [%u 0 R /XYZ 0 %F null]', $this->page_obj_id[($l['p'])], ($this->pagedim[$l['p']]['h'] - ($l['y'] * $this->k)));
12572 }
12573 }
12574 } elseif (isset($this->page_obj_id[($o['p'])])) {
12575 // link to a page
12576 $out .= ' '.sprintf('/Dest [%u 0 R /XYZ %F %F null]', $this->page_obj_id[($o['p'])], ($o['x'] * $this->k), ($this->pagedim[$o['p']]['h'] - ($o['y'] * $this->k)));
12577 }
12578 // set font style
12579 $style = 0;
12580 if (!empty($o['s'])) {
12581 // bold
12582 if (strpos($o['s'], 'B') !== false) {
12583 $style |= 2;
12584 }
12585 // oblique
12586 if (strpos($o['s'], 'I') !== false) {
12587 $style |= 1;
12588 }
12589 }
12590 $out .= sprintf(' /F %d', $style);
12591 // set bookmark color
12592 if (isset($o['c']) AND is_array($o['c']) AND (count($o['c']) == 3)) {
12593 $color = array_values($o['c']);
12594 $out .= sprintf(' /C [%F %F %F]', ($color[0] / 255), ($color[1] / 255), ($color[2] / 255));
12595 } else {
12596 // black
12597 $out .= ' /C [0.0 0.0 0.0]';
12598 }
12599 $out .= ' /Count 0'; // normally closed item
12600 $out .= ' >>';
12601 $out .= "\n".'endobj';
12602 $this->_out($out);
12603 }
12604 //Outline root
12605 $this->OutlineRoot = $this->_newobj();
12606 $this->_out('<< /Type /Outlines /First '.$n.' 0 R /Last '.($n + $lru[0]).' 0 R >>'."\n".'endobj');
12607 }
12608
12609 // --- JAVASCRIPT ------------------------------------------------------
12610
12611 /**
12612 * Adds a javascript
12613 * @param $script (string) Javascript code
12614 * @public
12615 * @author Johannes G\FCntert, Nicola Asuni
12616 * @since 2.1.002 (2008-02-12)
12617 */
12618 public function IncludeJS($script) {
12619 $this->javascript .= $script;
12620 }
12621
12622 /**
12623 * Adds a javascript object and return object ID
12624 * @param $script (string) Javascript code
12625 * @param $onload (boolean) if true executes this object when opening the document
12626 * @return int internal object ID
12627 * @public
12628 * @author Nicola Asuni
12629 * @since 4.8.000 (2009-09-07)
12630 */
12631 public function addJavascriptObject($script, $onload=false) {
12632 if ($this->pdfa_mode) {
12633 // javascript is not allowed in PDF/A mode
12634 return false;
12635 }
12636 ++$this->n;
12637 $this->js_objects[$this->n] = array('n' => $this->n, 'js' => $script, 'onload' => $onload);
12638 return $this->n;
12639 }
12640
12641 /**
12642 * Create a javascript PDF string.
12643 * @protected
12644 * @author Johannes G\FCntert, Nicola Asuni
12645 * @since 2.1.002 (2008-02-12)
12646 */
12647 protected function _putjavascript() {
12648 if ($this->pdfa_mode OR (empty($this->javascript) AND empty($this->js_objects))) {
12649 return;
12650 }
12651 if (strpos($this->javascript, 'this.addField') > 0) {
12652 if (!$this->ur['enabled']) {
12653 //$this->setUserRights();
12654 }
12655 // the following two lines are used to avoid form fields duplication after saving
12656 // The addField method only works when releasing user rights (UR3)
12657 $jsa = sprintf("ftcpdfdocsaved=this.addField('%s','%s',%d,[%F,%F,%F,%F]);", 'tcpdfdocsaved', 'text', 0, 0, 1, 0, 1);
12658 $jsb = "getField('tcpdfdocsaved').value='saved';";
12659 $this->javascript = $jsa."\n".$this->javascript."\n".$jsb;
12660 }
12661 // name tree for javascript
12662 $this->n_js = '<< /Names [';
12663 if (!empty($this->javascript)) {
12664 $this->n_js .= ' (EmbeddedJS) '.($this->n + 1).' 0 R';
12665 }
12666 if (!empty($this->js_objects)) {
12667 foreach ($this->js_objects as $key => $val) {
12668 if ($val['onload']) {
12669 $this->n_js .= ' (JS'.$key.') '.$key.' 0 R';
12670 }
12671 }
12672 }
12673 $this->n_js .= ' ] >>';
12674 // default Javascript object
12675 if (!empty($this->javascript)) {
12676 $obj_id = $this->_newobj();
12677 $out = '<< /S /JavaScript';
12678 $out .= ' /JS '.$this->_textstring($this->javascript, $obj_id);
12679 $out .= ' >>';
12680 $out .= "\n".'endobj';
12681 $this->_out($out);
12682 }
12683 // additional Javascript objects
12684 if (!empty($this->js_objects)) {
12685 foreach ($this->js_objects as $key => $val) {
12686 $out = $this->_getobj($key)."\n".' << /S /JavaScript /JS '.$this->_textstring($val['js'], $key).' >>'."\n".'endobj';
12687 $this->_out($out);
12688 }
12689 }
12690 }
12691
12692 /**
12693 * Adds a javascript form field.
12694 * @param $type (string) field type
12695 * @param $name (string) field name
12696 * @param $x (int) horizontal position
12697 * @param $y (int) vertical position
12698 * @param $w (int) width
12699 * @param $h (int) height
12700 * @param $prop (array) javascript field properties. Possible values are described on official Javascript for Acrobat API reference.
12701 * @protected
12702 * @author Denis Van Nuffelen, Nicola Asuni
12703 * @since 2.1.002 (2008-02-12)
12704 */
12705 protected function _addfield($type, $name, $x, $y, $w, $h, $prop) {
12706 if ($this->rtl) {
12707 $x = $x - $w;
12708 }
12709 // the followind avoid fields duplication after saving the document
12710 $this->javascript .= "if (getField('tcpdfdocsaved').value != 'saved') {";
12711 $k = $this->k;
12712 $this->javascript .= sprintf("f".$name."=this.addField('%s','%s',%u,[%F,%F,%F,%F]);", $name, $type, $this->PageNo()-1, $x*$k, ($this->h-$y)*$k+1, ($x+$w)*$k, ($this->h-$y-$h)*$k+1)."\n";
12713 $this->javascript .= 'f'.$name.'.textSize='.$this->FontSizePt.";\n";
12714 while (list($key, $val) = each($prop)) {
12715 if (strcmp(substr($key, -5), 'Color') == 0) {
12716 $val = TCPDF_COLORS::_JScolor($val);
12717 } else {
12718 $val = "'".$val."'";
12719 }
12720 $this->javascript .= 'f'.$name.'.'.$key.'='.$val.";\n";
12721 }
12722 if ($this->rtl) {
12723 $this->x -= $w;
12724 } else {
12725 $this->x += $w;
12726 }
12727 $this->javascript .= '}';
12728 }
12729
12730 // --- FORM FIELDS -----------------------------------------------------
12731
12732
12733
12734 /**
12735 * Set default properties for form fields.
12736 * @param $prop (array) javascript field properties. Possible values are described on official Javascript for Acrobat API reference.
12737 * @public
12738 * @author Nicola Asuni
12739 * @since 4.8.000 (2009-09-06)
12740 */
12741 public function setFormDefaultProp($prop=array()) {
12742 $this->default_form_prop = $prop;
12743 }
12744
12745 /**
12746 * Return the default properties for form fields.
12747 * @return array $prop javascript field properties. Possible values are described on official Javascript for Acrobat API reference.
12748 * @public
12749 * @author Nicola Asuni
12750 * @since 4.8.000 (2009-09-06)
12751 */
12752 public function getFormDefaultProp() {
12753 return $this->default_form_prop;
12754 }
12755
12756 /**
12757 * Creates a text field
12758 * @param $name (string) field name
12759 * @param $w (float) Width of the rectangle
12760 * @param $h (float) Height of the rectangle
12761 * @param $prop (array) javascript field properties. Possible values are described on official Javascript for Acrobat API reference.
12762 * @param $opt (array) annotation parameters. Possible values are described on official PDF32000_2008 reference.
12763 * @param $x (float) Abscissa of the upper-left corner of the rectangle
12764 * @param $y (float) Ordinate of the upper-left corner of the rectangle
12765 * @param $js (boolean) if true put the field using JavaScript (requires Acrobat Writer to be rendered).
12766 * @public
12767 * @author Nicola Asuni
12768 * @since 4.8.000 (2009-09-07)
12769 */
12770 public function TextField($name, $w, $h, $prop=array(), $opt=array(), $x='', $y='', $js=false) {
12771 if ($x === '') {
12772 $x = $this->x;
12773 }
12774 if ($y === '') {
12775 $y = $this->y;
12776 }
12777 // check page for no-write regions and adapt page margins if necessary
12778 list($x, $y) = $this->checkPageRegions($h, $x, $y);
12779 if ($js) {
12780 $this->_addfield('text', $name, $x, $y, $w, $h, $prop);
12781 return;
12782 }
12783 // get default style
12784 $prop = array_merge($this->getFormDefaultProp(), $prop);
12785 // get annotation data
12786 $popt = TCPDF_STATIC::getAnnotOptFromJSProp($prop, $this->spot_colors, $this->rtl);
12787 // set default appearance stream
12788 $this->annotation_fonts[$this->CurrentFont['fontkey']] = $this->CurrentFont['i'];
12789 $fontstyle = sprintf('/F%d %F Tf %s', $this->CurrentFont['i'], $this->FontSizePt, $this->TextColor);
12790 $popt['da'] = $fontstyle;
12791 // build appearance stream
12792 $popt['ap'] = array();
12793 $popt['ap']['n'] = '/Tx BMC q '.$fontstyle.' ';
12794 $text = '';
12795 if (isset($prop['value']) AND !empty($prop['value'])) {
12796 $text = $prop['value'];
12797 } elseif (isset($opt['v']) AND !empty($opt['v'])) {
12798 $text = $opt['v'];
12799 }
12800 $tmpid = $this->startTemplate($w, $h, false);
12801 $align = '';
12802 if (isset($popt['q'])) {
12803 switch ($popt['q']) {
12804 case 0: {
12805 $align = 'L';
12806 break;
12807 }
12808 case 1: {
12809 $align = 'C';
12810 break;
12811 }
12812 case 2: {
12813 $align = 'R';
12814 break;
12815 }
12816 default: {
12817 $align = '';
12818 break;
12819 }
12820 }
12821 }
12822 $this->MultiCell($w, $h, $text, 0, $align, false, 0, 0, 0, true, 0, false, true, 0, 'T', false);
12823 $this->endTemplate();
12824 --$this->n;
12825 $popt['ap']['n'] .= $this->xobjects[$tmpid]['outdata'];
12826 unset($this->xobjects[$tmpid]);
12827 $popt['ap']['n'] .= 'Q EMC';
12828 // merge options
12829 $opt = array_merge($popt, $opt);
12830 // remove some conflicting options
12831 unset($opt['bs']);
12832 // set remaining annotation data
12833 $opt['Subtype'] = 'Widget';
12834 $opt['ft'] = 'Tx';
12835 $opt['t'] = $name;
12836 // Additional annotation's parameters (check _putannotsobj() method):
12837 //$opt['f']
12838 //$opt['as']
12839 //$opt['bs']
12840 //$opt['be']
12841 //$opt['c']
12842 //$opt['border']
12843 //$opt['h']
12844 //$opt['mk'];
12845 //$opt['mk']['r']
12846 //$opt['mk']['bc'];
12847 //$opt['mk']['bg'];
12848 unset($opt['mk']['ca']);
12849 unset($opt['mk']['rc']);
12850 unset($opt['mk']['ac']);
12851 unset($opt['mk']['i']);
12852 unset($opt['mk']['ri']);
12853 unset($opt['mk']['ix']);
12854 unset($opt['mk']['if']);
12855 //$opt['mk']['if']['sw'];
12856 //$opt['mk']['if']['s'];
12857 //$opt['mk']['if']['a'];
12858 //$opt['mk']['if']['fb'];
12859 unset($opt['mk']['tp']);
12860 //$opt['tu']
12861 //$opt['tm']
12862 //$opt['ff']
12863 //$opt['v']
12864 //$opt['dv']
12865 //$opt['a']
12866 //$opt['aa']
12867 //$opt['q']
12868 $this->Annotation($x, $y, $w, $h, $name, $opt, 0);
12869 if ($this->rtl) {
12870 $this->x -= $w;
12871 } else {
12872 $this->x += $w;
12873 }
12874 }
12875
12876 /**
12877 * Creates a RadioButton field.
12878 * @param $name (string) Field name.
12879 * @param $w (int) Width of the radio button.
12880 * @param $prop (array) Javascript field properties. Possible values are described on official Javascript for Acrobat API reference.
12881 * @param $opt (array) Annotation parameters. Possible values are described on official PDF32000_2008 reference.
12882 * @param $onvalue (string) Value to be returned if selected.
12883 * @param $checked (boolean) Define the initial state.
12884 * @param $x (float) Abscissa of the upper-left corner of the rectangle
12885 * @param $y (float) Ordinate of the upper-left corner of the rectangle
12886 * @param $js (boolean) If true put the field using JavaScript (requires Acrobat Writer to be rendered).
12887 * @public
12888 * @author Nicola Asuni
12889 * @since 4.8.000 (2009-09-07)
12890 */
12891 public function RadioButton($name, $w, $prop=array(), $opt=array(), $onvalue='On', $checked=false, $x='', $y='', $js=false) {
12892 if ($x === '') {
12893 $x = $this->x;
12894 }
12895 if ($y === '') {
12896 $y = $this->y;
12897 }
12898 // check page for no-write regions and adapt page margins if necessary
12899 list($x, $y) = $this->checkPageRegions($w, $x, $y);
12900 if ($js) {
12901 $this->_addfield('radiobutton', $name, $x, $y, $w, $w, $prop);
12902 return;
12903 }
12904 if (TCPDF_STATIC::empty_string($onvalue)) {
12905 $onvalue = 'On';
12906 }
12907 if ($checked) {
12908 $defval = $onvalue;
12909 } else {
12910 $defval = 'Off';
12911 }
12912 // set font
12913 $font = 'zapfdingbats';
12914 if ($this->pdfa_mode) {
12915 // all fonts must be embedded
12916 $font = 'pdfa'.$font;
12917 }
12918 $this->AddFont($font);
12919 $tmpfont = $this->getFontBuffer($font);
12920 // set data for parent group
12921 if (!isset($this->radiobutton_groups[$this->page])) {
12922 $this->radiobutton_groups[$this->page] = array();
12923 }
12924 if (!isset($this->radiobutton_groups[$this->page][$name])) {
12925 $this->radiobutton_groups[$this->page][$name] = array();
12926 ++$this->n;
12927 $this->radiobutton_groups[$this->page][$name]['n'] = $this->n;
12928 $this->radio_groups[] = $this->n;
12929 }
12930 $kid = ($this->n + 1);
12931 // save object ID to be added on Kids entry on parent object
12932 $this->radiobutton_groups[$this->page][$name][] = array('kid' => $kid, 'def' => $defval);
12933 // get default style
12934 $prop = array_merge($this->getFormDefaultProp(), $prop);
12935 $prop['NoToggleToOff'] = 'true';
12936 $prop['Radio'] = 'true';
12937 $prop['borderStyle'] = 'inset';
12938 // get annotation data
12939 $popt = TCPDF_STATIC::getAnnotOptFromJSProp($prop, $this->spot_colors, $this->rtl);
12940 // set additional default options
12941 $this->annotation_fonts[$tmpfont['fontkey']] = $tmpfont['i'];
12942 $fontstyle = sprintf('/F%d %F Tf %s', $tmpfont['i'], $this->FontSizePt, $this->TextColor);
12943 $popt['da'] = $fontstyle;
12944 // build appearance stream
12945 $popt['ap'] = array();
12946 $popt['ap']['n'] = array();
12947 $fx = ((($w - $this->getAbsFontMeasure($tmpfont['cw'][108])) / 2) * $this->k);
12948 $fy = (($w - ((($tmpfont['desc']['Ascent'] - $tmpfont['desc']['Descent']) * $this->FontSizePt / 1000) / $this->k)) * $this->k);
12949 $popt['ap']['n'][$onvalue] = sprintf('q %s BT /F%d %F Tf %F %F Td ('.chr(108).') Tj ET Q', $this->TextColor, $tmpfont['i'], $this->FontSizePt, $fx, $fy);
12950 $popt['ap']['n']['Off'] = sprintf('q %s BT /F%d %F Tf %F %F Td ('.chr(109).') Tj ET Q', $this->TextColor, $tmpfont['i'], $this->FontSizePt, $fx, $fy);
12951 if (!isset($popt['mk'])) {
12952 $popt['mk'] = array();
12953 }
12954 $popt['mk']['ca'] = '(l)';
12955 // merge options
12956 $opt = array_merge($popt, $opt);
12957 // set remaining annotation data
12958 $opt['Subtype'] = 'Widget';
12959 $opt['ft'] = 'Btn';
12960 if ($checked) {
12961 $opt['v'] = array('/'.$onvalue);
12962 $opt['as'] = $onvalue;
12963 } else {
12964 $opt['as'] = 'Off';
12965 }
12966 // store readonly flag
12967 if (!isset($this->radiobutton_groups[$this->page][$name]['#readonly#'])) {
12968 $this->radiobutton_groups[$this->page][$name]['#readonly#'] = false;
12969 }
12970 $this->radiobutton_groups[$this->page][$name]['#readonly#'] |= ($opt['f'] & 64);
12971 $this->Annotation($x, $y, $w, $w, $name, $opt, 0);
12972 if ($this->rtl) {
12973 $this->x -= $w;
12974 } else {
12975 $this->x += $w;
12976 }
12977 }
12978
12979 /**
12980 * Creates a List-box field
12981 * @param $name (string) field name
12982 * @param $w (int) width
12983 * @param $h (int) height
12984 * @param $values (array) array containing the list of values.
12985 * @param $prop (array) javascript field properties. Possible values are described on official Javascript for Acrobat API reference.
12986 * @param $opt (array) annotation parameters. Possible values are described on official PDF32000_2008 reference.
12987 * @param $x (float) Abscissa of the upper-left corner of the rectangle
12988 * @param $y (float) Ordinate of the upper-left corner of the rectangle
12989 * @param $js (boolean) if true put the field using JavaScript (requires Acrobat Writer to be rendered).
12990 * @public
12991 * @author Nicola Asuni
12992 * @since 4.8.000 (2009-09-07)
12993 */
12994 public function ListBox($name, $w, $h, $values, $prop=array(), $opt=array(), $x='', $y='', $js=false) {
12995 if ($x === '') {
12996 $x = $this->x;
12997 }
12998 if ($y === '') {
12999 $y = $this->y;
13000 }
13001 // check page for no-write regions and adapt page margins if necessary
13002 list($x, $y) = $this->checkPageRegions($h, $x, $y);
13003 if ($js) {
13004 $this->_addfield('listbox', $name, $x, $y, $w, $h, $prop);
13005 $s = '';
13006 foreach ($values as $value) {
13007 if (is_array($value)) {
13008 $s .= ',[\''.addslashes($value[1]).'\',\''.addslashes($value[0]).'\']';
13009 } else {
13010 $s .= ',[\''.addslashes($value).'\',\''.addslashes($value).'\']';
13011 }
13012 }
13013 $this->javascript .= 'f'.$name.'.setItems('.substr($s, 1).');'."\n";
13014 return;
13015 }
13016 // get default style
13017 $prop = array_merge($this->getFormDefaultProp(), $prop);
13018 // get annotation data
13019 $popt = TCPDF_STATIC::getAnnotOptFromJSProp($prop, $this->spot_colors, $this->rtl);
13020 // set additional default values
13021 $this->annotation_fonts[$this->CurrentFont['fontkey']] = $this->CurrentFont['i'];
13022 $fontstyle = sprintf('/F%d %F Tf %s', $this->CurrentFont['i'], $this->FontSizePt, $this->TextColor);
13023 $popt['da'] = $fontstyle;
13024 // build appearance stream
13025 $popt['ap'] = array();
13026 $popt['ap']['n'] = '/Tx BMC q '.$fontstyle.' ';
13027 $text = '';
13028 foreach($values as $item) {
13029 if (is_array($item)) {
13030 $text .= $item[1]."\n";
13031 } else {
13032 $text .= $item."\n";
13033 }
13034 }
13035 $tmpid = $this->startTemplate($w, $h, false);
13036 $this->MultiCell($w, $h, $text, 0, '', false, 0, 0, 0, true, 0, false, true, 0, 'T', false);
13037 $this->endTemplate();
13038 --$this->n;
13039 $popt['ap']['n'] .= $this->xobjects[$tmpid]['outdata'];
13040 unset($this->xobjects[$tmpid]);
13041 $popt['ap']['n'] .= 'Q EMC';
13042 // merge options
13043 $opt = array_merge($popt, $opt);
13044 // set remaining annotation data
13045 $opt['Subtype'] = 'Widget';
13046 $opt['ft'] = 'Ch';
13047 $opt['t'] = $name;
13048 $opt['opt'] = $values;
13049 unset($opt['mk']['ca']);
13050 unset($opt['mk']['rc']);
13051 unset($opt['mk']['ac']);
13052 unset($opt['mk']['i']);
13053 unset($opt['mk']['ri']);
13054 unset($opt['mk']['ix']);
13055 unset($opt['mk']['if']);
13056 unset($opt['mk']['tp']);
13057 $this->Annotation($x, $y, $w, $h, $name, $opt, 0);
13058 if ($this->rtl) {
13059 $this->x -= $w;
13060 } else {
13061 $this->x += $w;
13062 }
13063 }
13064
13065 /**
13066 * Creates a Combo-box field
13067 * @param $name (string) field name
13068 * @param $w (int) width
13069 * @param $h (int) height
13070 * @param $values (array) array containing the list of values.
13071 * @param $prop (array) javascript field properties. Possible values are described on official Javascript for Acrobat API reference.
13072 * @param $opt (array) annotation parameters. Possible values are described on official PDF32000_2008 reference.
13073 * @param $x (float) Abscissa of the upper-left corner of the rectangle
13074 * @param $y (float) Ordinate of the upper-left corner of the rectangle
13075 * @param $js (boolean) if true put the field using JavaScript (requires Acrobat Writer to be rendered).
13076 * @public
13077 * @author Nicola Asuni
13078 * @since 4.8.000 (2009-09-07)
13079 */
13080 public function ComboBox($name, $w, $h, $values, $prop=array(), $opt=array(), $x='', $y='', $js=false) {
13081 if ($x === '') {
13082 $x = $this->x;
13083 }
13084 if ($y === '') {
13085 $y = $this->y;
13086 }
13087 // check page for no-write regions and adapt page margins if necessary
13088 list($x, $y) = $this->checkPageRegions($h, $x, $y);
13089 if ($js) {
13090 $this->_addfield('combobox', $name, $x, $y, $w, $h, $prop);
13091 $s = '';
13092 foreach ($values as $value) {
13093 if (is_array($value)) {
13094 $s .= ',[\''.addslashes($value[1]).'\',\''.addslashes($value[0]).'\']';
13095 } else {
13096 $s .= ',[\''.addslashes($value).'\',\''.addslashes($value).'\']';
13097 }
13098 }
13099 $this->javascript .= 'f'.$name.'.setItems('.substr($s, 1).');'."\n";
13100 return;
13101 }
13102 // get default style
13103 $prop = array_merge($this->getFormDefaultProp(), $prop);
13104 $prop['Combo'] = true;
13105 // get annotation data
13106 $popt = TCPDF_STATIC::getAnnotOptFromJSProp($prop, $this->spot_colors, $this->rtl);
13107 // set additional default options
13108 $this->annotation_fonts[$this->CurrentFont['fontkey']] = $this->CurrentFont['i'];
13109 $fontstyle = sprintf('/F%d %F Tf %s', $this->CurrentFont['i'], $this->FontSizePt, $this->TextColor);
13110 $popt['da'] = $fontstyle;
13111 // build appearance stream
13112 $popt['ap'] = array();
13113 $popt['ap']['n'] = '/Tx BMC q '.$fontstyle.' ';
13114 $text = '';
13115 foreach($values as $item) {
13116 if (is_array($item)) {
13117 $text .= $item[1]."\n";
13118 } else {
13119 $text .= $item."\n";
13120 }
13121 }
13122 $tmpid = $this->startTemplate($w, $h, false);
13123 $this->MultiCell($w, $h, $text, 0, '', false, 0, 0, 0, true, 0, false, true, 0, 'T', false);
13124 $this->endTemplate();
13125 --$this->n;
13126 $popt['ap']['n'] .= $this->xobjects[$tmpid]['outdata'];
13127 unset($this->xobjects[$tmpid]);
13128 $popt['ap']['n'] .= 'Q EMC';
13129 // merge options
13130 $opt = array_merge($popt, $opt);
13131 // set remaining annotation data
13132 $opt['Subtype'] = 'Widget';
13133 $opt['ft'] = 'Ch';
13134 $opt['t'] = $name;
13135 $opt['opt'] = $values;
13136 unset($opt['mk']['ca']);
13137 unset($opt['mk']['rc']);
13138 unset($opt['mk']['ac']);
13139 unset($opt['mk']['i']);
13140 unset($opt['mk']['ri']);
13141 unset($opt['mk']['ix']);
13142 unset($opt['mk']['if']);
13143 unset($opt['mk']['tp']);
13144 $this->Annotation($x, $y, $w, $h, $name, $opt, 0);
13145 if ($this->rtl) {
13146 $this->x -= $w;
13147 } else {
13148 $this->x += $w;
13149 }
13150 }
13151
13152 /**
13153 * Creates a CheckBox field
13154 * @param $name (string) field name
13155 * @param $w (int) width
13156 * @param $checked (boolean) define the initial state.
13157 * @param $prop (array) javascript field properties. Possible values are described on official Javascript for Acrobat API reference.
13158 * @param $opt (array) annotation parameters. Possible values are described on official PDF32000_2008 reference.
13159 * @param $onvalue (string) value to be returned if selected.
13160 * @param $x (float) Abscissa of the upper-left corner of the rectangle
13161 * @param $y (float) Ordinate of the upper-left corner of the rectangle
13162 * @param $js (boolean) if true put the field using JavaScript (requires Acrobat Writer to be rendered).
13163 * @public
13164 * @author Nicola Asuni
13165 * @since 4.8.000 (2009-09-07)
13166 */
13167 public function CheckBox($name, $w, $checked=false, $prop=array(), $opt=array(), $onvalue='Yes', $x='', $y='', $js=false) {
13168 if ($x === '') {
13169 $x = $this->x;
13170 }
13171 if ($y === '') {
13172 $y = $this->y;
13173 }
13174 // check page for no-write regions and adapt page margins if necessary
13175 list($x, $y) = $this->checkPageRegions($w, $x, $y);
13176 if ($js) {
13177 $this->_addfield('checkbox', $name, $x, $y, $w, $w, $prop);
13178 return;
13179 }
13180 if (!isset($prop['value'])) {
13181 $prop['value'] = array('Yes');
13182 }
13183 // get default style
13184 $prop = array_merge($this->getFormDefaultProp(), $prop);
13185 $prop['borderStyle'] = 'inset';
13186 // get annotation data
13187 $popt = TCPDF_STATIC::getAnnotOptFromJSProp($prop, $this->spot_colors, $this->rtl);
13188 // set additional default options
13189 $font = 'zapfdingbats';
13190 if ($this->pdfa_mode) {
13191 // all fonts must be embedded
13192 $font = 'pdfa'.$font;
13193 }
13194 $this->AddFont($font);
13195 $tmpfont = $this->getFontBuffer($font);
13196 $this->annotation_fonts[$tmpfont['fontkey']] = $tmpfont['i'];
13197 $fontstyle = sprintf('/F%d %F Tf %s', $tmpfont['i'], $this->FontSizePt, $this->TextColor);
13198 $popt['da'] = $fontstyle;
13199 // build appearance stream
13200 $popt['ap'] = array();
13201 $popt['ap']['n'] = array();
13202 $fx = ((($w - $this->getAbsFontMeasure($tmpfont['cw'][110])) / 2) * $this->k);
13203 $fy = (($w - ((($tmpfont['desc']['Ascent'] - $tmpfont['desc']['Descent']) * $this->FontSizePt / 1000) / $this->k)) * $this->k);
13204 $popt['ap']['n']['Yes'] = sprintf('q %s BT /F%d %F Tf %F %F Td ('.chr(110).') Tj ET Q', $this->TextColor, $tmpfont['i'], $this->FontSizePt, $fx, $fy);
13205 $popt['ap']['n']['Off'] = sprintf('q %s BT /F%d %F Tf %F %F Td ('.chr(111).') Tj ET Q', $this->TextColor, $tmpfont['i'], $this->FontSizePt, $fx, $fy);
13206 // merge options
13207 $opt = array_merge($popt, $opt);
13208 // set remaining annotation data
13209 $opt['Subtype'] = 'Widget';
13210 $opt['ft'] = 'Btn';
13211 $opt['t'] = $name;
13212 if (TCPDF_STATIC::empty_string($onvalue)) {
13213 $onvalue = 'Yes';
13214 }
13215 $opt['opt'] = array($onvalue);
13216 if ($checked) {
13217 $opt['v'] = array('/Yes');
13218 $opt['as'] = 'Yes';
13219 } else {
13220 $opt['v'] = array('/Off');
13221 $opt['as'] = 'Off';
13222 }
13223 $this->Annotation($x, $y, $w, $w, $name, $opt, 0);
13224 if ($this->rtl) {
13225 $this->x -= $w;
13226 } else {
13227 $this->x += $w;
13228 }
13229 }
13230
13231 /**
13232 * Creates a button field
13233 * @param $name (string) field name
13234 * @param $w (int) width
13235 * @param $h (int) height
13236 * @param $caption (string) caption.
13237 * @param $action (mixed) action triggered by pressing the button. Use a string to specify a javascript action. Use an array to specify a form action options as on section 12.7.5 of PDF32000_2008.
13238 * @param $prop (array) javascript field properties. Possible values are described on official Javascript for Acrobat API reference.
13239 * @param $opt (array) annotation parameters. Possible values are described on official PDF32000_2008 reference.
13240 * @param $x (float) Abscissa of the upper-left corner of the rectangle
13241 * @param $y (float) Ordinate of the upper-left corner of the rectangle
13242 * @param $js (boolean) if true put the field using JavaScript (requires Acrobat Writer to be rendered).
13243 * @public
13244 * @author Nicola Asuni
13245 * @since 4.8.000 (2009-09-07)
13246 */
13247 public function Button($name, $w, $h, $caption, $action, $prop=array(), $opt=array(), $x='', $y='', $js=false) {
13248 if ($x === '') {
13249 $x = $this->x;
13250 }
13251 if ($y === '') {
13252 $y = $this->y;
13253 }
13254 // check page for no-write regions and adapt page margins if necessary
13255 list($x, $y) = $this->checkPageRegions($h, $x, $y);
13256 if ($js) {
13257 $this->_addfield('button', $name, $this->x, $this->y, $w, $h, $prop);
13258 $this->javascript .= 'f'.$name.".buttonSetCaption('".addslashes($caption)."');\n";
13259 $this->javascript .= 'f'.$name.".setAction('MouseUp','".addslashes($action)."');\n";
13260 $this->javascript .= 'f'.$name.".highlight='push';\n";
13261 $this->javascript .= 'f'.$name.".print=false;\n";
13262 return;
13263 }
13264 // get default style
13265 $prop = array_merge($this->getFormDefaultProp(), $prop);
13266 $prop['Pushbutton'] = 'true';
13267 $prop['highlight'] = 'push';
13268 $prop['display'] = 'display.noPrint';
13269 // get annotation data
13270 $popt = TCPDF_STATIC::getAnnotOptFromJSProp($prop, $this->spot_colors, $this->rtl);
13271 $this->annotation_fonts[$this->CurrentFont['fontkey']] = $this->CurrentFont['i'];
13272 $fontstyle = sprintf('/F%d %F Tf %s', $this->CurrentFont['i'], $this->FontSizePt, $this->TextColor);
13273 $popt['da'] = $fontstyle;
13274 // build appearance stream
13275 $popt['ap'] = array();
13276 $popt['ap']['n'] = '/Tx BMC q '.$fontstyle.' ';
13277 $tmpid = $this->startTemplate($w, $h, false);
13278 $bw = (2 / $this->k); // border width
13279 $border = array(
13280 'L' => array('width' => $bw, 'cap' => 'square', 'join' => 'miter', 'dash' => 0, 'color' => array(231)),
13281 'R' => array('width' => $bw, 'cap' => 'square', 'join' => 'miter', 'dash' => 0, 'color' => array(51)),
13282 'T' => array('width' => $bw, 'cap' => 'square', 'join' => 'miter', 'dash' => 0, 'color' => array(231)),
13283 'B' => array('width' => $bw, 'cap' => 'square', 'join' => 'miter', 'dash' => 0, 'color' => array(51)));
13284 $this->SetFillColor(204);
13285 $this->Cell($w, $h, $caption, $border, 0, 'C', true, '', 1, false, 'T', 'M');
13286 $this->endTemplate();
13287 --$this->n;
13288 $popt['ap']['n'] .= $this->xobjects[$tmpid]['outdata'];
13289 unset($this->xobjects[$tmpid]);
13290 $popt['ap']['n'] .= 'Q EMC';
13291 // set additional default options
13292 if (!isset($popt['mk'])) {
13293 $popt['mk'] = array();
13294 }
13295 $ann_obj_id = ($this->n + 1);
13296 if (!empty($action) AND !is_array($action)) {
13297 $ann_obj_id = ($this->n + 2);
13298 }
13299 $popt['mk']['ca'] = $this->_textstring($caption, $ann_obj_id);
13300 $popt['mk']['rc'] = $this->_textstring($caption, $ann_obj_id);
13301 $popt['mk']['ac'] = $this->_textstring($caption, $ann_obj_id);
13302 // merge options
13303 $opt = array_merge($popt, $opt);
13304 // set remaining annotation data
13305 $opt['Subtype'] = 'Widget';
13306 $opt['ft'] = 'Btn';
13307 $opt['t'] = $caption;
13308 $opt['v'] = $name;
13309 if (!empty($action)) {
13310 if (is_array($action)) {
13311 // form action options as on section 12.7.5 of PDF32000_2008.
13312 $opt['aa'] = '/D <<';
13313 $bmode = array('SubmitForm', 'ResetForm', 'ImportData');
13314 foreach ($action AS $key => $val) {
13315 if (($key == 'S') AND in_array($val, $bmode)) {
13316 $opt['aa'] .= ' /S /'.$val;
13317 } elseif (($key == 'F') AND (!empty($val))) {
13318 $opt['aa'] .= ' /F '.$this->_datastring($val, $ann_obj_id);
13319 } elseif (($key == 'Fields') AND is_array($val) AND !empty($val)) {
13320 $opt['aa'] .= ' /Fields [';
13321 foreach ($val AS $field) {
13322 $opt['aa'] .= ' '.$this->_textstring($field, $ann_obj_id);
13323 }
13324 $opt['aa'] .= ']';
13325 } elseif (($key == 'Flags')) {
13326 $ff = 0;
13327 if (is_array($val)) {
13328 foreach ($val AS $flag) {
13329 switch ($flag) {
13330 case 'Include/Exclude': {
13331 $ff += 1 << 0;
13332 break;
13333 }
13334 case 'IncludeNoValueFields': {
13335 $ff += 1 << 1;
13336 break;
13337 }
13338 case 'ExportFormat': {
13339 $ff += 1 << 2;
13340 break;
13341 }
13342 case 'GetMethod': {
13343 $ff += 1 << 3;
13344 break;
13345 }
13346 case 'SubmitCoordinates': {
13347 $ff += 1 << 4;
13348 break;
13349 }
13350 case 'XFDF': {
13351 $ff += 1 << 5;
13352 break;
13353 }
13354 case 'IncludeAppendSaves': {
13355 $ff += 1 << 6;
13356 break;
13357 }
13358 case 'IncludeAnnotations': {
13359 $ff += 1 << 7;
13360 break;
13361 }
13362 case 'SubmitPDF': {
13363 $ff += 1 << 8;
13364 break;
13365 }
13366 case 'CanonicalFormat': {
13367 $ff += 1 << 9;
13368 break;
13369 }
13370 case 'ExclNonUserAnnots': {
13371 $ff += 1 << 10;
13372 break;
13373 }
13374 case 'ExclFKey': {
13375 $ff += 1 << 11;
13376 break;
13377 }
13378 case 'EmbedForm': {
13379 $ff += 1 << 13;
13380 break;
13381 }
13382 }
13383 }
13384 } else {
13385 $ff = intval($val);
13386 }
13387 $opt['aa'] .= ' /Flags '.$ff;
13388 }
13389 }
13390 $opt['aa'] .= ' >>';
13391 } else {
13392 // Javascript action or raw action command
13393 $js_obj_id = $this->addJavascriptObject($action);
13394 $opt['aa'] = '/D '.$js_obj_id.' 0 R';
13395 }
13396 }
13397 $this->Annotation($x, $y, $w, $h, $name, $opt, 0);
13398 if ($this->rtl) {
13399 $this->x -= $w;
13400 } else {
13401 $this->x += $w;
13402 }
13403 }
13404
13405 // --- END FORMS FIELDS ------------------------------------------------
13406
13407 /**
13408 * Add certification signature (DocMDP or UR3)
13409 * You can set only one signature type
13410 * @protected
13411 * @author Nicola Asuni
13412 * @since 4.6.008 (2009-05-07)
13413 */
13414 protected function _putsignature() {
13415 if ((!$this->sign) OR (!isset($this->signature_data['cert_type']))) {
13416 return;
13417 }
13418 $sigobjid = ($this->sig_obj_id + 1);
13419 $out = $this->_getobj($sigobjid)."\n";
13420 $out .= '<< /Type /Sig';
13421 $out .= ' /Filter /Adobe.PPKLite';
13422 $out .= ' /SubFilter /adbe.pkcs7.detached';
13423 $out .= ' '.TCPDF_STATIC::$byterange_string;
13424 $out .= ' /Contents<'.str_repeat('0', $this->signature_max_length).'>';
13425 if (empty($this->signature_data['approval']) OR ($this->signature_data['approval'] != 'A')) {
13426 $out .= ' /Reference ['; // array of signature reference dictionaries
13427 $out .= ' << /Type /SigRef';
13428 if ($this->signature_data['cert_type'] > 0) {
13429 $out .= ' /TransformMethod /DocMDP';
13430 $out .= ' /TransformParams <<';
13431 $out .= ' /Type /TransformParams';
13432 $out .= ' /P '.$this->signature_data['cert_type'];
13433 $out .= ' /V /1.2';
13434 } else {
13435 $out .= ' /TransformMethod /UR3';
13436 $out .= ' /TransformParams <<';
13437 $out .= ' /Type /TransformParams';
13438 $out .= ' /V /2.2';
13439 if (!TCPDF_STATIC::empty_string($this->ur['document'])) {
13440 $out .= ' /Document['.$this->ur['document'].']';
13441 }
13442 if (!TCPDF_STATIC::empty_string($this->ur['form'])) {
13443 $out .= ' /Form['.$this->ur['form'].']';
13444 }
13445 if (!TCPDF_STATIC::empty_string($this->ur['signature'])) {
13446 $out .= ' /Signature['.$this->ur['signature'].']';
13447 }
13448 if (!TCPDF_STATIC::empty_string($this->ur['annots'])) {
13449 $out .= ' /Annots['.$this->ur['annots'].']';
13450 }
13451 if (!TCPDF_STATIC::empty_string($this->ur['ef'])) {
13452 $out .= ' /EF['.$this->ur['ef'].']';
13453 }
13454 if (!TCPDF_STATIC::empty_string($this->ur['formex'])) {
13455 $out .= ' /FormEX['.$this->ur['formex'].']';
13456 }
13457 }
13458 $out .= ' >>'; // close TransformParams
13459 // optional digest data (values must be calculated and replaced later)
13460 //$out .= ' /Data ********** 0 R';
13461 //$out .= ' /DigestMethod/MD5';
13462 //$out .= ' /DigestLocation[********** 34]';
13463 //$out .= ' /DigestValue<********************************>';
13464 $out .= ' >>';
13465 $out .= ' ]'; // end of reference
13466 }
13467 if (isset($this->signature_data['info']['Name']) AND !TCPDF_STATIC::empty_string($this->signature_data['info']['Name'])) {
13468 $out .= ' /Name '.$this->_textstring($this->signature_data['info']['Name'], $sigobjid);
13469 }
13470 if (isset($this->signature_data['info']['Location']) AND !TCPDF_STATIC::empty_string($this->signature_data['info']['Location'])) {
13471 $out .= ' /Location '.$this->_textstring($this->signature_data['info']['Location'], $sigobjid);
13472 }
13473 if (isset($this->signature_data['info']['Reason']) AND !TCPDF_STATIC::empty_string($this->signature_data['info']['Reason'])) {
13474 $out .= ' /Reason '.$this->_textstring($this->signature_data['info']['Reason'], $sigobjid);
13475 }
13476 if (isset($this->signature_data['info']['ContactInfo']) AND !TCPDF_STATIC::empty_string($this->signature_data['info']['ContactInfo'])) {
13477 $out .= ' /ContactInfo '.$this->_textstring($this->signature_data['info']['ContactInfo'], $sigobjid);
13478 }
13479 $out .= ' /M '.$this->_datestring($sigobjid, $this->doc_modification_timestamp);
13480 $out .= ' >>';
13481 $out .= "\n".'endobj';
13482 $this->_out($out);
13483 }
13484
13485 /**
13486 * Set User's Rights for PDF Reader
13487 * WARNING: This is experimental and currently do not work.
13488 * Check the PDF Reference 8.7.1 Transform Methods,
13489 * Table 8.105 Entries in the UR transform parameters dictionary
13490 * @param $enable (boolean) if true enable user's rights on PDF reader
13491 * @param $document (string) Names specifying additional document-wide usage rights for the document. The only defined value is "/FullSave", which permits a user to save the document along with modified form and/or annotation data.
13492 * @param $annots (string) Names specifying additional annotation-related usage rights for the document. Valid names in PDF 1.5 and later are /Create/Delete/Modify/Copy/Import/Export, which permit the user to perform the named operation on annotations.
13493 * @param $form (string) Names specifying additional form-field-related usage rights for the document. Valid names are: /Add/Delete/FillIn/Import/Export/SubmitStandalone/SpawnTemplate
13494 * @param $signature (string) Names specifying additional signature-related usage rights for the document. The only defined value is /Modify, which permits a user to apply a digital signature to an existing signature form field or clear a signed signature form field.
13495 * @param $ef (string) Names specifying additional usage rights for named embedded files in the document. Valid names are /Create/Delete/Modify/Import, which permit the user to perform the named operation on named embedded files
13496 Names specifying additional embedded-files-related usage rights for the document.
13497 * @param $formex (string) Names specifying additional form-field-related usage rights. The only valid name is BarcodePlaintext, which permits text form field data to be encoded as a plaintext two-dimensional barcode.
13498 * @public
13499 * @author Nicola Asuni
13500 * @since 2.9.000 (2008-03-26)
13501 */
13502 public function setUserRights(
13503 $enable=true,
13504 $document='/FullSave',
13505 $annots='/Create/Delete/Modify/Copy/Import/Export',
13506 $form='/Add/Delete/FillIn/Import/Export/SubmitStandalone/SpawnTemplate',
13507 $signature='/Modify',
13508 $ef='/Create/Delete/Modify/Import',
13509 $formex='') {
13510 $this->ur['enabled'] = $enable;
13511 $this->ur['document'] = $document;
13512 $this->ur['annots'] = $annots;
13513 $this->ur['form'] = $form;
13514 $this->ur['signature'] = $signature;
13515 $this->ur['ef'] = $ef;
13516 $this->ur['formex'] = $formex;
13517 if (!$this->sign) {
13518 $this->setSignature('', '', '', '', 0, array());
13519 }
13520 }
13521
13522 /**
13523 * Enable document signature (requires the OpenSSL Library).
13524 * The digital signature improve document authenticity and integrity and allows o enable extra features on Acrobat Reader.
13525 * To create self-signed signature: openssl req -x509 -nodes -days 365000 -newkey rsa:1024 -keyout tcpdf.crt -out tcpdf.crt
13526 * To export crt to p12: openssl pkcs12 -export -in tcpdf.crt -out tcpdf.p12
13527 * To convert pfx certificate to pem: openssl pkcs12 -in tcpdf.pfx -out tcpdf.crt -nodes
13528 * @param $signing_cert (mixed) signing certificate (string or filename prefixed with 'file://')
13529 * @param $private_key (mixed) private key (string or filename prefixed with 'file://')
13530 * @param $private_key_password (string) password
13531 * @param $extracerts (string) specifies the name of a file containing a bunch of extra certificates to include in the signature which can for example be used to help the recipient to verify the certificate that you used.
13532 * @param $cert_type (int) The access permissions granted for this document. Valid values shall be: 1 = No changes to the document shall be permitted; any change to the document shall invalidate the signature; 2 = Permitted changes shall be filling in forms, instantiating page templates, and signing; other changes shall invalidate the signature; 3 = Permitted changes shall be the same as for 2, as well as annotation creation, deletion, and modification; other changes shall invalidate the signature.
13533 * @param $info (array) array of option information: Name, Location, Reason, ContactInfo.
13534 * @param $approval (string) Enable approval signature eg. for PDF incremental update
13535 * @public
13536 * @author Nicola Asuni
13537 * @since 4.6.005 (2009-04-24)
13538 */
13539 public function setSignature($signing_cert='', $private_key='', $private_key_password='', $extracerts='', $cert_type=2, $info=array(), $approval='') {
13540 // to create self-signed signature: openssl req -x509 -nodes -days 365000 -newkey rsa:1024 -keyout tcpdf.crt -out tcpdf.crt
13541 // to export crt to p12: openssl pkcs12 -export -in tcpdf.crt -out tcpdf.p12
13542 // to convert pfx certificate to pem: openssl
13543 // OpenSSL> pkcs12 -in <cert.pfx> -out <cert.crt> -nodes
13544 $this->sign = true;
13545 ++$this->n;
13546 $this->sig_obj_id = $this->n; // signature widget
13547 ++$this->n; // signature object ($this->sig_obj_id + 1)
13548 $this->signature_data = array();
13549 if (strlen($signing_cert) == 0) {
13550 $this->Error('Please provide a certificate file and password!');
13551 }
13552 if (strlen($private_key) == 0) {
13553 $private_key = $signing_cert;
13554 }
13555 $this->signature_data['signcert'] = $signing_cert;
13556 $this->signature_data['privkey'] = $private_key;
13557 $this->signature_data['password'] = $private_key_password;
13558 $this->signature_data['extracerts'] = $extracerts;
13559 $this->signature_data['cert_type'] = $cert_type;
13560 $this->signature_data['info'] = $info;
13561 $this->signature_data['approval'] = $approval;
13562 }
13563
13564 /**
13565 * Set the digital signature appearance (a cliccable rectangle area to get signature properties)
13566 * @param $x (float) Abscissa of the upper-left corner.
13567 * @param $y (float) Ordinate of the upper-left corner.
13568 * @param $w (float) Width of the signature area.
13569 * @param $h (float) Height of the signature area.
13570 * @param $page (int) option page number (if < 0 the current page is used).
13571 * @param $name (string) Name of the signature.
13572 * @public
13573 * @author Nicola Asuni
13574 * @since 5.3.011 (2010-06-17)
13575 */
13576 public function setSignatureAppearance($x=0, $y=0, $w=0, $h=0, $page=-1, $name='') {
13577 $this->signature_appearance = $this->getSignatureAppearanceArray($x, $y, $w, $h, $page, $name);
13578 }
13579
13580 /**
13581 * Add an empty digital signature appearance (a cliccable rectangle area to get signature properties)
13582 * @param $x (float) Abscissa of the upper-left corner.
13583 * @param $y (float) Ordinate of the upper-left corner.
13584 * @param $w (float) Width of the signature area.
13585 * @param $h (float) Height of the signature area.
13586 * @param $page (int) option page number (if < 0 the current page is used).
13587 * @param $name (string) Name of the signature.
13588 * @public
13589 * @author Nicola Asuni
13590 * @since 5.9.101 (2011-07-06)
13591 */
13592 public function addEmptySignatureAppearance($x=0, $y=0, $w=0, $h=0, $page=-1, $name='') {
13593 ++$this->n;
13594 $this->empty_signature_appearance[] = array('objid' => $this->n) + $this->getSignatureAppearanceArray($x, $y, $w, $h, $page, $name);
13595 }
13596
13597 /**
13598 * Get the array that defines the signature appearance (page and rectangle coordinates).
13599 * @param $x (float) Abscissa of the upper-left corner.
13600 * @param $y (float) Ordinate of the upper-left corner.
13601 * @param $w (float) Width of the signature area.
13602 * @param $h (float) Height of the signature area.
13603 * @param $page (int) option page number (if < 0 the current page is used).
13604 * @param $name (string) Name of the signature.
13605 * @return (array) Array defining page and rectangle coordinates of signature appearance.
13606 * @protected
13607 * @author Nicola Asuni
13608 * @since 5.9.101 (2011-07-06)
13609 */
13610 protected function getSignatureAppearanceArray($x=0, $y=0, $w=0, $h=0, $page=-1, $name='') {
13611 $sigapp = array();
13612 if (($page < 1) OR ($page > $this->numpages)) {
13613 $sigapp['page'] = $this->page;
13614 } else {
13615 $sigapp['page'] = intval($page);
13616 }
13617 if (empty($name)) {
13618 $sigapp['name'] = 'Signature';
13619 } else {
13620 $sigapp['name'] = $name;
13621 }
13622 $a = $x * $this->k;
13623 $b = $this->pagedim[($sigapp['page'])]['h'] - (($y + $h) * $this->k);
13624 $c = $w * $this->k;
13625 $d = $h * $this->k;
13626 $sigapp['rect'] = sprintf('%F %F %F %F', $a, $b, ($a + $c), ($b + $d));
13627 return $sigapp;
13628 }
13629
13630 /**
13631 * Enable document timestamping (requires the OpenSSL Library).
13632 * The trusted timestamping improve document security that means that no one should be able to change the document once it has been recorded.
13633 * Use with digital signature only!
13634 * @param $tsa_host (string) Time Stamping Authority (TSA) server (prefixed with 'https://')
13635 * @param $tsa_username (string) Specifies the username for TSA authorization (optional) OR specifies the TSA authorization PEM file (see: example_66.php, optional)
13636 * @param $tsa_password (string) Specifies the password for TSA authorization (optional)
13637 * @param $tsa_cert (string) Specifies the location of TSA certificate for authorization (optional for cURL)
13638 * @public
13639 * @author Richard Stockinger
13640 * @since 6.0.090 (2014-06-16)
13641 */
13642 public function setTimeStamp($tsa_host='', $tsa_username='', $tsa_password='', $tsa_cert='') {
13643 $this->tsa_data = array();
13644 if (!function_exists('curl_init')) {
13645 $this->Error('Please enable cURL PHP extension!');
13646 }
13647 if (strlen($tsa_host) == 0) {
13648 $this->Error('Please specify the host of Time Stamping Authority (TSA)!');
13649 }
13650 $this->tsa_data['tsa_host'] = $tsa_host;
13651 if (is_file($tsa_username)) {
13652 $this->tsa_data['tsa_auth'] = $tsa_username;
13653 } else {
13654 $this->tsa_data['tsa_username'] = $tsa_username;
13655 }
13656 $this->tsa_data['tsa_password'] = $tsa_password;
13657 $this->tsa_data['tsa_cert'] = $tsa_cert;
13658 $this->tsa_timestamp = true;
13659 }
13660
13661 /**
13662 * NOT YET IMPLEMENTED
13663 * Request TSA for a timestamp
13664 * @param $signature (string) Digital signature as binary string
13665 * @return (string) Timestamped digital signature
13666 * @protected
13667 * @author Richard Stockinger
13668 * @since 6.0.090 (2014-06-16)
13669 */
13670 protected function applyTSA($signature) {
13671 if (!$this->tsa_timestamp) {
13672 return $signature;
13673 }
13674 //@TODO: implement this feature
13675 return $signature;
13676 }
13677
13678 /**
13679 * Create a new page group.
13680 * NOTE: call this function before calling AddPage()
13681 * @param $page (int) starting group page (leave empty for next page).
13682 * @public
13683 * @since 3.0.000 (2008-03-27)
13684 */
13685 public function startPageGroup($page='') {
13686 if (empty($page)) {
13687 $page = $this->page + 1;
13688 }
13689 $this->newpagegroup[$page] = sizeof($this->newpagegroup) + 1;
13690 }
13691
13692 /**
13693 * Set the starting page number.
13694 * @param $num (int) Starting page number.
13695 * @since 5.9.093 (2011-06-16)
13696 * @public
13697 */
13698 public function setStartingPageNumber($num=1) {
13699 $this->starting_page_number = max(0, intval($num));
13700 }
13701
13702 /**
13703 * Returns the string alias used right align page numbers.
13704 * If the current font is unicode type, the returned string wil contain an additional open curly brace.
13705 * @return string
13706 * @since 5.9.099 (2011-06-27)
13707 * @public
13708 */
13709 public function getAliasRightShift() {
13710 // calculate aproximatively the ratio between widths of aliases and replacements.
13711 $ref = '{'.TCPDF_STATIC::$alias_right_shift.'}{'.TCPDF_STATIC::$alias_tot_pages.'}{'.TCPDF_STATIC::$alias_num_page.'}';
13712 $rep = str_repeat(' ', $this->GetNumChars($ref));
13713 $wrep = $this->GetStringWidth($rep);
13714 if ($wrep > 0) {
13715 $wdiff = max(1, ($this->GetStringWidth($ref) / $wrep));
13716 } else {
13717 $wdiff = 1;
13718 }
13719 $sdiff = sprintf('%F', $wdiff);
13720 $alias = TCPDF_STATIC::$alias_right_shift.$sdiff.'}';
13721 if ($this->isUnicodeFont()) {
13722 $alias = '{'.$alias;
13723 }
13724 return $alias;
13725 }
13726
13727 /**
13728 * Returns the string alias used for the total number of pages.
13729 * If the current font is unicode type, the returned string is surrounded by additional curly braces.
13730 * This alias will be replaced by the total number of pages in the document.
13731 * @return string
13732 * @since 4.0.018 (2008-08-08)
13733 * @public
13734 */
13735 public function getAliasNbPages() {
13736 if ($this->isUnicodeFont()) {
13737 return '{'.TCPDF_STATIC::$alias_tot_pages.'}';
13738 }
13739 return TCPDF_STATIC::$alias_tot_pages;
13740 }
13741
13742 /**
13743 * Returns the string alias used for the page number.
13744 * If the current font is unicode type, the returned string is surrounded by additional curly braces.
13745 * This alias will be replaced by the page number.
13746 * @return string
13747 * @since 4.5.000 (2009-01-02)
13748 * @public
13749 */
13750 public function getAliasNumPage() {
13751 if ($this->isUnicodeFont()) {
13752 return '{'.TCPDF_STATIC::$alias_num_page.'}';
13753 }
13754 return TCPDF_STATIC::$alias_num_page;
13755 }
13756
13757 /**
13758 * Return the alias for the total number of pages in the current page group.
13759 * If the current font is unicode type, the returned string is surrounded by additional curly braces.
13760 * This alias will be replaced by the total number of pages in this group.
13761 * @return alias of the current page group
13762 * @public
13763 * @since 3.0.000 (2008-03-27)
13764 */
13765 public function getPageGroupAlias() {
13766 if ($this->isUnicodeFont()) {
13767 return '{'.TCPDF_STATIC::$alias_group_tot_pages.'}';
13768 }
13769 return TCPDF_STATIC::$alias_group_tot_pages;
13770 }
13771
13772 /**
13773 * Return the alias for the page number on the current page group.
13774 * If the current font is unicode type, the returned string is surrounded by additional curly braces.
13775 * This alias will be replaced by the page number (relative to the belonging group).
13776 * @return alias of the current page group
13777 * @public
13778 * @since 4.5.000 (2009-01-02)
13779 */
13780 public function getPageNumGroupAlias() {
13781 if ($this->isUnicodeFont()) {
13782 return '{'.TCPDF_STATIC::$alias_group_num_page.'}';
13783 }
13784 return TCPDF_STATIC::$alias_group_num_page;
13785 }
13786
13787 /**
13788 * Return the current page in the group.
13789 * @return current page in the group
13790 * @public
13791 * @since 3.0.000 (2008-03-27)
13792 */
13793 public function getGroupPageNo() {
13794 return $this->pagegroups[$this->currpagegroup];
13795 }
13796
13797 /**
13798 * Returns the current group page number formatted as a string.
13799 * @public
13800 * @since 4.3.003 (2008-11-18)
13801 * @see PaneNo(), formatPageNumber()
13802 */
13803 public function getGroupPageNoFormatted() {
13804 return TCPDF_STATIC::formatPageNumber($this->getGroupPageNo());
13805 }
13806
13807 /**
13808 * Returns the current page number formatted as a string.
13809 * @public
13810 * @since 4.2.005 (2008-11-06)
13811 * @see PaneNo(), formatPageNumber()
13812 */
13813 public function PageNoFormatted() {
13814 return TCPDF_STATIC::formatPageNumber($this->PageNo());
13815 }
13816
13817 /**
13818 * Put pdf layers.
13819 * @protected
13820 * @since 3.0.000 (2008-03-27)
13821 */
13822 protected function _putocg() {
13823 if (empty($this->pdflayers)) {
13824 return;
13825 }
13826 foreach ($this->pdflayers as $key => $layer) {
13827 $this->pdflayers[$key]['objid'] = $this->_newobj();
13828 $out = '<< /Type /OCG';
13829 $out .= ' /Name '.$this->_textstring($layer['name'], $this->pdflayers[$key]['objid']);
13830 $out .= ' /Usage <<';
13831 if (isset($layer['print']) AND ($layer['print'] !== NULL)) {
13832 $out .= ' /Print <</PrintState /'.($layer['print']?'ON':'OFF').'>>';
13833 }
13834 $out .= ' /View <</ViewState /'.($layer['view']?'ON':'OFF').'>>';
13835 $out .= ' >> >>';
13836 $out .= "\n".'endobj';
13837 $this->_out($out);
13838 }
13839 }
13840
13841 /**
13842 * Start a new pdf layer.
13843 * @param $name (string) Layer name (only a-z letters and numbers). Leave empty for automatic name.
13844 * @param $print (boolean|null) Set to TRUE to print this layer, FALSE to not print and NULL to not set this option
13845 * @param $view (boolean) Set to true to view this layer.
13846 * @param $lock (boolean) If true lock the layer
13847 * @public
13848 * @since 5.9.102 (2011-07-13)
13849 */
13850 public function startLayer($name='', $print=true, $view=true, $lock=true) {
13851 if ($this->state != 2) {
13852 return;
13853 }
13854 $layer = sprintf('LYR%03d', (count($this->pdflayers) + 1));
13855 if (empty($name)) {
13856 $name = $layer;
13857 } else {
13858 $name = preg_replace('/[^a-zA-Z0-9_\-]/', '', $name);
13859 }
13860 $this->pdflayers[] = array('layer' => $layer, 'name' => $name, 'print' => $print, 'view' => $view, 'lock' => $lock);
13861 $this->openMarkedContent = true;
13862 $this->_out('/OC /'.$layer.' BDC');
13863 }
13864
13865 /**
13866 * End the current PDF layer.
13867 * @public
13868 * @since 5.9.102 (2011-07-13)
13869 */
13870 public function endLayer() {
13871 if ($this->state != 2) {
13872 return;
13873 }
13874 if ($this->openMarkedContent) {
13875 // close existing open marked-content layer
13876 $this->_out('EMC');
13877 $this->openMarkedContent = false;
13878 }
13879 }
13880
13881 /**
13882 * Set the visibility of the successive elements.
13883 * This can be useful, for instance, to put a background
13884 * image or color that will show on screen but won't print.
13885 * @param $v (string) visibility mode. Legal values are: all, print, screen or view.
13886 * @public
13887 * @since 3.0.000 (2008-03-27)
13888 */
13889 public function setVisibility($v) {
13890 if ($this->state != 2) {
13891 return;
13892 }
13893 $this->endLayer();
13894 switch($v) {
13895 case 'print': {
13896 $this->startLayer('Print', true, false);
13897 break;
13898 }
13899 case 'view':
13900 case 'screen': {
13901 $this->startLayer('View', false, true);
13902 break;
13903 }
13904 case 'all': {
13905 $this->_out('');
13906 break;
13907 }
13908 default: {
13909 $this->Error('Incorrect visibility: '.$v);
13910 break;
13911 }
13912 }
13913 }
13914
13915 /**
13916 * Add transparency parameters to the current extgstate
13917 * @param $parms (array) parameters
13918 * @return the number of extgstates
13919 * @protected
13920 * @since 3.0.000 (2008-03-27)
13921 */
13922 protected function addExtGState($parms) {
13923 if ($this->pdfa_mode) {
13924 // transparencies are not allowed in PDF/A mode
13925 return;
13926 }
13927 // check if this ExtGState already exist
13928 foreach ($this->extgstates as $i => $ext) {
13929 if ($ext['parms'] == $parms) {
13930 if ($this->inxobj) {
13931 // we are inside an XObject template
13932 $this->xobjects[$this->xobjid]['extgstates'][$i] = $ext;
13933 }
13934 // return reference to existing ExtGState
13935 return $i;
13936 }
13937 }
13938 $n = (count($this->extgstates) + 1);
13939 $this->extgstates[$n] = array('parms' => $parms);
13940 if ($this->inxobj) {
13941 // we are inside an XObject template
13942 $this->xobjects[$this->xobjid]['extgstates'][$n] = $this->extgstates[$n];
13943 }
13944 return $n;
13945 }
13946
13947 /**
13948 * Add an extgstate
13949 * @param $gs (array) extgstate
13950 * @protected
13951 * @since 3.0.000 (2008-03-27)
13952 */
13953 protected function setExtGState($gs) {
13954 if ($this->pdfa_mode OR ($this->state != 2)) {
13955 // transparency is not allowed in PDF/A mode
13956 return;
13957 }
13958 $this->_out(sprintf('/GS%d gs', $gs));
13959 }
13960
13961 /**
13962 * Put extgstates for object transparency
13963 * @protected
13964 * @since 3.0.000 (2008-03-27)
13965 */
13966 protected function _putextgstates() {
13967 foreach ($this->extgstates as $i => $ext) {
13968 $this->extgstates[$i]['n'] = $this->_newobj();
13969 $out = '<< /Type /ExtGState';
13970 foreach ($ext['parms'] as $k => $v) {
13971 if (is_float($v)) {
13972 $v = sprintf('%F', $v);
13973 } elseif ($v === true) {
13974 $v = 'true';
13975 } elseif ($v === false) {
13976 $v = 'false';
13977 }
13978 $out .= ' /'.$k.' '.$v;
13979 }
13980 $out .= ' >>';
13981 $out .= "\n".'endobj';
13982 $this->_out($out);
13983 }
13984 }
13985
13986 /**
13987 * Set overprint mode for stroking (OP) and non-stroking (op) painting operations.
13988 * (Check the "Entries in a Graphics State Parameter Dictionary" on PDF 32000-1:2008).
13989 * @param $stroking (boolean) If true apply overprint for stroking operations.
13990 * @param $nonstroking (boolean) If true apply overprint for painting operations other than stroking.
13991 * @param $mode (integer) Overprint mode: (0 = each source colour component value replaces the value previously painted for the corresponding device colorant; 1 = a tint value of 0.0 for a source colour component shall leave the corresponding component of the previously painted colour unchanged).
13992 * @public
13993 * @since 5.9.152 (2012-03-23)
13994 */
13995 public function setOverprint($stroking=true, $nonstroking='', $mode=0) {
13996 if ($this->state != 2) {
13997 return;
13998 }
13999 $stroking = $stroking ? true : false;
14000 if (TCPDF_STATIC::empty_string($nonstroking)) {
14001 // default value if not set
14002 $nonstroking = $stroking;
14003 } else {
14004 $nonstroking = $nonstroking ? true : false;
14005 }
14006 if (($mode != 0) AND ($mode != 1)) {
14007 $mode = 0;
14008 }
14009 $this->overprint = array('OP' => $stroking, 'op' => $nonstroking, 'OPM' => $mode);
14010 $gs = $this->addExtGState($this->overprint);
14011 $this->setExtGState($gs);
14012 }
14013
14014 /**
14015 * Get the overprint mode array (OP, op, OPM).
14016 * (Check the "Entries in a Graphics State Parameter Dictionary" on PDF 32000-1:2008).
14017 * @return array.
14018 * @public
14019 * @since 5.9.152 (2012-03-23)
14020 */
14021 public function getOverprint() {
14022 return $this->overprint;
14023 }
14024
14025 /**
14026 * Set alpha for stroking (CA) and non-stroking (ca) operations.
14027 * @param $stroking (float) Alpha value for stroking operations: real value from 0 (transparent) to 1 (opaque).
14028 * @param $bm (string) blend mode, one of the following: Normal, Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, ColorBurn, HardLight, SoftLight, Difference, Exclusion, Hue, Saturation, Color, Luminosity
14029 * @param $nonstroking (float) Alpha value for non-stroking operations: real value from 0 (transparent) to 1 (opaque).
14030 * @param $ais (boolean)
14031 * @public
14032 * @since 3.0.000 (2008-03-27)
14033 */
14034 public function setAlpha($stroking=1, $bm='Normal', $nonstroking='', $ais=false) {
14035 if ($this->pdfa_mode) {
14036 // transparency is not allowed in PDF/A mode
14037 return;
14038 }
14039 $stroking = floatval($stroking);
14040 if (TCPDF_STATIC::empty_string($nonstroking)) {
14041 // default value if not set
14042 $nonstroking = $stroking;
14043 } else {
14044 $nonstroking = floatval($nonstroking);
14045 }
14046 if ($bm[0] == '/') {
14047 // remove trailing slash
14048 $bm = substr($bm, 1);
14049 }
14050 if (!in_array($bm, array('Normal', 'Multiply', 'Screen', 'Overlay', 'Darken', 'Lighten', 'ColorDodge', 'ColorBurn', 'HardLight', 'SoftLight', 'Difference', 'Exclusion', 'Hue', 'Saturation', 'Color', 'Luminosity'))) {
14051 $bm = 'Normal';
14052 }
14053 $ais = $ais ? true : false;
14054 $this->alpha = array('CA' => $stroking, 'ca' => $nonstroking, 'BM' => '/'.$bm, 'AIS' => $ais);
14055 $gs = $this->addExtGState($this->alpha);
14056 $this->setExtGState($gs);
14057 }
14058
14059 /**
14060 * Get the alpha mode array (CA, ca, BM, AIS).
14061 * (Check the "Entries in a Graphics State Parameter Dictionary" on PDF 32000-1:2008).
14062 * @return array.
14063 * @public
14064 * @since 5.9.152 (2012-03-23)
14065 */
14066 public function getAlpha() {
14067 return $this->alpha;
14068 }
14069
14070 /**
14071 * Set the default JPEG compression quality (1-100)
14072 * @param $quality (int) JPEG quality, integer between 1 and 100
14073 * @public
14074 * @since 3.0.000 (2008-03-27)
14075 */
14076 public function setJPEGQuality($quality) {
14077 if (($quality < 1) OR ($quality > 100)) {
14078 $quality = 75;
14079 }
14080 $this->jpeg_quality = intval($quality);
14081 }
14082
14083 /**
14084 * Set the default number of columns in a row for HTML tables.
14085 * @param $cols (int) number of columns
14086 * @public
14087 * @since 3.0.014 (2008-06-04)
14088 */
14089 public function setDefaultTableColumns($cols=4) {
14090 $this->default_table_columns = intval($cols);
14091 }
14092
14093 /**
14094 * Set the height of the cell (line height) respect the font height.
14095 * @param $h (int) cell proportion respect font height (typical value = 1.25).
14096 * @public
14097 * @since 3.0.014 (2008-06-04)
14098 */
14099 public function setCellHeightRatio($h) {
14100 $this->cell_height_ratio = $h;
14101 }
14102
14103 /**
14104 * return the height of cell repect font height.
14105 * @public
14106 * @since 4.0.012 (2008-07-24)
14107 */
14108 public function getCellHeightRatio() {
14109 return $this->cell_height_ratio;
14110 }
14111
14112 /**
14113 * Set the PDF version (check PDF reference for valid values).
14114 * @param $version (string) PDF document version.
14115 * @public
14116 * @since 3.1.000 (2008-06-09)
14117 */
14118 public function setPDFVersion($version='1.7') {
14119 if ($this->pdfa_mode) {
14120 // PDF/A mode
14121 $this->PDFVersion = '1.4';
14122 } else {
14123 $this->PDFVersion = $version;
14124 }
14125 }
14126
14127 /**
14128 * Set the viewer preferences dictionary controlling the way the document is to be presented on the screen or in print.
14129 * (see Section 8.1 of PDF reference, "Viewer Preferences").
14130 * <ul><li>HideToolbar boolean (Optional) A flag specifying whether to hide the viewer application's tool bars when the document is active. Default value: false.</li><li>HideMenubar boolean (Optional) A flag specifying whether to hide the viewer application's menu bar when the document is active. Default value: false.</li><li>HideWindowUI boolean (Optional) A flag specifying whether to hide user interface elements in the document's window (such as scroll bars and navigation controls), leaving only the document's contents displayed. Default value: false.</li><li>FitWindow boolean (Optional) A flag specifying whether to resize the document's window to fit the size of the first displayed page. Default value: false.</li><li>CenterWindow boolean (Optional) A flag specifying whether to position the document's window in the center of the screen. Default value: false.</li><li>DisplayDocTitle boolean (Optional; PDF 1.4) A flag specifying whether the window's title bar should display the document title taken from the Title entry of the document information dictionary (see Section 10.2.1, "Document Information Dictionary"). If false, the title bar should instead display the name of the PDF file containing the document. Default value: false.</li><li>NonFullScreenPageMode name (Optional) The document's page mode, specifying how to display the document on exiting full-screen mode:<ul><li>UseNone Neither document outline nor thumbnail images visible</li><li>UseOutlines Document outline visible</li><li>UseThumbs Thumbnail images visible</li><li>UseOC Optional content group panel visible</li></ul>This entry is meaningful only if the value of the PageMode entry in the catalog dictionary (see Section 3.6.1, "Document Catalog") is FullScreen; it is ignored otherwise. Default value: UseNone.</li><li>ViewArea name (Optional; PDF 1.4) The name of the page boundary representing the area of a page to be displayed when viewing the document on the screen. Valid values are (see Section 10.10.1, "Page Boundaries").:<ul><li>MediaBox</li><li>CropBox (default)</li><li>BleedBox</li><li>TrimBox</li><li>ArtBox</li></ul></li><li>ViewClip name (Optional; PDF 1.4) The name of the page boundary to which the contents of a page are to be clipped when viewing the document on the screen. Valid values are (see Section 10.10.1, "Page Boundaries").:<ul><li>MediaBox</li><li>CropBox (default)</li><li>BleedBox</li><li>TrimBox</li><li>ArtBox</li></ul></li><li>PrintArea name (Optional; PDF 1.4) The name of the page boundary representing the area of a page to be rendered when printing the document. Valid values are (see Section 10.10.1, "Page Boundaries").:<ul><li>MediaBox</li><li>CropBox (default)</li><li>BleedBox</li><li>TrimBox</li><li>ArtBox</li></ul></li><li>PrintClip name (Optional; PDF 1.4) The name of the page boundary to which the contents of a page are to be clipped when printing the document. Valid values are (see Section 10.10.1, "Page Boundaries").:<ul><li>MediaBox</li><li>CropBox (default)</li><li>BleedBox</li><li>TrimBox</li><li>ArtBox</li></ul></li><li>PrintScaling name (Optional; PDF 1.6) The page scaling option to be selected when a print dialog is displayed for this document. Valid values are: <ul><li>None, which indicates that the print dialog should reflect no page scaling</li><li>AppDefault (default), which indicates that applications should use the current print scaling</li></ul></li><li>Duplex name (Optional; PDF 1.7) The paper handling option to use when printing the file from the print dialog. The following values are valid:<ul><li>Simplex - Print single-sided</li><li>DuplexFlipShortEdge - Duplex and flip on the short edge of the sheet</li><li>DuplexFlipLongEdge - Duplex and flip on the long edge of the sheet</li></ul>Default value: none</li><li>PickTrayByPDFSize boolean (Optional; PDF 1.7) A flag specifying whether the PDF page size is used to select the input paper tray. This setting influences only the preset values used to populate the print dialog presented by a PDF viewer application. If PickTrayByPDFSize is true, the check box in the print dialog associated with input paper tray is checked. Note: This setting has no effect on Mac OS systems, which do not provide the ability to pick the input tray by size.</li><li>PrintPageRange array (Optional; PDF 1.7) The page numbers used to initialize the print dialog box when the file is printed. The first page of the PDF file is denoted by 1. Each pair consists of the first and last pages in the sub-range. An odd number of integers causes this entry to be ignored. Negative numbers cause the entire array to be ignored. Default value: as defined by PDF viewer application</li><li>NumCopies integer (Optional; PDF 1.7) The number of copies to be printed when the print dialog is opened for this file. Supported values are the integers 2 through 5. Values outside this range are ignored. Default value: as defined by PDF viewer application, but typically 1</li></ul>
14131 * @param $preferences (array) array of options.
14132 * @author Nicola Asuni
14133 * @public
14134 * @since 3.1.000 (2008-06-09)
14135 */
14136 public function setViewerPreferences($preferences) {
14137 $this->viewer_preferences = $preferences;
14138 }
14139
14140 /**
14141 * Paints color transition registration bars
14142 * @param $x (float) abscissa of the top left corner of the rectangle.
14143 * @param $y (float) ordinate of the top left corner of the rectangle.
14144 * @param $w (float) width of the rectangle.
14145 * @param $h (float) height of the rectangle.
14146 * @param $transition (boolean) if true prints tcolor transitions to white.
14147 * @param $vertical (boolean) if true prints bar vertically.
14148 * @param $colors (string) colors to print separated by comma. Valid values are: A,W,R,G,B,C,M,Y,K,RGB,CMYK,ALL,ALLSPOT,<SPOT_COLOR_NAME>. Where: A = grayscale black, W = grayscale white, R = RGB red, G RGB green, B RGB blue, C = CMYK cyan, M = CMYK magenta, Y = CMYK yellow, K = CMYK key/black, RGB = RGB registration color, CMYK = CMYK registration color, ALL = Spot registration color, ALLSPOT = print all defined spot colors, <SPOT_COLOR_NAME> = name of the spot color to print.
14149 * @author Nicola Asuni
14150 * @since 4.9.000 (2010-03-26)
14151 * @public
14152 */
14153 public function colorRegistrationBar($x, $y, $w, $h, $transition=true, $vertical=false, $colors='A,R,G,B,C,M,Y,K') {
14154 if (strpos($colors, 'ALLSPOT') !== false) {
14155 // expand spot colors
14156 $spot_colors = '';
14157 foreach ($this->spot_colors as $spot_color_name => $v) {
14158 $spot_colors .= ','.$spot_color_name;
14159 }
14160 if (!empty($spot_colors)) {
14161 $spot_colors = substr($spot_colors, 1);
14162 $colors = str_replace('ALLSPOT', $spot_colors, $colors);
14163 } else {
14164 $colors = str_replace('ALLSPOT', 'NONE', $colors);
14165 }
14166 }
14167 $bars = explode(',', $colors);
14168 $numbars = count($bars); // number of bars to print
14169 if ($numbars <= 0) {
14170 return;
14171 }
14172 // set bar measures
14173 if ($vertical) {
14174 $coords = array(0, 0, 0, 1);
14175 $wb = $w / $numbars; // bar width
14176 $hb = $h; // bar height
14177 $xd = $wb; // delta x
14178 $yd = 0; // delta y
14179 } else {
14180 $coords = array(1, 0, 0, 0);
14181 $wb = $w; // bar width
14182 $hb = $h / $numbars; // bar height
14183 $xd = 0; // delta x
14184 $yd = $hb; // delta y
14185 }
14186 $xb = $x;
14187 $yb = $y;
14188 foreach ($bars as $col) {
14189 switch ($col) {
14190 // set transition colors
14191 case 'A': { // BLACK (GRAYSCALE)
14192 $col_a = array(255);
14193 $col_b = array(0);
14194 break;
14195 }
14196 case 'W': { // WHITE (GRAYSCALE)
14197 $col_a = array(0);
14198 $col_b = array(255);
14199 break;
14200 }
14201 case 'R': { // RED (RGB)
14202 $col_a = array(255,255,255);
14203 $col_b = array(255,0,0);
14204 break;
14205 }
14206 case 'G': { // GREEN (RGB)
14207 $col_a = array(255,255,255);
14208 $col_b = array(0,255,0);
14209 break;
14210 }
14211 case 'B': { // BLUE (RGB)
14212 $col_a = array(255,255,255);
14213 $col_b = array(0,0,255);
14214 break;
14215 }
14216 case 'C': { // CYAN (CMYK)
14217 $col_a = array(0,0,0,0);
14218 $col_b = array(100,0,0,0);
14219 break;
14220 }
14221 case 'M': { // MAGENTA (CMYK)
14222 $col_a = array(0,0,0,0);
14223 $col_b = array(0,100,0,0);
14224 break;
14225 }
14226 case 'Y': { // YELLOW (CMYK)
14227 $col_a = array(0,0,0,0);
14228 $col_b = array(0,0,100,0);
14229 break;
14230 }
14231 case 'K': { // KEY - BLACK (CMYK)
14232 $col_a = array(0,0,0,0);
14233 $col_b = array(0,0,0,100);
14234 break;
14235 }
14236 case 'RGB': { // BLACK REGISTRATION (RGB)
14237 $col_a = array(255,255,255);
14238 $col_b = array(0,0,0);
14239 break;
14240 }
14241 case 'CMYK': { // BLACK REGISTRATION (CMYK)
14242 $col_a = array(0,0,0,0);
14243 $col_b = array(100,100,100,100);
14244 break;
14245 }
14246 case 'ALL': { // SPOT COLOR REGISTRATION
14247 $col_a = array(0,0,0,0,'None');
14248 $col_b = array(100,100,100,100,'All');
14249 break;
14250 }
14251 case 'NONE': { // SKIP THIS COLOR
14252 $col_a = array(0,0,0,0,'None');
14253 $col_b = array(0,0,0,0,'None');
14254 break;
14255 }
14256 default: { // SPECIFIC SPOT COLOR NAME
14257 $col_a = array(0,0,0,0,'None');
14258 $col_b = TCPDF_COLORS::getSpotColor($col, $this->spot_colors);
14259 if ($col_b === false) {
14260 // in case of error defaults to the registration color
14261 $col_b = array(100,100,100,100,'All');
14262 }
14263 break;
14264 }
14265 }
14266 if ($col != 'NONE') {
14267 if ($transition) {
14268 // color gradient
14269 $this->LinearGradient($xb, $yb, $wb, $hb, $col_a, $col_b, $coords);
14270 } else {
14271 $this->SetFillColorArray($col_b);
14272 // colored rectangle
14273 $this->Rect($xb, $yb, $wb, $hb, 'F', array());
14274 }
14275 $xb += $xd;
14276 $yb += $yd;
14277 }
14278 }
14279 }
14280
14281 /**
14282 * Paints crop marks.
14283 * @param $x (float) abscissa of the crop mark center.
14284 * @param $y (float) ordinate of the crop mark center.
14285 * @param $w (float) width of the crop mark.
14286 * @param $h (float) height of the crop mark.
14287 * @param $type (string) type of crop mark, one symbol per type separated by comma: T = TOP, F = BOTTOM, L = LEFT, R = RIGHT, TL = A = TOP-LEFT, TR = B = TOP-RIGHT, BL = C = BOTTOM-LEFT, BR = D = BOTTOM-RIGHT.
14288 * @param $color (array) crop mark color (default spot registration color).
14289 * @author Nicola Asuni
14290 * @since 4.9.000 (2010-03-26)
14291 * @public
14292 */
14293 public function cropMark($x, $y, $w, $h, $type='T,R,B,L', $color=array(100,100,100,100,'All')) {
14294 $this->SetLineStyle(array('width' => (0.5 / $this->k), 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => $color));
14295 $type = strtoupper($type);
14296 $type = preg_replace('/[^A-Z\-\,]*/', '', $type);
14297 // split type in single components
14298 $type = str_replace('-', ',', $type);
14299 $type = str_replace('TL', 'T,L', $type);
14300 $type = str_replace('TR', 'T,R', $type);
14301 $type = str_replace('BL', 'F,L', $type);
14302 $type = str_replace('BR', 'F,R', $type);
14303 $type = str_replace('A', 'T,L', $type);
14304 $type = str_replace('B', 'T,R', $type);
14305 $type = str_replace('T,RO', 'BO', $type);
14306 $type = str_replace('C', 'F,L', $type);
14307 $type = str_replace('D', 'F,R', $type);
14308 $crops = explode(',', strtoupper($type));
14309 // remove duplicates
14310 $crops = array_unique($crops);
14311 $dw = ($w / 4); // horizontal space to leave before the intersection point
14312 $dh = ($h / 4); // vertical space to leave before the intersection point
14313 foreach ($crops as $crop) {
14314 switch ($crop) {
14315 case 'T':
14316 case 'TOP': {
14317 $x1 = $x;
14318 $y1 = ($y - $h);
14319 $x2 = $x;
14320 $y2 = ($y - $dh);
14321 break;
14322 }
14323 case 'F':
14324 case 'BOTTOM': {
14325 $x1 = $x;
14326 $y1 = ($y + $dh);
14327 $x2 = $x;
14328 $y2 = ($y + $h);
14329 break;
14330 }
14331 case 'L':
14332 case 'LEFT': {
14333 $x1 = ($x - $w);
14334 $y1 = $y;
14335 $x2 = ($x - $dw);
14336 $y2 = $y;
14337 break;
14338 }
14339 case 'R':
14340 case 'RIGHT': {
14341 $x1 = ($x + $dw);
14342 $y1 = $y;
14343 $x2 = ($x + $w);
14344 $y2 = $y;
14345 break;
14346 }
14347 }
14348 $this->Line($x1, $y1, $x2, $y2);
14349 }
14350 }
14351
14352 /**
14353 * Paints a registration mark
14354 * @param $x (float) abscissa of the registration mark center.
14355 * @param $y (float) ordinate of the registration mark center.
14356 * @param $r (float) radius of the crop mark.
14357 * @param $double (boolean) if true print two concentric crop marks.
14358 * @param $cola (array) crop mark color (default spot registration color 'All').
14359 * @param $colb (array) second crop mark color (default spot registration color 'None').
14360 * @author Nicola Asuni
14361 * @since 4.9.000 (2010-03-26)
14362 * @public
14363 */
14364 public function registrationMark($x, $y, $r, $double=false, $cola=array(100,100,100,100,'All'), $colb=array(0,0,0,0,'None')) {
14365 $line_style = array('width' => max((0.5 / $this->k),($r / 30)), 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => $cola);
14366 $this->SetFillColorArray($cola);
14367 $this->PieSector($x, $y, $r, 90, 180, 'F');
14368 $this->PieSector($x, $y, $r, 270, 360, 'F');
14369 $this->Circle($x, $y, $r, 0, 360, 'C', $line_style, array(), 8);
14370 if ($double) {
14371 $ri = $r * 0.5;
14372 $this->SetFillColorArray($colb);
14373 $this->PieSector($x, $y, $ri, 90, 180, 'F');
14374 $this->PieSector($x, $y, $ri, 270, 360, 'F');
14375 $this->SetFillColorArray($cola);
14376 $this->PieSector($x, $y, $ri, 0, 90, 'F');
14377 $this->PieSector($x, $y, $ri, 180, 270, 'F');
14378 $this->Circle($x, $y, $ri, 0, 360, 'C', $line_style, array(), 8);
14379 }
14380 }
14381
14382 /**
14383 * Paints a CMYK registration mark
14384 * @param $x (float) abscissa of the registration mark center.
14385 * @param $y (float) ordinate of the registration mark center.
14386 * @param $r (float) radius of the crop mark.
14387 * @author Nicola Asuni
14388 * @since 6.0.038 (2013-09-30)
14389 * @public
14390 */
14391 public function registrationMarkCMYK($x, $y, $r) {
14392 // line width
14393 $lw = max((0.5 / $this->k),($r / 8));
14394 // internal radius
14395 $ri = ($r * 0.6);
14396 // external radius
14397 $re = ($r * 1.3);
14398 // Cyan
14399 $this->SetFillColorArray(array(100,0,0,0));
14400 $this->PieSector($x, $y, $ri, 270, 360, 'F');
14401 // Magenta
14402 $this->SetFillColorArray(array(0,100,0,0));
14403 $this->PieSector($x, $y, $ri, 0, 90, 'F');
14404 // Yellow
14405 $this->SetFillColorArray(array(0,0,100,0));
14406 $this->PieSector($x, $y, $ri, 90, 180, 'F');
14407 // Key - black
14408 $this->SetFillColorArray(array(0,0,0,100));
14409 $this->PieSector($x, $y, $ri, 180, 270, 'F');
14410 // registration color
14411 $line_style = array('width' => $lw, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(100,100,100,100,'All'));
14412 $this->SetFillColorArray(array(100,100,100,100,'All'));
14413 // external circle
14414 $this->Circle($x, $y, $r, 0, 360, 'C', $line_style, array(), 8);
14415 // cross lines
14416 $this->Line($x, ($y - $re), $x, ($y - $ri));
14417 $this->Line($x, ($y + $ri), $x, ($y + $re));
14418 $this->Line(($x - $re), $y, ($x - $ri), $y);
14419 $this->Line(($x + $ri), $y, ($x + $re), $y);
14420 }
14421
14422 /**
14423 * Paints a linear colour gradient.
14424 * @param $x (float) abscissa of the top left corner of the rectangle.
14425 * @param $y (float) ordinate of the top left corner of the rectangle.
14426 * @param $w (float) width of the rectangle.
14427 * @param $h (float) height of the rectangle.
14428 * @param $col1 (array) first color (Grayscale, RGB or CMYK components).
14429 * @param $col2 (array) second color (Grayscale, RGB or CMYK components).
14430 * @param $coords (array) array of the form (x1, y1, x2, y2) which defines the gradient vector (see linear_gradient_coords.jpg). The default value is from left to right (x1=0, y1=0, x2=1, y2=0).
14431 * @author Andreas W\FCrmser, Nicola Asuni
14432 * @since 3.1.000 (2008-06-09)
14433 * @public
14434 */
14435 public function LinearGradient($x, $y, $w, $h, $col1=array(), $col2=array(), $coords=array(0,0,1,0)) {
14436 $this->Clip($x, $y, $w, $h);
14437 $this->Gradient(2, $coords, array(array('color' => $col1, 'offset' => 0, 'exponent' => 1), array('color' => $col2, 'offset' => 1, 'exponent' => 1)), array(), false);
14438 }
14439
14440 /**
14441 * Paints a radial colour gradient.
14442 * @param $x (float) abscissa of the top left corner of the rectangle.
14443 * @param $y (float) ordinate of the top left corner of the rectangle.
14444 * @param $w (float) width of the rectangle.
14445 * @param $h (float) height of the rectangle.
14446 * @param $col1 (array) first color (Grayscale, RGB or CMYK components).
14447 * @param $col2 (array) second color (Grayscale, RGB or CMYK components).
14448 * @param $coords (array) array of the form (fx, fy, cx, cy, r) where (fx, fy) is the starting point of the gradient with color1, (cx, cy) is the center of the circle with color2, and r is the radius of the circle (see radial_gradient_coords.jpg). (fx, fy) should be inside the circle, otherwise some areas will not be defined.
14449 * @author Andreas W\FCrmser, Nicola Asuni
14450 * @since 3.1.000 (2008-06-09)
14451 * @public
14452 */
14453 public function RadialGradient($x, $y, $w, $h, $col1=array(), $col2=array(), $coords=array(0.5,0.5,0.5,0.5,1)) {
14454 $this->Clip($x, $y, $w, $h);
14455 $this->Gradient(3, $coords, array(array('color' => $col1, 'offset' => 0, 'exponent' => 1), array('color' => $col2, 'offset' => 1, 'exponent' => 1)), array(), false);
14456 }
14457
14458 /**
14459 * Paints a coons patch mesh.
14460 * @param $x (float) abscissa of the top left corner of the rectangle.
14461 * @param $y (float) ordinate of the top left corner of the rectangle.
14462 * @param $w (float) width of the rectangle.
14463 * @param $h (float) height of the rectangle.
14464 * @param $col1 (array) first color (lower left corner) (RGB components).
14465 * @param $col2 (array) second color (lower right corner) (RGB components).
14466 * @param $col3 (array) third color (upper right corner) (RGB components).
14467 * @param $col4 (array) fourth color (upper left corner) (RGB components).
14468 * @param $coords (array) <ul><li>for one patch mesh: array(float x1, float y1, .... float x12, float y12): 12 pairs of coordinates (normally from 0 to 1) which specify the Bezier control points that define the patch. First pair is the lower left edge point, next is its right control point (control point 2). Then the other points are defined in the order: control point 1, edge point, control point 2 going counter-clockwise around the patch. Last (x12, y12) is the first edge point's left control point (control point 1).</li><li>for two or more patch meshes: array[number of patches]: arrays with the following keys for each patch: f: where to put that patch (0 = first patch, 1, 2, 3 = right, top and left of precedent patch - I didn't figure this out completely - just try and error ;-) points: 12 pairs of coordinates of the Bezier control points as above for the first patch, 8 pairs of coordinates for the following patches, ignoring the coordinates already defined by the precedent patch (I also didn't figure out the order of these - also: try and see what's happening) colors: must be 4 colors for the first patch, 2 colors for the following patches</li></ul>
14469 * @param $coords_min (array) minimum value used by the coordinates. If a coordinate's value is smaller than this it will be cut to coords_min. default: 0
14470 * @param $coords_max (array) maximum value used by the coordinates. If a coordinate's value is greater than this it will be cut to coords_max. default: 1
14471 * @param $antialias (boolean) A flag indicating whether to filter the shading function to prevent aliasing artifacts.
14472 * @author Andreas W\FCrmser, Nicola Asuni
14473 * @since 3.1.000 (2008-06-09)
14474 * @public
14475 */
14476 public function CoonsPatchMesh($x, $y, $w, $h, $col1=array(), $col2=array(), $col3=array(), $col4=array(), $coords=array(0.00,0.0,0.33,0.00,0.67,0.00,1.00,0.00,1.00,0.33,1.00,0.67,1.00,1.00,0.67,1.00,0.33,1.00,0.00,1.00,0.00,0.67,0.00,0.33), $coords_min=0, $coords_max=1, $antialias=false) {
14477 if ($this->pdfa_mode OR ($this->state != 2)) {
14478 return;
14479 }
14480 $this->Clip($x, $y, $w, $h);
14481 $n = count($this->gradients) + 1;
14482 $this->gradients[$n] = array();
14483 $this->gradients[$n]['type'] = 6; //coons patch mesh
14484 $this->gradients[$n]['coords'] = array();
14485 $this->gradients[$n]['antialias'] = $antialias;
14486 $this->gradients[$n]['colors'] = array();
14487 $this->gradients[$n]['transparency'] = false;
14488 //check the coords array if it is the simple array or the multi patch array
14489 if (!isset($coords[0]['f'])) {
14490 //simple array -> convert to multi patch array
14491 if (!isset($col1[1])) {
14492 $col1[1] = $col1[2] = $col1[0];
14493 }
14494 if (!isset($col2[1])) {
14495 $col2[1] = $col2[2] = $col2[0];
14496 }
14497 if (!isset($col3[1])) {
14498 $col3[1] = $col3[2] = $col3[0];
14499 }
14500 if (!isset($col4[1])) {
14501 $col4[1] = $col4[2] = $col4[0];
14502 }
14503 $patch_array[0]['f'] = 0;
14504 $patch_array[0]['points'] = $coords;
14505 $patch_array[0]['colors'][0]['r'] = $col1[0];
14506 $patch_array[0]['colors'][0]['g'] = $col1[1];
14507 $patch_array[0]['colors'][0]['b'] = $col1[2];
14508 $patch_array[0]['colors'][1]['r'] = $col2[0];
14509 $patch_array[0]['colors'][1]['g'] = $col2[1];
14510 $patch_array[0]['colors'][1]['b'] = $col2[2];
14511 $patch_array[0]['colors'][2]['r'] = $col3[0];
14512 $patch_array[0]['colors'][2]['g'] = $col3[1];
14513 $patch_array[0]['colors'][2]['b'] = $col3[2];
14514 $patch_array[0]['colors'][3]['r'] = $col4[0];
14515 $patch_array[0]['colors'][3]['g'] = $col4[1];
14516 $patch_array[0]['colors'][3]['b'] = $col4[2];
14517 } else {
14518 //multi patch array
14519 $patch_array = $coords;
14520 }
14521 $bpcd = 65535; //16 bits per coordinate
14522 //build the data stream
14523 $this->gradients[$n]['stream'] = '';
14524 $count_patch = count($patch_array);
14525 for ($i=0; $i < $count_patch; ++$i) {
14526 $this->gradients[$n]['stream'] .= chr($patch_array[$i]['f']); //start with the edge flag as 8 bit
14527 $count_points = count($patch_array[$i]['points']);
14528 for ($j=0; $j < $count_points; ++$j) {
14529 //each point as 16 bit
14530 $patch_array[$i]['points'][$j] = (($patch_array[$i]['points'][$j] - $coords_min) / ($coords_max - $coords_min)) * $bpcd;
14531 if ($patch_array[$i]['points'][$j] < 0) {
14532 $patch_array[$i]['points'][$j] = 0;
14533 }
14534 if ($patch_array[$i]['points'][$j] > $bpcd) {
14535 $patch_array[$i]['points'][$j] = $bpcd;
14536 }
14537 $this->gradients[$n]['stream'] .= chr(floor($patch_array[$i]['points'][$j] / 256));
14538 $this->gradients[$n]['stream'] .= chr(floor($patch_array[$i]['points'][$j] % 256));
14539 }
14540 $count_cols = count($patch_array[$i]['colors']);
14541 for ($j=0; $j < $count_cols; ++$j) {
14542 //each color component as 8 bit
14543 $this->gradients[$n]['stream'] .= chr($patch_array[$i]['colors'][$j]['r']);
14544 $this->gradients[$n]['stream'] .= chr($patch_array[$i]['colors'][$j]['g']);
14545 $this->gradients[$n]['stream'] .= chr($patch_array[$i]['colors'][$j]['b']);
14546 }
14547 }
14548 //paint the gradient
14549 $this->_out('/Sh'.$n.' sh');
14550 //restore previous Graphic State
14551 $this->_outRestoreGraphicsState();
14552 if ($this->inxobj) {
14553 // we are inside an XObject template
14554 $this->xobjects[$this->xobjid]['gradients'][$n] = $this->gradients[$n];
14555 }
14556 }
14557
14558 /**
14559 * Set a rectangular clipping area.
14560 * @param $x (float) abscissa of the top left corner of the rectangle (or top right corner for RTL mode).
14561 * @param $y (float) ordinate of the top left corner of the rectangle.
14562 * @param $w (float) width of the rectangle.
14563 * @param $h (float) height of the rectangle.
14564 * @author Andreas W\FCrmser, Nicola Asuni
14565 * @since 3.1.000 (2008-06-09)
14566 * @protected
14567 */
14568 protected function Clip($x, $y, $w, $h) {
14569 if ($this->state != 2) {
14570 return;
14571 }
14572 if ($this->rtl) {
14573 $x = $this->w - $x - $w;
14574 }
14575 //save current Graphic State
14576 $s = 'q';
14577 //set clipping area
14578 $s .= sprintf(' %F %F %F %F re W n', $x*$this->k, ($this->h-$y)*$this->k, $w*$this->k, -$h*$this->k);
14579 //set up transformation matrix for gradient
14580 $s .= sprintf(' %F 0 0 %F %F %F cm', $w*$this->k, $h*$this->k, $x*$this->k, ($this->h-($y+$h))*$this->k);
14581 $this->_out($s);
14582 }
14583
14584 /**
14585 * Output gradient.
14586 * @param $type (int) type of gradient (1 Function-based shading; 2 Axial shading; 3 Radial shading; 4 Free-form Gouraud-shaded triangle mesh; 5 Lattice-form Gouraud-shaded triangle mesh; 6 Coons patch mesh; 7 Tensor-product patch mesh). (Not all types are currently supported)
14587 * @param $coords (array) array of coordinates.
14588 * @param $stops (array) array gradient color components: color = array of GRAY, RGB or CMYK color components; offset = (0 to 1) represents a location along the gradient vector; exponent = exponent of the exponential interpolation function (default = 1).
14589 * @param $background (array) An array of colour components appropriate to the colour space, specifying a single background colour value.
14590 * @param $antialias (boolean) A flag indicating whether to filter the shading function to prevent aliasing artifacts.
14591 * @author Nicola Asuni
14592 * @since 3.1.000 (2008-06-09)
14593 * @public
14594 */
14595 public function Gradient($type, $coords, $stops, $background=array(), $antialias=false) {
14596 if ($this->pdfa_mode OR ($this->state != 2)) {
14597 return;
14598 }
14599 $n = count($this->gradients) + 1;
14600 $this->gradients[$n] = array();
14601 $this->gradients[$n]['type'] = $type;
14602 $this->gradients[$n]['coords'] = $coords;
14603 $this->gradients[$n]['antialias'] = $antialias;
14604 $this->gradients[$n]['colors'] = array();
14605 $this->gradients[$n]['transparency'] = false;
14606 // color space
14607 $numcolspace = count($stops[0]['color']);
14608 $bcolor = array_values($background);
14609 switch($numcolspace) {
14610 case 5: // SPOT
14611 case 4: { // CMYK
14612 $this->gradients[$n]['colspace'] = 'DeviceCMYK';
14613 if (!empty($background)) {
14614 $this->gradients[$n]['background'] = sprintf('%F %F %F %F', $bcolor[0]/100, $bcolor[1]/100, $bcolor[2]/100, $bcolor[3]/100);
14615 }
14616 break;
14617 }
14618 case 3: { // RGB
14619 $this->gradients[$n]['colspace'] = 'DeviceRGB';
14620 if (!empty($background)) {
14621 $this->gradients[$n]['background'] = sprintf('%F %F %F', $bcolor[0]/255, $bcolor[1]/255, $bcolor[2]/255);
14622 }
14623 break;
14624 }
14625 case 1: { // GRAY SCALE
14626 $this->gradients[$n]['colspace'] = 'DeviceGray';
14627 if (!empty($background)) {
14628 $this->gradients[$n]['background'] = sprintf('%F', $bcolor[0]/255);
14629 }
14630 break;
14631 }
14632 }
14633 $num_stops = count($stops);
14634 $last_stop_id = $num_stops - 1;
14635 foreach ($stops as $key => $stop) {
14636 $this->gradients[$n]['colors'][$key] = array();
14637 // offset represents a location along the gradient vector
14638 if (isset($stop['offset'])) {
14639 $this->gradients[$n]['colors'][$key]['offset'] = $stop['offset'];
14640 } else {
14641 if ($key == 0) {
14642 $this->gradients[$n]['colors'][$key]['offset'] = 0;
14643 } elseif ($key == $last_stop_id) {
14644 $this->gradients[$n]['colors'][$key]['offset'] = 1;
14645 } else {
14646 $offsetstep = (1 - $this->gradients[$n]['colors'][($key - 1)]['offset']) / ($num_stops - $key);
14647 $this->gradients[$n]['colors'][$key]['offset'] = $this->gradients[$n]['colors'][($key - 1)]['offset'] + $offsetstep;
14648 }
14649 }
14650 if (isset($stop['opacity'])) {
14651 $this->gradients[$n]['colors'][$key]['opacity'] = $stop['opacity'];
14652 if ((!$this->pdfa_mode) AND ($stop['opacity'] < 1)) {
14653 $this->gradients[$n]['transparency'] = true;
14654 }
14655 } else {
14656 $this->gradients[$n]['colors'][$key]['opacity'] = 1;
14657 }
14658 // exponent for the exponential interpolation function
14659 if (isset($stop['exponent'])) {
14660 $this->gradients[$n]['colors'][$key]['exponent'] = $stop['exponent'];
14661 } else {
14662 $this->gradients[$n]['colors'][$key]['exponent'] = 1;
14663 }
14664 // set colors
14665 $color = array_values($stop['color']);
14666 switch($numcolspace) {
14667 case 5: // SPOT
14668 case 4: { // CMYK
14669 $this->gradients[$n]['colors'][$key]['color'] = sprintf('%F %F %F %F', $color[0]/100, $color[1]/100, $color[2]/100, $color[3]/100);
14670 break;
14671 }
14672 case 3: { // RGB
14673 $this->gradients[$n]['colors'][$key]['color'] = sprintf('%F %F %F', $color[0]/255, $color[1]/255, $color[2]/255);
14674 break;
14675 }
14676 case 1: { // GRAY SCALE
14677 $this->gradients[$n]['colors'][$key]['color'] = sprintf('%F', $color[0]/255);
14678 break;
14679 }
14680 }
14681 }
14682 if ($this->gradients[$n]['transparency']) {
14683 // paint luminosity gradient
14684 $this->_out('/TGS'.$n.' gs');
14685 }
14686 //paint the gradient
14687 $this->_out('/Sh'.$n.' sh');
14688 //restore previous Graphic State
14689 $this->_outRestoreGraphicsState();
14690 if ($this->inxobj) {
14691 // we are inside an XObject template
14692 $this->xobjects[$this->xobjid]['gradients'][$n] = $this->gradients[$n];
14693 }
14694 }
14695
14696 /**
14697 * Output gradient shaders.
14698 * @author Nicola Asuni
14699 * @since 3.1.000 (2008-06-09)
14700 * @protected
14701 */
14702 function _putshaders() {
14703 if ($this->pdfa_mode) {
14704 return;
14705 }
14706 $idt = count($this->gradients); //index for transparency gradients
14707 foreach ($this->gradients as $id => $grad) {
14708 if (($grad['type'] == 2) OR ($grad['type'] == 3)) {
14709 $fc = $this->_newobj();
14710 $out = '<<';
14711 $out .= ' /FunctionType 3';
14712 $out .= ' /Domain [0 1]';
14713 $functions = '';
14714 $bounds = '';
14715 $encode = '';
14716 $i = 1;
14717 $num_cols = count($grad['colors']);
14718 $lastcols = $num_cols - 1;
14719 for ($i = 1; $i < $num_cols; ++$i) {
14720 $functions .= ($fc + $i).' 0 R ';
14721 if ($i < $lastcols) {
14722 $bounds .= sprintf('%F ', $grad['colors'][$i]['offset']);
14723 }
14724 $encode .= '0 1 ';
14725 }
14726 $out .= ' /Functions ['.trim($functions).']';
14727 $out .= ' /Bounds ['.trim($bounds).']';
14728 $out .= ' /Encode ['.trim($encode).']';
14729 $out .= ' >>';
14730 $out .= "\n".'endobj';
14731 $this->_out($out);
14732 for ($i = 1; $i < $num_cols; ++$i) {
14733 $this->_newobj();
14734 $out = '<<';
14735 $out .= ' /FunctionType 2';
14736 $out .= ' /Domain [0 1]';
14737 $out .= ' /C0 ['.$grad['colors'][($i - 1)]['color'].']';
14738 $out .= ' /C1 ['.$grad['colors'][$i]['color'].']';
14739 $out .= ' /N '.$grad['colors'][$i]['exponent'];
14740 $out .= ' >>';
14741 $out .= "\n".'endobj';
14742 $this->_out($out);
14743 }
14744 // set transparency fuctions
14745 if ($grad['transparency']) {
14746 $ft = $this->_newobj();
14747 $out = '<<';
14748 $out .= ' /FunctionType 3';
14749 $out .= ' /Domain [0 1]';
14750 $functions = '';
14751 $i = 1;
14752 $num_cols = count($grad['colors']);
14753 for ($i = 1; $i < $num_cols; ++$i) {
14754 $functions .= ($ft + $i).' 0 R ';
14755 }
14756 $out .= ' /Functions ['.trim($functions).']';
14757 $out .= ' /Bounds ['.trim($bounds).']';
14758 $out .= ' /Encode ['.trim($encode).']';
14759 $out .= ' >>';
14760 $out .= "\n".'endobj';
14761 $this->_out($out);
14762 for ($i = 1; $i < $num_cols; ++$i) {
14763 $this->_newobj();
14764 $out = '<<';
14765 $out .= ' /FunctionType 2';
14766 $out .= ' /Domain [0 1]';
14767 $out .= ' /C0 ['.$grad['colors'][($i - 1)]['opacity'].']';
14768 $out .= ' /C1 ['.$grad['colors'][$i]['opacity'].']';
14769 $out .= ' /N '.$grad['colors'][$i]['exponent'];
14770 $out .= ' >>';
14771 $out .= "\n".'endobj';
14772 $this->_out($out);
14773 }
14774 }
14775 }
14776 // set shading object
14777 $this->_newobj();
14778 $out = '<< /ShadingType '.$grad['type'];
14779 if (isset($grad['colspace'])) {
14780 $out .= ' /ColorSpace /'.$grad['colspace'];
14781 } else {
14782 $out .= ' /ColorSpace /DeviceRGB';
14783 }
14784 if (isset($grad['background']) AND !empty($grad['background'])) {
14785 $out .= ' /Background ['.$grad['background'].']';
14786 }
14787 if (isset($grad['antialias']) AND ($grad['antialias'] === true)) {
14788 $out .= ' /AntiAlias true';
14789 }
14790 if ($grad['type'] == 2) {
14791 $out .= ' '.sprintf('/Coords [%F %F %F %F]', $grad['coords'][0], $grad['coords'][1], $grad['coords'][2], $grad['coords'][3]);
14792 $out .= ' /Domain [0 1]';
14793 $out .= ' /Function '.$fc.' 0 R';
14794 $out .= ' /Extend [true true]';
14795 $out .= ' >>';
14796 } elseif ($grad['type'] == 3) {
14797 //x0, y0, r0, x1, y1, r1
14798 //at this this time radius of inner circle is 0
14799 $out .= ' '.sprintf('/Coords [%F %F 0 %F %F %F]', $grad['coords'][0], $grad['coords'][1], $grad['coords'][2], $grad['coords'][3], $grad['coords'][4]);
14800 $out .= ' /Domain [0 1]';
14801 $out .= ' /Function '.$fc.' 0 R';
14802 $out .= ' /Extend [true true]';
14803 $out .= ' >>';
14804 } elseif ($grad['type'] == 6) {
14805 $out .= ' /BitsPerCoordinate 16';
14806 $out .= ' /BitsPerComponent 8';
14807 $out .= ' /Decode[0 1 0 1 0 1 0 1 0 1]';
14808 $out .= ' /BitsPerFlag 8';
14809 $stream = $this->_getrawstream($grad['stream']);
14810 $out .= ' /Length '.strlen($stream);
14811 $out .= ' >>';
14812 $out .= ' stream'."\n".$stream."\n".'endstream';
14813 }
14814 $out .= "\n".'endobj';
14815 $this->_out($out);
14816 if ($grad['transparency']) {
14817 $shading_transparency = preg_replace('/\/ColorSpace \/[^\s]+/si', '/ColorSpace /DeviceGray', $out);
14818 $shading_transparency = preg_replace('/\/Function [0-9]+ /si', '/Function '.$ft.' ', $shading_transparency);
14819 }
14820 $this->gradients[$id]['id'] = $this->n;
14821 // set pattern object
14822 $this->_newobj();
14823 $out = '<< /Type /Pattern /PatternType 2';
14824 $out .= ' /Shading '.$this->gradients[$id]['id'].' 0 R';
14825 $out .= ' >>';
14826 $out .= "\n".'endobj';
14827 $this->_out($out);
14828 $this->gradients[$id]['pattern'] = $this->n;
14829 // set shading and pattern for transparency mask
14830 if ($grad['transparency']) {
14831 // luminosity pattern
14832 $idgs = $id + $idt;
14833 $this->_newobj();
14834 $this->_out($shading_transparency);
14835 $this->gradients[$idgs]['id'] = $this->n;
14836 $this->_newobj();
14837 $out = '<< /Type /Pattern /PatternType 2';
14838 $out .= ' /Shading '.$this->gradients[$idgs]['id'].' 0 R';
14839 $out .= ' >>';
14840 $out .= "\n".'endobj';
14841 $this->_out($out);
14842 $this->gradients[$idgs]['pattern'] = $this->n;
14843 // luminosity XObject
14844 $oid = $this->_newobj();
14845 $this->xobjects['LX'.$oid] = array('n' => $oid);
14846 $filter = '';
14847 $stream = 'q /a0 gs /Pattern cs /p'.$idgs.' scn 0 0 '.$this->wPt.' '.$this->hPt.' re f Q';
14848 if ($this->compress) {
14849 $filter = ' /Filter /FlateDecode';
14850 $stream = gzcompress($stream);
14851 }
14852 $stream = $this->_getrawstream($stream);
14853 $out = '<< /Type /XObject /Subtype /Form /FormType 1'.$filter;
14854 $out .= ' /Length '.strlen($stream);
14855 $rect = sprintf('%F %F', $this->wPt, $this->hPt);
14856 $out .= ' /BBox [0 0 '.$rect.']';
14857 $out .= ' /Group << /Type /Group /S /Transparency /CS /DeviceGray >>';
14858 $out .= ' /Resources <<';
14859 $out .= ' /ExtGState << /a0 << /ca 1 /CA 1 >> >>';
14860 $out .= ' /Pattern << /p'.$idgs.' '.$this->gradients[$idgs]['pattern'].' 0 R >>';
14861 $out .= ' >>';
14862 $out .= ' >> ';
14863 $out .= ' stream'."\n".$stream."\n".'endstream';
14864 $out .= "\n".'endobj';
14865 $this->_out($out);
14866 // SMask
14867 $this->_newobj();
14868 $out = '<< /Type /Mask /S /Luminosity /G '.($this->n - 1).' 0 R >>'."\n".'endobj';
14869 $this->_out($out);
14870 // ExtGState
14871 $this->_newobj();
14872 $out = '<< /Type /ExtGState /SMask '.($this->n - 1).' 0 R /AIS false >>'."\n".'endobj';
14873 $this->_out($out);
14874 $this->extgstates[] = array('n' => $this->n, 'name' => 'TGS'.$id);
14875 }
14876 }
14877 }
14878
14879 /**
14880 * Draw the sector of a circle.
14881 * It can be used for instance to render pie charts.
14882 * @param $xc (float) abscissa of the center.
14883 * @param $yc (float) ordinate of the center.
14884 * @param $r (float) radius.
14885 * @param $a (float) start angle (in degrees).
14886 * @param $b (float) end angle (in degrees).
14887 * @param $style (string) Style of rendering. See the getPathPaintOperator() function for more information.
14888 * @param $cw: (float) indicates whether to go clockwise (default: true).
14889 * @param $o: (float) origin of angles (0 for 3 o'clock, 90 for noon, 180 for 9 o'clock, 270 for 6 o'clock). Default: 90.
14890 * @author Maxime Delorme, Nicola Asuni
14891 * @since 3.1.000 (2008-06-09)
14892 * @public
14893 */
14894 public function PieSector($xc, $yc, $r, $a, $b, $style='FD', $cw=true, $o=90) {
14895 $this->PieSectorXY($xc, $yc, $r, $r, $a, $b, $style, $cw, $o);
14896 }
14897
14898 /**
14899 * Draw the sector of an ellipse.
14900 * It can be used for instance to render pie charts.
14901 * @param $xc (float) abscissa of the center.
14902 * @param $yc (float) ordinate of the center.
14903 * @param $rx (float) the x-axis radius.
14904 * @param $ry (float) the y-axis radius.
14905 * @param $a (float) start angle (in degrees).
14906 * @param $b (float) end angle (in degrees).
14907 * @param $style (string) Style of rendering. See the getPathPaintOperator() function for more information.
14908 * @param $cw: (float) indicates whether to go clockwise.
14909 * @param $o: (float) origin of angles (0 for 3 o'clock, 90 for noon, 180 for 9 o'clock, 270 for 6 o'clock).
14910 * @param $nc (integer) Number of curves used to draw a 90 degrees portion of arc.
14911 * @author Maxime Delorme, Nicola Asuni
14912 * @since 3.1.000 (2008-06-09)
14913 * @public
14914 */
14915 public function PieSectorXY($xc, $yc, $rx, $ry, $a, $b, $style='FD', $cw=false, $o=0, $nc=2) {
14916 if ($this->state != 2) {
14917 return;
14918 }
14919 if ($this->rtl) {
14920 $xc = ($this->w - $xc);
14921 }
14922 $op = TCPDF_STATIC::getPathPaintOperator($style);
14923 if ($op == 'f') {
14924 $line_style = array();
14925 }
14926 if ($cw) {
14927 $d = $b;
14928 $b = (360 - $a + $o);
14929 $a = (360 - $d + $o);
14930 } else {
14931 $b += $o;
14932 $a += $o;
14933 }
14934 $this->_outellipticalarc($xc, $yc, $rx, $ry, 0, $a, $b, true, $nc);
14935 $this->_out($op);
14936 }
14937
14938 /**
14939 * Embed vector-based Adobe Illustrator (AI) or AI-compatible EPS files.
14940 * NOTE: EPS is not yet fully implemented, use the setRasterizeVectorImages() method to enable/disable rasterization of vector images using ImageMagick library.
14941 * Only vector drawing is supported, not text or bitmap.
14942 * Although the script was successfully tested with various AI format versions, best results are probably achieved with files that were exported in the AI3 format (tested with Illustrator CS2, Freehand MX and Photoshop CS2).
14943 * @param $file (string) Name of the file containing the image or a '@' character followed by the EPS/AI data string.
14944 * @param $x (float) Abscissa of the upper-left corner.
14945 * @param $y (float) Ordinate of the upper-left corner.
14946 * @param $w (float) Width of the image in the page. If not specified or equal to zero, it is automatically calculated.
14947 * @param $h (float) Height of the image in the page. If not specified or equal to zero, it is automatically calculated.
14948 * @param $link (mixed) URL or identifier returned by AddLink().
14949 * @param $useBoundingBox (boolean) specifies whether to position the bounding box (true) or the complete canvas (false) at location (x,y). Default value is true.
14950 * @param $align (string) Indicates the alignment of the pointer next to image insertion relative to image height. The value can be:<ul><li>T: top-right for LTR or top-left for RTL</li><li>M: middle-right for LTR or middle-left for RTL</li><li>B: bottom-right for LTR or bottom-left for RTL</li><li>N: next line</li></ul>
14951 * @param $palign (string) Allows to center or align the image on the current line. Possible values are:<ul><li>L : left align</li><li>C : center</li><li>R : right align</li><li>'' : empty string : left for LTR or right for RTL</li></ul>
14952 * @param $border (mixed) Indicates if borders must be drawn around the cell. 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 - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0)))
14953 * @param $fitonpage (boolean) if true the image is resized to not exceed page dimensions.
14954 * @param $fixoutvals (boolean) if true remove values outside the bounding box.
14955 * @author Valentin Schmidt, Nicola Asuni
14956 * @since 3.1.000 (2008-06-09)
14957 * @public
14958 */
14959 public function ImageEps($file, $x='', $y='', $w=0, $h=0, $link='', $useBoundingBox=true, $align='', $palign='', $border=0, $fitonpage=false, $fixoutvals=false) {
14960 if ($this->state != 2) {
14961 return;
14962 }
14963 if ($this->rasterize_vector_images AND ($w > 0) AND ($h > 0)) {
14964 // convert EPS to raster image using GD or ImageMagick libraries
14965 return $this->Image($file, $x, $y, $w, $h, 'EPS', $link, $align, true, 300, $palign, false, false, $border, false, false, $fitonpage);
14966 }
14967 if ($x === '') {
14968 $x = $this->x;
14969 }
14970 if ($y === '') {
14971 $y = $this->y;
14972 }
14973 // check page for no-write regions and adapt page margins if necessary
14974 list($x, $y) = $this->checkPageRegions($h, $x, $y);
14975 $k = $this->k;
14976 if ($file[0] === '@') { // image from string
14977 $data = substr($file, 1);
14978 } else { // EPS/AI file
14979 $data = TCPDF_STATIC::fileGetContents($file);
14980 }
14981 if ($data === FALSE) {
14982 $this->Error('EPS file not found: '.$file);
14983 }
14984 $regs = array();
14985 // EPS/AI compatibility check (only checks files created by Adobe Illustrator!)
14986 preg_match("/%%Creator:([^\r\n]+)/", $data, $regs); # find Creator
14987 if (count($regs) > 1) {
14988 $version_str = trim($regs[1]); # e.g. "Adobe Illustrator(R) 8.0"
14989 if (strpos($version_str, 'Adobe Illustrator') !== false) {
14990 $versexp = explode(' ', $version_str);
14991 $version = (float)array_pop($versexp);
14992 if ($version >= 9) {
14993 $this->Error('This version of Adobe Illustrator file is not supported: '.$file);
14994 }
14995 }
14996 }
14997 // strip binary bytes in front of PS-header
14998 $start = strpos($data, '%!PS-Adobe');
14999 if ($start > 0) {
15000 $data = substr($data, $start);
15001 }
15002 // find BoundingBox params
15003 preg_match("/%%BoundingBox:([^\r\n]+)/", $data, $regs);
15004 if (count($regs) > 1) {
15005 list($x1, $y1, $x2, $y2) = explode(' ', trim($regs[1]));
15006 } else {
15007 $this->Error('No BoundingBox found in EPS/AI file: '.$file);
15008 }
15009 $start = strpos($data, '%%EndSetup');
15010 if ($start === false) {
15011 $start = strpos($data, '%%EndProlog');
15012 }
15013 if ($start === false) {
15014 $start = strpos($data, '%%BoundingBox');
15015 }
15016 $data = substr($data, $start);
15017 $end = strpos($data, '%%PageTrailer');
15018 if ($end===false) {
15019 $end = strpos($data, 'showpage');
15020 }
15021 if ($end) {
15022 $data = substr($data, 0, $end);
15023 }
15024 // calculate image width and height on document
15025 if (($w <= 0) AND ($h <= 0)) {
15026 $w = ($x2 - $x1) / $k;
15027 $h = ($y2 - $y1) / $k;
15028 } elseif ($w <= 0) {
15029 $w = ($x2-$x1) / $k * ($h / (($y2 - $y1) / $k));
15030 } elseif ($h <= 0) {
15031 $h = ($y2 - $y1) / $k * ($w / (($x2 - $x1) / $k));
15032 }
15033 // fit the image on available space
15034 list($w, $h, $x, $y) = $this->fitBlock($w, $h, $x, $y, $fitonpage);
15035 if ($this->rasterize_vector_images) {
15036 // convert EPS to raster image using GD or ImageMagick libraries
15037 return $this->Image($file, $x, $y, $w, $h, 'EPS', $link, $align, true, 300, $palign, false, false, $border, false, false, $fitonpage);
15038 }
15039 // set scaling factors
15040 $scale_x = $w / (($x2 - $x1) / $k);
15041 $scale_y = $h / (($y2 - $y1) / $k);
15042 // set alignment
15043 $this->img_rb_y = $y + $h;
15044 // set alignment
15045 if ($this->rtl) {
15046 if ($palign == 'L') {
15047 $ximg = $this->lMargin;
15048 } elseif ($palign == 'C') {
15049 $ximg = ($this->w + $this->lMargin - $this->rMargin - $w) / 2;
15050 } elseif ($palign == 'R') {
15051 $ximg = $this->w - $this->rMargin - $w;
15052 } else {
15053 $ximg = $x - $w;
15054 }
15055 $this->img_rb_x = $ximg;
15056 } else {
15057 if ($palign == 'L') {
15058 $ximg = $this->lMargin;
15059 } elseif ($palign == 'C') {
15060 $ximg = ($this->w + $this->lMargin - $this->rMargin - $w) / 2;
15061 } elseif ($palign == 'R') {
15062 $ximg = $this->w - $this->rMargin - $w;
15063 } else {
15064 $ximg = $x;
15065 }
15066 $this->img_rb_x = $ximg + $w;
15067 }
15068 if ($useBoundingBox) {
15069 $dx = $ximg * $k - $x1;
15070 $dy = $y * $k - $y1;
15071 } else {
15072 $dx = $ximg * $k;
15073 $dy = $y * $k;
15074 }
15075 // save the current graphic state
15076 $this->_out('q'.$this->epsmarker);
15077 // translate
15078 $this->_out(sprintf('%F %F %F %F %F %F cm', 1, 0, 0, 1, $dx, $dy + ($this->hPt - (2 * $y * $k) - ($y2 - $y1))));
15079 // scale
15080 if (isset($scale_x)) {
15081 $this->_out(sprintf('%F %F %F %F %F %F cm', $scale_x, 0, 0, $scale_y, $x1 * (1 - $scale_x), $y2 * (1 - $scale_y)));
15082 }
15083 // handle pc/unix/mac line endings
15084 $lines = preg_split('/[\r\n]+/si', $data, -1, PREG_SPLIT_NO_EMPTY);
15085 $u=0;
15086 $cnt = count($lines);
15087 for ($i=0; $i < $cnt; ++$i) {
15088 $line = $lines[$i];
15089 if (($line == '') OR ($line[0] == '%')) {
15090 continue;
15091 }
15092 $len = strlen($line);
15093 // check for spot color names
15094 $color_name = '';
15095 if (strcasecmp('x', substr(trim($line), -1)) == 0) {
15096 if (preg_match('/\([^\)]*\)/', $line, $matches) > 0) {
15097 // extract spot color name
15098 $color_name = $matches[0];
15099 // remove color name from string
15100 $line = str_replace(' '.$color_name, '', $line);
15101 // remove pharentesis from color name
15102 $color_name = substr($color_name, 1, -1);
15103 }
15104 }
15105 $chunks = explode(' ', $line);
15106 $cmd = trim(array_pop($chunks));
15107 // RGB
15108 if (($cmd == 'Xa') OR ($cmd == 'XA')) {
15109 $b = array_pop($chunks);
15110 $g = array_pop($chunks);
15111 $r = array_pop($chunks);
15112 $this->_out(''.$r.' '.$g.' '.$b.' '.($cmd=='Xa'?'rg':'RG')); //substr($line, 0, -2).'rg' -> in EPS (AI8): c m y k r g b rg!
15113 continue;
15114 }
15115 $skip = false;
15116 if ($fixoutvals) {
15117 // check for values outside the bounding box
15118 switch ($cmd) {
15119 case 'm':
15120 case 'l':
15121 case 'L': {
15122 // skip values outside bounding box
15123 foreach ($chunks as $key => $val) {
15124 if ((($key % 2) == 0) AND (($val < $x1) OR ($val > $x2))) {
15125 $skip = true;
15126 } elseif ((($key % 2) != 0) AND (($val < $y1) OR ($val > $y2))) {
15127 $skip = true;
15128 }
15129 }
15130 }
15131 }
15132 }
15133 switch ($cmd) {
15134 case 'm':
15135 case 'l':
15136 case 'v':
15137 case 'y':
15138 case 'c':
15139 case 'k':
15140 case 'K':
15141 case 'g':
15142 case 'G':
15143 case 's':
15144 case 'S':
15145 case 'J':
15146 case 'j':
15147 case 'w':
15148 case 'M':
15149 case 'd':
15150 case 'n': {
15151 if ($skip) {
15152 break;
15153 }
15154 $this->_out($line);
15155 break;
15156 }
15157 case 'x': {// custom fill color
15158 if (empty($color_name)) {
15159 // CMYK color
15160 list($col_c, $col_m, $col_y, $col_k) = $chunks;
15161 $this->_out(''.$col_c.' '.$col_m.' '.$col_y.' '.$col_k.' k');
15162 } else {
15163 // Spot Color (CMYK + tint)
15164 list($col_c, $col_m, $col_y, $col_k, $col_t) = $chunks;
15165 $this->AddSpotColor($color_name, ($col_c * 100), ($col_m * 100), ($col_y * 100), ($col_k * 100));
15166 $color_cmd = sprintf('/CS%d cs %F scn', $this->spot_colors[$color_name]['i'], (1 - $col_t));
15167 $this->_out($color_cmd);
15168 }
15169 break;
15170 }
15171 case 'X': { // custom stroke color
15172 if (empty($color_name)) {
15173 // CMYK color
15174 list($col_c, $col_m, $col_y, $col_k) = $chunks;
15175 $this->_out(''.$col_c.' '.$col_m.' '.$col_y.' '.$col_k.' K');
15176 } else {
15177 // Spot Color (CMYK + tint)
15178 list($col_c, $col_m, $col_y, $col_k, $col_t) = $chunks;
15179 $this->AddSpotColor($color_name, ($col_c * 100), ($col_m * 100), ($col_y * 100), ($col_k * 100));
15180 $color_cmd = sprintf('/CS%d CS %F SCN', $this->spot_colors[$color_name]['i'], (1 - $col_t));
15181 $this->_out($color_cmd);
15182 }
15183 break;
15184 }
15185 case 'Y':
15186 case 'N':
15187 case 'V':
15188 case 'L':
15189 case 'C': {
15190 if ($skip) {
15191 break;
15192 }
15193 $line[($len - 1)] = strtolower($cmd);
15194 $this->_out($line);
15195 break;
15196 }
15197 case 'b':
15198 case 'B': {
15199 $this->_out($cmd . '*');
15200 break;
15201 }
15202 case 'f':
15203 case 'F': {
15204 if ($u > 0) {
15205 $isU = false;
15206 $max = min(($i + 5), $cnt);
15207 for ($j = ($i + 1); $j < $max; ++$j) {
15208 $isU = ($isU OR (($lines[$j] == 'U') OR ($lines[$j] == '*U')));
15209 }
15210 if ($isU) {
15211 $this->_out('f*');
15212 }
15213 } else {
15214 $this->_out('f*');
15215 }
15216 break;
15217 }
15218 case '*u': {
15219 ++$u;
15220 break;
15221 }
15222 case '*U': {
15223 --$u;
15224 break;
15225 }
15226 }
15227 }
15228 // restore previous graphic state
15229 $this->_out($this->epsmarker.'Q');
15230 if (!empty($border)) {
15231 $bx = $this->x;
15232 $by = $this->y;
15233 $this->x = $ximg;
15234 if ($this->rtl) {
15235 $this->x += $w;
15236 }
15237 $this->y = $y;
15238 $this->Cell($w, $h, '', $border, 0, '', 0, '', 0, true);
15239 $this->x = $bx;
15240 $this->y = $by;
15241 }
15242 if ($link) {
15243 $this->Link($ximg, $y, $w, $h, $link, 0);
15244 }
15245 // set pointer to align the next text/objects
15246 switch($align) {
15247 case 'T':{
15248 $this->y = $y;
15249 $this->x = $this->img_rb_x;
15250 break;
15251 }
15252 case 'M':{
15253 $this->y = $y + round($h/2);
15254 $this->x = $this->img_rb_x;
15255 break;
15256 }
15257 case 'B':{
15258 $this->y = $this->img_rb_y;
15259 $this->x = $this->img_rb_x;
15260 break;
15261 }
15262 case 'N':{
15263 $this->SetY($this->img_rb_y);
15264 break;
15265 }
15266 default:{
15267 break;
15268 }
15269 }
15270 $this->endlinex = $this->img_rb_x;
15271 }
15272
15273 /**
15274 * Set document barcode.
15275 * @param $bc (string) barcode
15276 * @public
15277 */
15278 public function setBarcode($bc='') {
15279 $this->barcode = $bc;
15280 }
15281
15282 /**
15283 * Get current barcode.
15284 * @return string
15285 * @public
15286 * @since 4.0.012 (2008-07-24)
15287 */
15288 public function getBarcode() {
15289 return $this->barcode;
15290 }
15291
15292 /**
15293 * Print a Linear Barcode.
15294 * @param $code (string) code to print
15295 * @param $type (string) type of barcode (see tcpdf_barcodes_1d.php for supported formats).
15296 * @param $x (int) x position in user units (empty string = current x position)
15297 * @param $y (int) y position in user units (empty string = current y position)
15298 * @param $w (int) width in user units (empty string = remaining page width)
15299 * @param $h (int) height in user units (empty string = remaining page height)
15300 * @param $xres (float) width of the smallest bar in user units (empty string = default value = 0.4mm)
15301 * @param $style (array) array of options:<ul>
15302 * <li>boolean $style['border'] if true prints a border</li>
15303 * <li>int $style['padding'] padding to leave around the barcode in user units (set to 'auto' for automatic padding)</li>
15304 * <li>int $style['hpadding'] horizontal padding in user units (set to 'auto' for automatic padding)</li>
15305 * <li>int $style['vpadding'] vertical padding in user units (set to 'auto' for automatic padding)</li>
15306 * <li>array $style['fgcolor'] color array for bars and text</li>
15307 * <li>mixed $style['bgcolor'] color array for background (set to false for transparent)</li>
15308 * <li>boolean $style['text'] if true prints text below the barcode</li>
15309 * <li>string $style['label'] override default label</li>
15310 * <li>string $style['font'] font name for text</li><li>int $style['fontsize'] font size for text</li>
15311 * <li>int $style['stretchtext']: 0 = disabled; 1 = horizontal scaling only if necessary; 2 = forced horizontal scaling; 3 = character spacing only if necessary; 4 = forced character spacing.</li>
15312 * <li>string $style['position'] horizontal position of the containing barcode cell on the page: L = left margin; C = center; R = right margin.</li>
15313 * <li>string $style['align'] horizontal position of the barcode on the containing rectangle: L = left; C = center; R = right.</li>
15314 * <li>string $style['stretch'] if true stretch the barcode to best fit the available width, otherwise uses $xres resolution for a single bar.</li>
15315 * <li>string $style['fitwidth'] if true reduce the width to fit the barcode width + padding. When this option is enabled the 'stretch' option is automatically disabled.</li>
15316 * <li>string $style['cellfitalign'] this option works only when 'fitwidth' is true and 'position' is unset or empty. Set the horizontal position of the containing barcode cell inside the specified rectangle: L = left; C = center; R = right.</li></ul>
15317 * @param $align (string) Indicates the alignment of the pointer next to barcode insertion relative to barcode height. The value can be:<ul><li>T: top-right for LTR or top-left for RTL</li><li>M: middle-right for LTR or middle-left for RTL</li><li>B: bottom-right for LTR or bottom-left for RTL</li><li>N: next line</li></ul>
15318 * @author Nicola Asuni
15319 * @since 3.1.000 (2008-06-09)
15320 * @public
15321 */
15322 public function write1DBarcode($code, $type, $x='', $y='', $w='', $h='', $xres='', $style='', $align='') {
15323 if (TCPDF_STATIC::empty_string(trim($code))) {
15324 return;
15325 }
15326 require_once(dirname(__FILE__).'/tcpdf_barcodes_1d.php');
15327 // save current graphic settings
15328 $gvars = $this->getGraphicVars();
15329 // create new barcode object
15330 $barcodeobj = new TCPDFBarcode($code, $type);
15331 $arrcode = $barcodeobj->getBarcodeArray();
15332 if (($arrcode === false) OR empty($arrcode) OR ($arrcode['maxw'] <= 0)) {
15333 $this->Error('Error in 1D barcode string');
15334 }
15335 if ($arrcode['maxh'] <= 0) {
15336 $arrcode['maxh'] = 1;
15337 }
15338 // set default values
15339 if (!isset($style['position'])) {
15340 $style['position'] = '';
15341 } elseif ($style['position'] == 'S') {
15342 // keep this for backward compatibility
15343 $style['position'] = '';
15344 $style['stretch'] = true;
15345 }
15346 if (!isset($style['fitwidth'])) {
15347 if (!isset($style['stretch'])) {
15348 $style['fitwidth'] = true;
15349 } else {
15350 $style['fitwidth'] = false;
15351 }
15352 }
15353 if ($style['fitwidth']) {
15354 // disable stretch
15355 $style['stretch'] = false;
15356 }
15357 if (!isset($style['stretch'])) {
15358 if (($w === '') OR ($w <= 0)) {
15359 $style['stretch'] = false;
15360 } else {
15361 $style['stretch'] = true;
15362 }
15363 }
15364 if (!isset($style['fgcolor'])) {
15365 $style['fgcolor'] = array(0,0,0); // default black
15366 }
15367 if (!isset($style['bgcolor'])) {
15368 $style['bgcolor'] = false; // default transparent
15369 }
15370 if (!isset($style['border'])) {
15371 $style['border'] = false;
15372 }
15373 $fontsize = 0;
15374 if (!isset($style['text'])) {
15375 $style['text'] = false;
15376 }
15377 if ($style['text'] AND isset($style['font'])) {
15378 if (isset($style['fontsize'])) {
15379 $fontsize = $style['fontsize'];
15380 }
15381 $this->SetFont($style['font'], '', $fontsize);
15382 }
15383 if (!isset($style['stretchtext'])) {
15384 $style['stretchtext'] = 4;
15385 }
15386 if ($x === '') {
15387 $x = $this->x;
15388 }
15389 if ($y === '') {
15390 $y = $this->y;
15391 }
15392 // check page for no-write regions and adapt page margins if necessary
15393 list($x, $y) = $this->checkPageRegions($h, $x, $y);
15394 if (($w === '') OR ($w <= 0)) {
15395 if ($this->rtl) {
15396 $w = $x - $this->lMargin;
15397 } else {
15398 $w = $this->w - $this->rMargin - $x;
15399 }
15400 }
15401 // padding
15402 if (!isset($style['padding'])) {
15403 $padding = 0;
15404 } elseif ($style['padding'] === 'auto') {
15405 $padding = 10 * ($w / ($arrcode['maxw'] + 20));
15406 } else {
15407 $padding = floatval($style['padding']);
15408 }
15409 // horizontal padding
15410 if (!isset($style['hpadding'])) {
15411 $hpadding = $padding;
15412 } elseif ($style['hpadding'] === 'auto') {
15413 $hpadding = 10 * ($w / ($arrcode['maxw'] + 20));
15414 } else {
15415 $hpadding = floatval($style['hpadding']);
15416 }
15417 // vertical padding
15418 if (!isset($style['vpadding'])) {
15419 $vpadding = $padding;
15420 } elseif ($style['vpadding'] === 'auto') {
15421 $vpadding = ($hpadding / 2);
15422 } else {
15423 $vpadding = floatval($style['vpadding']);
15424 }
15425 // calculate xres (single bar width)
15426 $max_xres = ($w - (2 * $hpadding)) / $arrcode['maxw'];
15427 if ($style['stretch']) {
15428 $xres = $max_xres;
15429 } else {
15430 if (TCPDF_STATIC::empty_string($xres)) {
15431 $xres = (0.141 * $this->k); // default bar width = 0.4 mm
15432 }
15433 if ($xres > $max_xres) {
15434 // correct xres to fit on $w
15435 $xres = $max_xres;
15436 }
15437 if ((isset($style['padding']) AND ($style['padding'] === 'auto'))
15438 OR (isset($style['hpadding']) AND ($style['hpadding'] === 'auto'))) {
15439 $hpadding = 10 * $xres;
15440 if (isset($style['vpadding']) AND ($style['vpadding'] === 'auto')) {
15441 $vpadding = ($hpadding / 2);
15442 }
15443 }
15444 }
15445 if ($style['fitwidth']) {
15446 $wold = $w;
15447 $w = (($arrcode['maxw'] * $xres) + (2 * $hpadding));
15448 if (isset($style['cellfitalign'])) {
15449 switch ($style['cellfitalign']) {
15450 case 'L': {
15451 if ($this->rtl) {
15452 $x -= ($wold - $w);
15453 }
15454 break;
15455 }
15456 case 'R': {
15457 if (!$this->rtl) {
15458 $x += ($wold - $w);
15459 }
15460 break;
15461 }
15462 case 'C': {
15463 if ($this->rtl) {
15464 $x -= (($wold - $w) / 2);
15465 } else {
15466 $x += (($wold - $w) / 2);
15467 }
15468 break;
15469 }
15470 default : {
15471 break;
15472 }
15473 }
15474 }
15475 }
15476 $text_height = $this->getCellHeight($fontsize / $this->k);
15477 // height
15478 if (($h === '') OR ($h <= 0)) {
15479 // set default height
15480 $h = (($arrcode['maxw'] * $xres) / 3) + (2 * $vpadding) + $text_height;
15481 }
15482 $barh = $h - $text_height - (2 * $vpadding);
15483 if ($barh <=0) {
15484 // try to reduce font or padding to fit barcode on available height
15485 if ($text_height > $h) {
15486 $fontsize = (($h * $this->k) / (4 * $this->cell_height_ratio));
15487 $text_height = $this->getCellHeight($fontsize / $this->k);
15488 $this->SetFont($style['font'], '', $fontsize);
15489 }
15490 if ($vpadding > 0) {
15491 $vpadding = (($h - $text_height) / 4);
15492 }
15493 $barh = $h - $text_height - (2 * $vpadding);
15494 }
15495 // fit the barcode on available space
15496 list($w, $h, $x, $y) = $this->fitBlock($w, $h, $x, $y, false);
15497 // set alignment
15498 $this->img_rb_y = $y + $h;
15499 // set alignment
15500 if ($this->rtl) {
15501 if ($style['position'] == 'L') {
15502 $xpos = $this->lMargin;
15503 } elseif ($style['position'] == 'C') {
15504 $xpos = ($this->w + $this->lMargin - $this->rMargin - $w) / 2;
15505 } elseif ($style['position'] == 'R') {
15506 $xpos = $this->w - $this->rMargin - $w;
15507 } else {
15508 $xpos = $x - $w;
15509 }
15510 $this->img_rb_x = $xpos;
15511 } else {
15512 if ($style['position'] == 'L') {
15513 $xpos = $this->lMargin;
15514 } elseif ($style['position'] == 'C') {
15515 $xpos = ($this->w + $this->lMargin - $this->rMargin - $w) / 2;
15516 } elseif ($style['position'] == 'R') {
15517 $xpos = $this->w - $this->rMargin - $w;
15518 } else {
15519 $xpos = $x;
15520 }
15521 $this->img_rb_x = $xpos + $w;
15522 }
15523 $xpos_rect = $xpos;
15524 if (!isset($style['align'])) {
15525 $style['align'] = 'C';
15526 }
15527 switch ($style['align']) {
15528 case 'L': {
15529 $xpos = $xpos_rect + $hpadding;
15530 break;
15531 }
15532 case 'R': {
15533 $xpos = $xpos_rect + ($w - ($arrcode['maxw'] * $xres)) - $hpadding;
15534 break;
15535 }
15536 case 'C':
15537 default : {
15538 $xpos = $xpos_rect + (($w - ($arrcode['maxw'] * $xres)) / 2);
15539 break;
15540 }
15541 }
15542 $xpos_text = $xpos;
15543 // barcode is always printed in LTR direction
15544 $tempRTL = $this->rtl;
15545 $this->rtl = false;
15546 // print background color
15547 if ($style['bgcolor']) {
15548 $this->Rect($xpos_rect, $y, $w, $h, $style['border'] ? 'DF' : 'F', '', $style['bgcolor']);
15549 } elseif ($style['border']) {
15550 $this->Rect($xpos_rect, $y, $w, $h, 'D');
15551 }
15552 // set foreground color
15553 $this->SetDrawColorArray($style['fgcolor']);
15554 $this->SetTextColorArray($style['fgcolor']);
15555 // print bars
15556 foreach ($arrcode['bcode'] as $k => $v) {
15557 $bw = ($v['w'] * $xres);
15558 if ($v['t']) {
15559 // draw a vertical bar
15560 $ypos = $y + $vpadding + ($v['p'] * $barh / $arrcode['maxh']);
15561 $this->Rect($xpos, $ypos, $bw, ($v['h'] * $barh / $arrcode['maxh']), 'F', array(), $style['fgcolor']);
15562 }
15563 $xpos += $bw;
15564 }
15565 // print text
15566 if ($style['text']) {
15567 if (isset($style['label']) AND !TCPDF_STATIC::empty_string($style['label'])) {
15568 $label = $style['label'];
15569 } else {
15570 $label = $code;
15571 }
15572 $txtwidth = ($arrcode['maxw'] * $xres);
15573 if ($this->GetStringWidth($label) > $txtwidth) {
15574 $style['stretchtext'] = 2;
15575 }
15576 // print text
15577 $this->x = $xpos_text;
15578 $this->y = $y + $vpadding + $barh;
15579 $cellpadding = $this->cell_padding;
15580 $this->SetCellPadding(0);
15581 $this->Cell($txtwidth, '', $label, 0, 0, 'C', false, '', $style['stretchtext'], false, 'T', 'T');
15582 $this->cell_padding = $cellpadding;
15583 }
15584 // restore original direction
15585 $this->rtl = $tempRTL;
15586 // restore previous settings
15587 $this->setGraphicVars($gvars);
15588 // set pointer to align the next text/objects
15589 switch($align) {
15590 case 'T':{
15591 $this->y = $y;
15592 $this->x = $this->img_rb_x;
15593 break;
15594 }
15595 case 'M':{
15596 $this->y = $y + round($h / 2);
15597 $this->x = $this->img_rb_x;
15598 break;
15599 }
15600 case 'B':{
15601 $this->y = $this->img_rb_y;
15602 $this->x = $this->img_rb_x;
15603 break;
15604 }
15605 case 'N':{
15606 $this->SetY($this->img_rb_y);
15607 break;
15608 }
15609 default:{
15610 break;
15611 }
15612 }
15613 $this->endlinex = $this->img_rb_x;
15614 }
15615
15616 /**
15617 * Print 2D Barcode.
15618 * @param $code (string) code to print
15619 * @param $type (string) type of barcode (see tcpdf_barcodes_2d.php for supported formats).
15620 * @param $x (int) x position in user units
15621 * @param $y (int) y position in user units
15622 * @param $w (int) width in user units
15623 * @param $h (int) height in user units
15624 * @param $style (array) array of options:<ul>
15625 * <li>boolean $style['border'] if true prints a border around the barcode</li>
15626 * <li>int $style['padding'] padding to leave around the barcode in barcode units (set to 'auto' for automatic padding)</li>
15627 * <li>int $style['hpadding'] horizontal padding in barcode units (set to 'auto' for automatic padding)</li>
15628 * <li>int $style['vpadding'] vertical padding in barcode units (set to 'auto' for automatic padding)</li>
15629 * <li>int $style['module_width'] width of a single module in points</li>
15630 * <li>int $style['module_height'] height of a single module in points</li>
15631 * <li>array $style['fgcolor'] color array for bars and text</li>
15632 * <li>mixed $style['bgcolor'] color array for background or false for transparent</li>
15633 * <li>string $style['position'] barcode position on the page: L = left margin; C = center; R = right margin; S = stretch</li><li>$style['module_width'] width of a single module in points</li>
15634 * <li>$style['module_height'] height of a single module in points</li></ul>
15635 * @param $align (string) Indicates the alignment of the pointer next to barcode insertion relative to barcode height. The value can be:<ul><li>T: top-right for LTR or top-left for RTL</li><li>M: middle-right for LTR or middle-left for RTL</li><li>B: bottom-right for LTR or bottom-left for RTL</li><li>N: next line</li></ul>
15636 * @param $distort (boolean) if true distort the barcode to fit width and height, otherwise preserve aspect ratio
15637 * @author Nicola Asuni
15638 * @since 4.5.037 (2009-04-07)
15639 * @public
15640 */
15641 public function write2DBarcode($code, $type, $x='', $y='', $w='', $h='', $style='', $align='', $distort=false) {
15642 if (TCPDF_STATIC::empty_string(trim($code))) {
15643 return;
15644 }
15645 require_once(dirname(__FILE__).'/tcpdf_barcodes_2d.php');
15646 // save current graphic settings
15647 $gvars = $this->getGraphicVars();
15648 // create new barcode object
15649 $barcodeobj = new TCPDF2DBarcode($code, $type);
15650 $arrcode = $barcodeobj->getBarcodeArray();
15651 if (($arrcode === false) OR empty($arrcode) OR !isset($arrcode['num_rows']) OR ($arrcode['num_rows'] == 0) OR !isset($arrcode['num_cols']) OR ($arrcode['num_cols'] == 0)) {
15652 $this->Error('Error in 2D barcode string');
15653 }
15654 // set default values
15655 if (!isset($style['position'])) {
15656 $style['position'] = '';
15657 }
15658 if (!isset($style['fgcolor'])) {
15659 $style['fgcolor'] = array(0,0,0); // default black
15660 }
15661 if (!isset($style['bgcolor'])) {
15662 $style['bgcolor'] = false; // default transparent
15663 }
15664 if (!isset($style['border'])) {
15665 $style['border'] = false;
15666 }
15667 // padding
15668 if (!isset($style['padding'])) {
15669 $style['padding'] = 0;
15670 } elseif ($style['padding'] === 'auto') {
15671 $style['padding'] = 4;
15672 }
15673 if (!isset($style['hpadding'])) {
15674 $style['hpadding'] = $style['padding'];
15675 } elseif ($style['hpadding'] === 'auto') {
15676 $style['hpadding'] = 4;
15677 }
15678 if (!isset($style['vpadding'])) {
15679 $style['vpadding'] = $style['padding'];
15680 } elseif ($style['vpadding'] === 'auto') {
15681 $style['vpadding'] = 4;
15682 }
15683 $hpad = (2 * $style['hpadding']);
15684 $vpad = (2 * $style['vpadding']);
15685 // cell (module) dimension
15686 if (!isset($style['module_width'])) {
15687 $style['module_width'] = 1; // width of a single module in points
15688 }
15689 if (!isset($style['module_height'])) {
15690 $style['module_height'] = 1; // height of a single module in points
15691 }
15692 if ($x === '') {
15693 $x = $this->x;
15694 }
15695 if ($y === '') {
15696 $y = $this->y;
15697 }
15698 // check page for no-write regions and adapt page margins if necessary
15699 list($x, $y) = $this->checkPageRegions($h, $x, $y);
15700 // number of barcode columns and rows
15701 $rows = $arrcode['num_rows'];
15702 $cols = $arrcode['num_cols'];
15703 if (($rows <= 0) || ($cols <= 0)){
15704 $this->Error('Error in 2D barcode string');
15705 }
15706 // module width and height
15707 $mw = $style['module_width'];
15708 $mh = $style['module_height'];
15709 if (($mw <= 0) OR ($mh <= 0)) {
15710 $this->Error('Error in 2D barcode string');
15711 }
15712 // get max dimensions
15713 if ($this->rtl) {
15714 $maxw = $x - $this->lMargin;
15715 } else {
15716 $maxw = $this->w - $this->rMargin - $x;
15717 }
15718 $maxh = ($this->h - $this->tMargin - $this->bMargin);
15719 $ratioHW = ((($rows * $mh) + $hpad) / (($cols * $mw) + $vpad));
15720 $ratioWH = ((($cols * $mw) + $vpad) / (($rows * $mh) + $hpad));
15721 if (!$distort) {
15722 if (($maxw * $ratioHW) > $maxh) {
15723 $maxw = $maxh * $ratioWH;
15724 }
15725 if (($maxh * $ratioWH) > $maxw) {
15726 $maxh = $maxw * $ratioHW;
15727 }
15728 }
15729 // set maximum dimesions
15730 if ($w > $maxw) {
15731 $w = $maxw;
15732 }
15733 if ($h > $maxh) {
15734 $h = $maxh;
15735 }
15736 // set dimensions
15737 if ((($w === '') OR ($w <= 0)) AND (($h === '') OR ($h <= 0))) {
15738 $w = ($cols + $hpad) * ($mw / $this->k);
15739 $h = ($rows + $vpad) * ($mh / $this->k);
15740 } elseif (($w === '') OR ($w <= 0)) {
15741 $w = $h * $ratioWH;
15742 } elseif (($h === '') OR ($h <= 0)) {
15743 $h = $w * $ratioHW;
15744 }
15745 // barcode size (excluding padding)
15746 $bw = ($w * $cols) / ($cols + $hpad);
15747 $bh = ($h * $rows) / ($rows + $vpad);
15748 // dimension of single barcode cell unit
15749 $cw = $bw / $cols;
15750 $ch = $bh / $rows;
15751 if (!$distort) {
15752 if (($cw / $ch) > ($mw / $mh)) {
15753 // correct horizontal distortion
15754 $cw = $ch * $mw / $mh;
15755 $bw = $cw * $cols;
15756 $style['hpadding'] = ($w - $bw) / (2 * $cw);
15757 } else {
15758 // correct vertical distortion
15759 $ch = $cw * $mh / $mw;
15760 $bh = $ch * $rows;
15761 $style['vpadding'] = ($h - $bh) / (2 * $ch);
15762 }
15763 }
15764 // fit the barcode on available space
15765 list($w, $h, $x, $y) = $this->fitBlock($w, $h, $x, $y, false);
15766 // set alignment
15767 $this->img_rb_y = $y + $h;
15768 // set alignment
15769 if ($this->rtl) {
15770 if ($style['position'] == 'L') {
15771 $xpos = $this->lMargin;
15772 } elseif ($style['position'] == 'C') {
15773 $xpos = ($this->w + $this->lMargin - $this->rMargin - $w) / 2;
15774 } elseif ($style['position'] == 'R') {
15775 $xpos = $this->w - $this->rMargin - $w;
15776 } else {
15777 $xpos = $x - $w;
15778 }
15779 $this->img_rb_x = $xpos;
15780 } else {
15781 if ($style['position'] == 'L') {
15782 $xpos = $this->lMargin;
15783 } elseif ($style['position'] == 'C') {
15784 $xpos = ($this->w + $this->lMargin - $this->rMargin - $w) / 2;
15785 } elseif ($style['position'] == 'R') {
15786 $xpos = $this->w - $this->rMargin - $w;
15787 } else {
15788 $xpos = $x;
15789 }
15790 $this->img_rb_x = $xpos + $w;
15791 }
15792 $xstart = $xpos + ($style['hpadding'] * $cw);
15793 $ystart = $y + ($style['vpadding'] * $ch);
15794 // barcode is always printed in LTR direction
15795 $tempRTL = $this->rtl;
15796 $this->rtl = false;
15797 // print background color
15798 if ($style['bgcolor']) {
15799 $this->Rect($xpos, $y, $w, $h, $style['border'] ? 'DF' : 'F', '', $style['bgcolor']);
15800 } elseif ($style['border']) {
15801 $this->Rect($xpos, $y, $w, $h, 'D');
15802 }
15803 // set foreground color
15804 $this->SetDrawColorArray($style['fgcolor']);
15805 // print barcode cells
15806 // for each row
15807 for ($r = 0; $r < $rows; ++$r) {
15808 $xr = $xstart;
15809 // for each column
15810 for ($c = 0; $c < $cols; ++$c) {
15811 if ($arrcode['bcode'][$r][$c] == 1) {
15812 // draw a single barcode cell
15813 $this->Rect($xr, $ystart, $cw, $ch, 'F', array(), $style['fgcolor']);
15814 }
15815 $xr += $cw;
15816 }
15817 $ystart += $ch;
15818 }
15819 // restore original direction
15820 $this->rtl = $tempRTL;
15821 // restore previous settings
15822 $this->setGraphicVars($gvars);
15823 // set pointer to align the next text/objects
15824 switch($align) {
15825 case 'T':{
15826 $this->y = $y;
15827 $this->x = $this->img_rb_x;
15828 break;
15829 }
15830 case 'M':{
15831 $this->y = $y + round($h/2);
15832 $this->x = $this->img_rb_x;
15833 break;
15834 }
15835 case 'B':{
15836 $this->y = $this->img_rb_y;
15837 $this->x = $this->img_rb_x;
15838 break;
15839 }
15840 case 'N':{
15841 $this->SetY($this->img_rb_y);
15842 break;
15843 }
15844 default:{
15845 break;
15846 }
15847 }
15848 $this->endlinex = $this->img_rb_x;
15849 }
15850
15851 /**
15852 * Returns an array containing current margins:
15853 * <ul>
15854 <li>$ret['left'] = left margin</li>
15855 <li>$ret['right'] = right margin</li>
15856 <li>$ret['top'] = top margin</li>
15857 <li>$ret['bottom'] = bottom margin</li>
15858 <li>$ret['header'] = header margin</li>
15859 <li>$ret['footer'] = footer margin</li>
15860 <li>$ret['cell'] = cell padding array</li>
15861 <li>$ret['padding_left'] = cell left padding</li>
15862 <li>$ret['padding_top'] = cell top padding</li>
15863 <li>$ret['padding_right'] = cell right padding</li>
15864 <li>$ret['padding_bottom'] = cell bottom padding</li>
15865 * </ul>
15866 * @return array containing all margins measures
15867 * @public
15868 * @since 3.2.000 (2008-06-23)
15869 */
15870 public function getMargins() {
15871 $ret = array(
15872 'left' => $this->lMargin,
15873 'right' => $this->rMargin,
15874 'top' => $this->tMargin,
15875 'bottom' => $this->bMargin,
15876 'header' => $this->header_margin,
15877 'footer' => $this->footer_margin,
15878 'cell' => $this->cell_padding,
15879 'padding_left' => $this->cell_padding['L'],
15880 'padding_top' => $this->cell_padding['T'],
15881 'padding_right' => $this->cell_padding['R'],
15882 'padding_bottom' => $this->cell_padding['B']
15883 );
15884 return $ret;
15885 }
15886
15887 /**
15888 * Returns an array containing original margins:
15889 * <ul>
15890 <li>$ret['left'] = left margin</li>
15891 <li>$ret['right'] = right margin</li>
15892 * </ul>
15893 * @return array containing all margins measures
15894 * @public
15895 * @since 4.0.012 (2008-07-24)
15896 */
15897 public function getOriginalMargins() {
15898 $ret = array(
15899 'left' => $this->original_lMargin,
15900 'right' => $this->original_rMargin
15901 );
15902 return $ret;
15903 }
15904
15905 /**
15906 * Returns the current font size.
15907 * @return current font size
15908 * @public
15909 * @since 3.2.000 (2008-06-23)
15910 */
15911 public function getFontSize() {
15912 return $this->FontSize;
15913 }
15914
15915 /**
15916 * Returns the current font size in points unit.
15917 * @return current font size in points unit
15918 * @public
15919 * @since 3.2.000 (2008-06-23)
15920 */
15921 public function getFontSizePt() {
15922 return $this->FontSizePt;
15923 }
15924
15925 /**
15926 * Returns the current font family name.
15927 * @return string current font family name
15928 * @public
15929 * @since 4.3.008 (2008-12-05)
15930 */
15931 public function getFontFamily() {
15932 return $this->FontFamily;
15933 }
15934
15935 /**
15936 * Returns the current font style.
15937 * @return string current font style
15938 * @public
15939 * @since 4.3.008 (2008-12-05)
15940 */
15941 public function getFontStyle() {
15942 return $this->FontStyle;
15943 }
15944
15945 /**
15946 * Cleanup HTML code (requires HTML Tidy library).
15947 * @param $html (string) htmlcode to fix
15948 * @param $default_css (string) CSS commands to add
15949 * @param $tagvs (array) parameters for setHtmlVSpace method
15950 * @param $tidy_options (array) options for tidy_parse_string function
15951 * @return string XHTML code cleaned up
15952 * @author Nicola Asuni
15953 * @public
15954 * @since 5.9.017 (2010-11-16)
15955 * @see setHtmlVSpace()
15956 */
15957 public function fixHTMLCode($html, $default_css='', $tagvs='', $tidy_options='') {
15958 return TCPDF_STATIC::fixHTMLCode($html, $default_css, $tagvs, $tidy_options, $this->tagvspaces);
15959 }
15960
15961 /**
15962 * Returns the border width from CSS property
15963 * @param $width (string) border width
15964 * @return int with in user units
15965 * @protected
15966 * @since 5.7.000 (2010-08-02)
15967 */
15968 protected function getCSSBorderWidth($width) {
15969 if ($width == 'thin') {
15970 $width = (2 / $this->k);
15971 } elseif ($width == 'medium') {
15972 $width = (4 / $this->k);
15973 } elseif ($width == 'thick') {
15974 $width = (6 / $this->k);
15975 } else {
15976 $width = $this->getHTMLUnitToUnits($width, 1, 'px', false);
15977 }
15978 return $width;
15979 }
15980
15981 /**
15982 * Returns the border dash style from CSS property
15983 * @param $style (string) border style to convert
15984 * @return int sash style (return -1 in case of none or hidden border)
15985 * @protected
15986 * @since 5.7.000 (2010-08-02)
15987 */
15988 protected function getCSSBorderDashStyle($style) {
15989 switch (strtolower($style)) {
15990 case 'none':
15991 case 'hidden': {
15992 $dash = -1;
15993 break;
15994 }
15995 case 'dotted': {
15996 $dash = 1;
15997 break;
15998 }
15999 case 'dashed': {
16000 $dash = 3;
16001 break;
16002 }
16003 case 'double':
16004 case 'groove':
16005 case 'ridge':
16006 case 'inset':
16007 case 'outset':
16008 case 'solid':
16009 default: {
16010 $dash = 0;
16011 break;
16012 }
16013 }
16014 return $dash;
16015 }
16016
16017 /**
16018 * Returns the border style array from CSS border properties
16019 * @param $cssborder (string) border properties
16020 * @return array containing border properties
16021 * @protected
16022 * @since 5.7.000 (2010-08-02)
16023 */
16024 protected function getCSSBorderStyle($cssborder) {
16025 $bprop = preg_split('/[\s]+/', trim($cssborder));
16026 $border = array(); // value to be returned
16027 switch (count($bprop)) {
16028 case 3: {
16029 $width = $bprop[0];
16030 $style = $bprop[1];
16031 $color = $bprop[2];
16032 break;
16033 }
16034 case 2: {
16035 $width = 'medium';
16036 $style = $bprop[0];
16037 $color = $bprop[1];
16038 break;
16039 }
16040 case 1: {
16041 $width = 'medium';
16042 $style = $bprop[0];
16043 $color = 'black';
16044 break;
16045 }
16046 default: {
16047 $width = 'medium';
16048 $style = 'solid';
16049 $color = 'black';
16050 break;
16051 }
16052 }
16053 if ($style == 'none') {
16054 return array();
16055 }
16056 $border['cap'] = 'square';
16057 $border['join'] = 'miter';
16058 $border['dash'] = $this->getCSSBorderDashStyle($style);
16059 if ($border['dash'] < 0) {
16060 return array();
16061 }
16062 $border['width'] = $this->getCSSBorderWidth($width);
16063 $border['color'] = TCPDF_COLORS::convertHTMLColorToDec($color, $this->spot_colors);
16064 return $border;
16065 }
16066
16067 /**
16068 * Get the internal Cell padding from CSS attribute.
16069 * @param $csspadding (string) padding properties
16070 * @param $width (float) width of the containing element
16071 * @return array of cell paddings
16072 * @public
16073 * @since 5.9.000 (2010-10-04)
16074 */
16075 public function getCSSPadding($csspadding, $width=0) {
16076 $padding = preg_split('/[\s]+/', trim($csspadding));
16077 $cell_padding = array(); // value to be returned
16078 switch (count($padding)) {
16079 case 4: {
16080 $cell_padding['T'] = $padding[0];
16081 $cell_padding['R'] = $padding[1];
16082 $cell_padding['B'] = $padding[2];
16083 $cell_padding['L'] = $padding[3];
16084 break;
16085 }
16086 case 3: {
16087 $cell_padding['T'] = $padding[0];
16088 $cell_padding['R'] = $padding[1];
16089 $cell_padding['B'] = $padding[2];
16090 $cell_padding['L'] = $padding[1];
16091 break;
16092 }
16093 case 2: {
16094 $cell_padding['T'] = $padding[0];
16095 $cell_padding['R'] = $padding[1];
16096 $cell_padding['B'] = $padding[0];
16097 $cell_padding['L'] = $padding[1];
16098 break;
16099 }
16100 case 1: {
16101 $cell_padding['T'] = $padding[0];
16102 $cell_padding['R'] = $padding[0];
16103 $cell_padding['B'] = $padding[0];
16104 $cell_padding['L'] = $padding[0];
16105 break;
16106 }
16107 default: {
16108 return $this->cell_padding;
16109 }
16110 }
16111 if ($width == 0) {
16112 $width = $this->w - $this->lMargin - $this->rMargin;
16113 }
16114 $cell_padding['T'] = $this->getHTMLUnitToUnits($cell_padding['T'], $width, 'px', false);
16115 $cell_padding['R'] = $this->getHTMLUnitToUnits($cell_padding['R'], $width, 'px', false);
16116 $cell_padding['B'] = $this->getHTMLUnitToUnits($cell_padding['B'], $width, 'px', false);
16117 $cell_padding['L'] = $this->getHTMLUnitToUnits($cell_padding['L'], $width, 'px', false);
16118 return $cell_padding;
16119 }
16120
16121 /**
16122 * Get the internal Cell margin from CSS attribute.
16123 * @param $cssmargin (string) margin properties
16124 * @param $width (float) width of the containing element
16125 * @return array of cell margins
16126 * @public
16127 * @since 5.9.000 (2010-10-04)
16128 */
16129 public function getCSSMargin($cssmargin, $width=0) {
16130 $margin = preg_split('/[\s]+/', trim($cssmargin));
16131 $cell_margin = array(); // value to be returned
16132 switch (count($margin)) {
16133 case 4: {
16134 $cell_margin['T'] = $margin[0];
16135 $cell_margin['R'] = $margin[1];
16136 $cell_margin['B'] = $margin[2];
16137 $cell_margin['L'] = $margin[3];
16138 break;
16139 }
16140 case 3: {
16141 $cell_margin['T'] = $margin[0];
16142 $cell_margin['R'] = $margin[1];
16143 $cell_margin['B'] = $margin[2];
16144 $cell_margin['L'] = $margin[1];
16145 break;
16146 }
16147 case 2: {
16148 $cell_margin['T'] = $margin[0];
16149 $cell_margin['R'] = $margin[1];
16150 $cell_margin['B'] = $margin[0];
16151 $cell_margin['L'] = $margin[1];
16152 break;
16153 }
16154 case 1: {
16155 $cell_margin['T'] = $margin[0];
16156 $cell_margin['R'] = $margin[0];
16157 $cell_margin['B'] = $margin[0];
16158 $cell_margin['L'] = $margin[0];
16159 break;
16160 }
16161 default: {
16162 return $this->cell_margin;
16163 }
16164 }
16165 if ($width == 0) {
16166 $width = $this->w - $this->lMargin - $this->rMargin;
16167 }
16168 $cell_margin['T'] = $this->getHTMLUnitToUnits(str_replace('auto', '0', $cell_margin['T']), $width, 'px', false);
16169 $cell_margin['R'] = $this->getHTMLUnitToUnits(str_replace('auto', '0', $cell_margin['R']), $width, 'px', false);
16170 $cell_margin['B'] = $this->getHTMLUnitToUnits(str_replace('auto', '0', $cell_margin['B']), $width, 'px', false);
16171 $cell_margin['L'] = $this->getHTMLUnitToUnits(str_replace('auto', '0', $cell_margin['L']), $width, 'px', false);
16172 return $cell_margin;
16173 }
16174
16175 /**
16176 * Get the border-spacing from CSS attribute.
16177 * @param $cssbspace (string) border-spacing CSS properties
16178 * @param $width (float) width of the containing element
16179 * @return array of border spacings
16180 * @public
16181 * @since 5.9.010 (2010-10-27)
16182 */
16183 public function getCSSBorderMargin($cssbspace, $width=0) {
16184 $space = preg_split('/[\s]+/', trim($cssbspace));
16185 $border_spacing = array(); // value to be returned
16186 switch (count($space)) {
16187 case 2: {
16188 $border_spacing['H'] = $space[0];
16189 $border_spacing['V'] = $space[1];
16190 break;
16191 }
16192 case 1: {
16193 $border_spacing['H'] = $space[0];
16194 $border_spacing['V'] = $space[0];
16195 break;
16196 }
16197 default: {
16198 return array('H' => 0, 'V' => 0);
16199 }
16200 }
16201 if ($width == 0) {
16202 $width = $this->w - $this->lMargin - $this->rMargin;
16203 }
16204 $border_spacing['H'] = $this->getHTMLUnitToUnits($border_spacing['H'], $width, 'px', false);
16205 $border_spacing['V'] = $this->getHTMLUnitToUnits($border_spacing['V'], $width, 'px', false);
16206 return $border_spacing;
16207 }
16208
16209 /**
16210 * Returns the letter-spacing value from CSS value
16211 * @param $spacing (string) letter-spacing value
16212 * @param $parent (float) font spacing (tracking) value of the parent element
16213 * @return float quantity to increases or decreases the space between characters in a text.
16214 * @protected
16215 * @since 5.9.000 (2010-10-02)
16216 */
16217 protected function getCSSFontSpacing($spacing, $parent=0) {
16218 $val = 0; // value to be returned
16219 $spacing = trim($spacing);
16220 switch ($spacing) {
16221 case 'normal': {
16222 $val = 0;
16223 break;
16224 }
16225 case 'inherit': {
16226 if ($parent == 'normal') {
16227 $val = 0;
16228 } else {
16229 $val = $parent;
16230 }
16231 break;
16232 }
16233 default: {
16234 $val = $this->getHTMLUnitToUnits($spacing, 0, 'px', false);
16235 }
16236 }
16237 return $val;
16238 }
16239
16240 /**
16241 * Returns the percentage of font stretching from CSS value
16242 * @param $stretch (string) stretch mode
16243 * @param $parent (float) stretch value of the parent element
16244 * @return float font stretching percentage
16245 * @protected
16246 * @since 5.9.000 (2010-10-02)
16247 */
16248 protected function getCSSFontStretching($stretch, $parent=100) {
16249 $val = 100; // value to be returned
16250 $stretch = trim($stretch);
16251 switch ($stretch) {
16252 case 'ultra-condensed': {
16253 $val = 40;
16254 break;
16255 }
16256 case 'extra-condensed': {
16257 $val = 55;
16258 break;
16259 }
16260 case 'condensed': {
16261 $val = 70;
16262 break;
16263 }
16264 case 'semi-condensed': {
16265 $val = 85;
16266 break;
16267 }
16268 case 'normal': {
16269 $val = 100;
16270 break;
16271 }
16272 case 'semi-expanded': {
16273 $val = 115;
16274 break;
16275 }
16276 case 'expanded': {
16277 $val = 130;
16278 break;
16279 }
16280 case 'extra-expanded': {
16281 $val = 145;
16282 break;
16283 }
16284 case 'ultra-expanded': {
16285 $val = 160;
16286 break;
16287 }
16288 case 'wider': {
16289 $val = ($parent + 10);
16290 break;
16291 }
16292 case 'narrower': {
16293 $val = ($parent - 10);
16294 break;
16295 }
16296 case 'inherit': {
16297 if ($parent == 'normal') {
16298 $val = 100;
16299 } else {
16300 $val = $parent;
16301 }
16302 break;
16303 }
16304 default: {
16305 $val = $this->getHTMLUnitToUnits($stretch, 100, '%', false);
16306 }
16307 }
16308 return $val;
16309 }
16310
16311 /**
16312 * Convert HTML string containing font size value to points
16313 * @param $val (string) String containing font size value and unit.
16314 * @param $refsize (float) Reference font size in points.
16315 * @param $parent_size (float) Parent font size in points.
16316 * @param $defaultunit (string) Default unit (can be one of the following: %, em, ex, px, in, mm, pc, pt).
16317 * @return float value in points
16318 * @public
16319 */
16320 public function getHTMLFontUnits($val, $refsize=12, $parent_size=12, $defaultunit='pt') {
16321 $refsize = TCPDF_FONTS::getFontRefSize($refsize);
16322 $parent_size = TCPDF_FONTS::getFontRefSize($parent_size, $refsize);
16323 switch ($val) {
16324 case 'xx-small': {
16325 $size = ($refsize - 4);
16326 break;
16327 }
16328 case 'x-small': {
16329 $size = ($refsize - 3);
16330 break;
16331 }
16332 case 'small': {
16333 $size = ($refsize - 2);
16334 break;
16335 }
16336 case 'medium': {
16337 $size = $refsize;
16338 break;
16339 }
16340 case 'large': {
16341 $size = ($refsize + 2);
16342 break;
16343 }
16344 case 'x-large': {
16345 $size = ($refsize + 4);
16346 break;
16347 }
16348 case 'xx-large': {
16349 $size = ($refsize + 6);
16350 break;
16351 }
16352 case 'smaller': {
16353 $size = ($parent_size - 3);
16354 break;
16355 }
16356 case 'larger': {
16357 $size = ($parent_size + 3);
16358 break;
16359 }
16360 default: {
16361 $size = $this->getHTMLUnitToUnits($val, $parent_size, $defaultunit, true);
16362 }
16363 }
16364 return $size;
16365 }
16366
16367 /**
16368 * Returns the HTML DOM array.
16369 * @param $html (string) html code
16370 * @return array
16371 * @protected
16372 * @since 3.2.000 (2008-06-20)
16373 */
16374 protected function getHtmlDomArray($html) {
16375 // array of CSS styles ( selector => properties).
16376 $css = array();
16377 // get CSS array defined at previous call
16378 $matches = array();
16379 if (preg_match_all('/<cssarray>([^\<]*)<\/cssarray>/isU', $html, $matches) > 0) {
16380 if (isset($matches[1][0])) {
16381 $css = array_merge($css, json_decode($this->unhtmlentities($matches[1][0]), true));
16382 }
16383 $html = preg_replace('/<cssarray>(.*?)<\/cssarray>/isU', '', $html);
16384 }
16385 // extract external CSS files
16386 $matches = array();
16387 if (preg_match_all('/<link([^\>]*)>/isU', $html, $matches) > 0) {
16388 foreach ($matches[1] as $key => $link) {
16389 $type = array();
16390 if (preg_match('/type[\s]*=[\s]*"text\/css"/', $link, $type)) {
16391 $type = array();
16392 preg_match('/media[\s]*=[\s]*"([^"]*)"/', $link, $type);
16393 // get 'all' and 'print' media, other media types are discarded
16394 // (all, braille, embossed, handheld, print, projection, screen, speech, tty, tv)
16395 if (empty($type) OR (isset($type[1]) AND (($type[1] == 'all') OR ($type[1] == 'print')))) {
16396 $type = array();
16397 if (preg_match('/href[\s]*=[\s]*"([^"]*)"/', $link, $type) > 0) {
16398 // read CSS data file
16399 $cssdata = TCPDF_STATIC::fileGetContents(trim($type[1]));
16400 if (($cssdata !== FALSE) AND (strlen($cssdata) > 0)) {
16401 $css = array_merge($css, TCPDF_STATIC::extractCSSproperties($cssdata));
16402 }
16403 }
16404 }
16405 }
16406 }
16407 }
16408 // extract style tags
16409 $matches = array();
16410 if (preg_match_all('/<style([^\>]*)>([^\<]*)<\/style>/isU', $html, $matches) > 0) {
16411 foreach ($matches[1] as $key => $media) {
16412 $type = array();
16413 preg_match('/media[\s]*=[\s]*"([^"]*)"/', $media, $type);
16414 // get 'all' and 'print' media, other media types are discarded
16415 // (all, braille, embossed, handheld, print, projection, screen, speech, tty, tv)
16416 if (empty($type) OR (isset($type[1]) AND (($type[1] == 'all') OR ($type[1] == 'print')))) {
16417 $cssdata = $matches[2][$key];
16418 $css = array_merge($css, TCPDF_STATIC::extractCSSproperties($cssdata));
16419 }
16420 }
16421 }
16422 // create a special tag to contain the CSS array (used for table content)
16423 $csstagarray = '<cssarray>'.htmlentities(json_encode($css)).'</cssarray>';
16424 // remove head and style blocks
16425 $html = preg_replace('/<head([^\>]*)>(.*?)<\/head>/siU', '', $html);
16426 $html = preg_replace('/<style([^\>]*)>([^\<]*)<\/style>/isU', '', $html);
16427 // define block tags
16428 $blocktags = array('blockquote','br','dd','dl','div','dt','h1','h2','h3','h4','h5','h6','hr','li','ol','p','pre','ul','tcpdf','table','tr','td');
16429 // define self-closing tags
16430 $selfclosingtags = array('area','base','basefont','br','hr','input','img','link','meta');
16431 // remove all unsupported tags (the line below lists all supported tags)
16432 $html = strip_tags($html, '<marker/><a><b><blockquote><body><br><br/><dd><del><div><dl><dt><em><font><form><h1><h2><h3><h4><h5><h6><hr><hr/><i><img><input><label><li><ol><option><p><pre><s><select><small><span><strike><strong><sub><sup><table><tablehead><tcpdf><td><textarea><th><thead><tr><tt><u><ul>');
16433 //replace some blank characters
16434 $html = preg_replace('/<pre/', '<xre', $html); // preserve pre tag
16435 $html = preg_replace('/<(table|tr|td|th|tcpdf|blockquote|dd|div|dl|dt|form|h1|h2|h3|h4|h5|h6|br|hr|li|ol|ul|p)([^\>]*)>[\n\r\t]+/', '<\\1\\2>', $html);
16436 $html = preg_replace('@(\r\n|\r)@', "\n", $html);
16437 $repTable = array("\t" => ' ', "\0" => ' ', "\x0B" => ' ', "\\" => "\\\\");
16438 $html = strtr($html, $repTable);
16439 $offset = 0;
16440 while (($offset < strlen($html)) AND ($pos = strpos($html, '</pre>', $offset)) !== false) {
16441 $html_a = substr($html, 0, $offset);
16442 $html_b = substr($html, $offset, ($pos - $offset + 6));
16443 while (preg_match("'<xre([^\>]*)>(.*?)\n(.*?)</pre>'si", $html_b)) {
16444 // preserve newlines on <pre> tag
16445 $html_b = preg_replace("'<xre([^\>]*)>(.*?)\n(.*?)</pre>'si", "<xre\\1>\\2<br />\\3</pre>", $html_b);
16446 }
16447 while (preg_match("'<xre([^\>]*)>(.*?)".$this->re_space['p']."(.*?)</pre>'".$this->re_space['m'], $html_b)) {
16448 // preserve spaces on <pre> tag
16449 $html_b = preg_replace("'<xre([^\>]*)>(.*?)".$this->re_space['p']."(.*?)</pre>'".$this->re_space['m'], "<xre\\1>\\2&nbsp;\\3</pre>", $html_b);
16450 }
16451 $html = $html_a.$html_b.substr($html, $pos + 6);
16452 $offset = strlen($html_a.$html_b);
16453 }
16454 $offset = 0;
16455 while (($offset < strlen($html)) AND ($pos = strpos($html, '</textarea>', $offset)) !== false) {
16456 $html_a = substr($html, 0, $offset);
16457 $html_b = substr($html, $offset, ($pos - $offset + 11));
16458 while (preg_match("'<textarea([^\>]*)>(.*?)\n(.*?)</textarea>'si", $html_b)) {
16459 // preserve newlines on <textarea> tag
16460 $html_b = preg_replace("'<textarea([^\>]*)>(.*?)\n(.*?)</textarea>'si", "<textarea\\1>\\2<TBR>\\3</textarea>", $html_b);
16461 $html_b = preg_replace("'<textarea([^\>]*)>(.*?)[\"](.*?)</textarea>'si", "<textarea\\1>\\2''\\3</textarea>", $html_b);
16462 }
16463 $html = $html_a.$html_b.substr($html, $pos + 11);
16464 $offset = strlen($html_a.$html_b);
16465 }
16466 $html = preg_replace('/([\s]*)<option/si', '<option', $html);
16467 $html = preg_replace('/<\/option>([\s]*)/si', '</option>', $html);
16468 $offset = 0;
16469 while (($offset < strlen($html)) AND ($pos = strpos($html, '</option>', $offset)) !== false) {
16470 $html_a = substr($html, 0, $offset);
16471 $html_b = substr($html, $offset, ($pos - $offset + 9));
16472 while (preg_match("'<option([^\>]*)>(.*?)</option>'si", $html_b)) {
16473 $html_b = preg_replace("'<option([\s]+)value=\"([^\"]*)\"([^\>]*)>(.*?)</option>'si", "\\2#!TaB!#\\4#!NwL!#", $html_b);
16474 $html_b = preg_replace("'<option([^\>]*)>(.*?)</option>'si", "\\2#!NwL!#", $html_b);
16475 }
16476 $html = $html_a.$html_b.substr($html, $pos + 9);
16477 $offset = strlen($html_a.$html_b);
16478 }
16479 if (preg_match("'</select'si", $html)) {
16480 $html = preg_replace("'<select([^\>]*)>'si", "<select\\1 opt=\"", $html);
16481 $html = preg_replace("'#!NwL!#</select>'si", "\" />", $html);
16482 }
16483 $html = str_replace("\n", ' ', $html);
16484 // restore textarea newlines
16485 $html = str_replace('<TBR>', "\n", $html);
16486 // remove extra spaces from code
16487 $html = preg_replace('/[\s]+<\/(table|tr|ul|ol|dl)>/', '</\\1>', $html);
16488 $html = preg_replace('/'.$this->re_space['p'].'+<\/(td|th|li|dt|dd)>/'.$this->re_space['m'], '</\\1>', $html);
16489 $html = preg_replace('/[\s]+<(tr|td|th|li|dt|dd)/', '<\\1', $html);
16490 $html = preg_replace('/'.$this->re_space['p'].'+<(ul|ol|dl|br)/'.$this->re_space['m'], '<\\1', $html);
16491 $html = preg_replace('/<\/(table|tr|td|th|blockquote|dd|dt|dl|div|dt|h1|h2|h3|h4|h5|h6|hr|li|ol|ul|p)>[\s]+</', '</\\1><', $html);
16492 $html = preg_replace('/<\/(td|th)>/', '<marker style="font-size:0"/></\\1>', $html);
16493 $html = preg_replace('/<\/table>([\s]*)<marker style="font-size:0"\/>/', '</table>', $html);
16494 $html = preg_replace('/'.$this->re_space['p'].'+<img/'.$this->re_space['m'], chr(32).'<img', $html);
16495 $html = preg_replace('/<img([^\>]*)>[\s]+([^\<])/xi', '<img\\1>&nbsp;\\2', $html);
16496 $html = preg_replace('/<img([^\>]*)>/xi', '<img\\1><span><marker style="font-size:0"/></span>', $html);
16497 $html = preg_replace('/<xre/', '<pre', $html); // restore pre tag
16498 $html = preg_replace('/<textarea([^\>]*)>([^\<]*)<\/textarea>/xi', '<textarea\\1 value="\\2" />', $html);
16499 $html = preg_replace('/<li([^\>]*)><\/li>/', '<li\\1>&nbsp;</li>', $html);
16500 $html = preg_replace('/<li([^\>]*)>'.$this->re_space['p'].'*<img/'.$this->re_space['m'], '<li\\1><font size="1">&nbsp;</font><img', $html);
16501 $html = preg_replace('/<([^\>\/]*)>[\s]/', '<\\1>&nbsp;', $html); // preserve some spaces
16502 $html = preg_replace('/[\s]<\/([^\>]*)>/', '&nbsp;</\\1>', $html); // preserve some spaces
16503 $html = preg_replace('/<su([bp])/', '<zws/><su\\1', $html); // fix sub/sup alignment
16504 $html = preg_replace('/<\/su([bp])>/', '</su\\1><zws/>', $html); // fix sub/sup alignment
16505 $html = preg_replace('/'.$this->re_space['p'].'+/'.$this->re_space['m'], chr(32), $html); // replace multiple spaces with a single space
16506 // trim string
16507 $html = $this->stringTrim($html);
16508 // fix br tag after li
16509 $html = preg_replace('/<li><br([^\>]*)>/', '<li> <br\\1>', $html);
16510 // fix first image tag alignment
16511 $html = preg_replace('/^<img/', '<span style="font-size:0"><br /></span> <img', $html, 1);
16512 // pattern for generic tag
16513 $tagpattern = '/(<[^>]+>)/';
16514 // explodes the string
16515 $a = preg_split($tagpattern, $html, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
16516 // count elements
16517 $maxel = count($a);
16518 $elkey = 0;
16519 $key = 0;
16520 // create an array of elements
16521 $dom = array();
16522 $dom[$key] = array();
16523 // set inheritable properties fot the first void element
16524 // possible inheritable properties are: azimuth, border-collapse, border-spacing, caption-side, color, cursor, direction, empty-cells, font, font-family, font-stretch, font-size, font-size-adjust, font-style, font-variant, font-weight, letter-spacing, line-height, list-style, list-style-image, list-style-position, list-style-type, orphans, page, page-break-inside, quotes, speak, speak-header, text-align, text-indent, text-transform, volume, white-space, widows, word-spacing
16525 $dom[$key]['tag'] = false;
16526 $dom[$key]['block'] = false;
16527 $dom[$key]['value'] = '';
16528 $dom[$key]['parent'] = 0;
16529 $dom[$key]['hide'] = false;
16530 $dom[$key]['fontname'] = $this->FontFamily;
16531 $dom[$key]['fontstyle'] = $this->FontStyle;
16532 $dom[$key]['fontsize'] = $this->FontSizePt;
16533 $dom[$key]['font-stretch'] = $this->font_stretching;
16534 $dom[$key]['letter-spacing'] = $this->font_spacing;
16535 $dom[$key]['stroke'] = $this->textstrokewidth;
16536 $dom[$key]['fill'] = (($this->textrendermode % 2) == 0);
16537 $dom[$key]['clip'] = ($this->textrendermode > 3);
16538 $dom[$key]['line-height'] = $this->cell_height_ratio;
16539 $dom[$key]['bgcolor'] = false;
16540 $dom[$key]['fgcolor'] = $this->fgcolor; // color
16541 $dom[$key]['strokecolor'] = $this->strokecolor;
16542 $dom[$key]['align'] = '';
16543 $dom[$key]['listtype'] = '';
16544 $dom[$key]['text-indent'] = 0;
16545 $dom[$key]['text-transform'] = '';
16546 $dom[$key]['border'] = array();
16547 $dom[$key]['dir'] = $this->rtl?'rtl':'ltr';
16548 $thead = false; // true when we are inside the THEAD tag
16549 ++$key;
16550 $level = array();
16551 array_push($level, 0); // root
16552 while ($elkey < $maxel) {
16553 $dom[$key] = array();
16554 $element = $a[$elkey];
16555 $dom[$key]['elkey'] = $elkey;
16556 if (preg_match($tagpattern, $element)) {
16557 // html tag
16558 $element = substr($element, 1, -1);
16559 // get tag name
16560 preg_match('/[\/]?([a-zA-Z0-9]*)/', $element, $tag);
16561 $tagname = strtolower($tag[1]);
16562 // check if we are inside a table header
16563 if ($tagname == 'thead') {
16564 if ($element[0] == '/') {
16565 $thead = false;
16566 } else {
16567 $thead = true;
16568 }
16569 ++$elkey;
16570 continue;
16571 }
16572 $dom[$key]['tag'] = true;
16573 $dom[$key]['value'] = $tagname;
16574 if (in_array($dom[$key]['value'], $blocktags)) {
16575 $dom[$key]['block'] = true;
16576 } else {
16577 $dom[$key]['block'] = false;
16578 }
16579 if ($element[0] == '/') {
16580 // *** closing html tag
16581 $dom[$key]['opening'] = false;
16582 $dom[$key]['parent'] = end($level);
16583 array_pop($level);
16584 $dom[$key]['hide'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['hide'];
16585 $dom[$key]['fontname'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['fontname'];
16586 $dom[$key]['fontstyle'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['fontstyle'];
16587 $dom[$key]['fontsize'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['fontsize'];
16588 $dom[$key]['font-stretch'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['font-stretch'];
16589 $dom[$key]['letter-spacing'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['letter-spacing'];
16590 $dom[$key]['stroke'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['stroke'];
16591 $dom[$key]['fill'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['fill'];
16592 $dom[$key]['clip'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['clip'];
16593 $dom[$key]['line-height'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['line-height'];
16594 $dom[$key]['bgcolor'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['bgcolor'];
16595 $dom[$key]['fgcolor'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['fgcolor'];
16596 $dom[$key]['strokecolor'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['strokecolor'];
16597 $dom[$key]['align'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['align'];
16598 $dom[$key]['text-transform'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['text-transform'];
16599 $dom[$key]['dir'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['dir'];
16600 if (isset($dom[($dom[($dom[$key]['parent'])]['parent'])]['listtype'])) {
16601 $dom[$key]['listtype'] = $dom[($dom[($dom[$key]['parent'])]['parent'])]['listtype'];
16602 }
16603 // set the number of columns in table tag
16604 if (($dom[$key]['value'] == 'tr') AND (!isset($dom[($dom[($dom[$key]['parent'])]['parent'])]['cols']))) {
16605 $dom[($dom[($dom[$key]['parent'])]['parent'])]['cols'] = $dom[($dom[$key]['parent'])]['cols'];
16606 }
16607 if (($dom[$key]['value'] == 'td') OR ($dom[$key]['value'] == 'th')) {
16608 $dom[($dom[$key]['parent'])]['content'] = $csstagarray;
16609 for ($i = ($dom[$key]['parent'] + 1); $i < $key; ++$i) {
16610 $dom[($dom[$key]['parent'])]['content'] .= $a[$dom[$i]['elkey']];
16611 }
16612 $key = $i;
16613 // mark nested tables
16614 $dom[($dom[$key]['parent'])]['content'] = str_replace('<table', '<table nested="true"', $dom[($dom[$key]['parent'])]['content']);
16615 // remove thead sections from nested tables
16616 $dom[($dom[$key]['parent'])]['content'] = str_replace('<thead>', '', $dom[($dom[$key]['parent'])]['content']);
16617 $dom[($dom[$key]['parent'])]['content'] = str_replace('</thead>', '', $dom[($dom[$key]['parent'])]['content']);
16618 }
16619 // store header rows on a new table
16620 if (($dom[$key]['value'] == 'tr') AND ($dom[($dom[$key]['parent'])]['thead'] === true)) {
16621 if (TCPDF_STATIC::empty_string($dom[($dom[($dom[$key]['parent'])]['parent'])]['thead'])) {
16622 $dom[($dom[($dom[$key]['parent'])]['parent'])]['thead'] = $csstagarray.$a[$dom[($dom[($dom[$key]['parent'])]['parent'])]['elkey']];
16623 }
16624 for ($i = $dom[$key]['parent']; $i <= $key; ++$i) {
16625 $dom[($dom[($dom[$key]['parent'])]['parent'])]['thead'] .= $a[$dom[$i]['elkey']];
16626 }
16627 if (!isset($dom[($dom[$key]['parent'])]['attribute'])) {
16628 $dom[($dom[$key]['parent'])]['attribute'] = array();
16629 }
16630 // header elements must be always contained in a single page
16631 $dom[($dom[$key]['parent'])]['attribute']['nobr'] = 'true';
16632 }
16633 if (($dom[$key]['value'] == 'table') AND (!TCPDF_STATIC::empty_string($dom[($dom[$key]['parent'])]['thead']))) {
16634 // remove the nobr attributes from the table header
16635 $dom[($dom[$key]['parent'])]['thead'] = str_replace(' nobr="true"', '', $dom[($dom[$key]['parent'])]['thead']);
16636 $dom[($dom[$key]['parent'])]['thead'] .= '</tablehead>';
16637 }
16638 } else {
16639 // *** opening or self-closing html tag
16640 $dom[$key]['opening'] = true;
16641 $dom[$key]['parent'] = end($level);
16642 if ((substr($element, -1, 1) == '/') OR (in_array($dom[$key]['value'], $selfclosingtags))) {
16643 // self-closing tag
16644 $dom[$key]['self'] = true;
16645 } else {
16646 // opening tag
16647 array_push($level, $key);
16648 $dom[$key]['self'] = false;
16649 }
16650 // copy some values from parent
16651 $parentkey = 0;
16652 if ($key > 0) {
16653 $parentkey = $dom[$key]['parent'];
16654 $dom[$key]['hide'] = $dom[$parentkey]['hide'];
16655 $dom[$key]['fontname'] = $dom[$parentkey]['fontname'];
16656 $dom[$key]['fontstyle'] = $dom[$parentkey]['fontstyle'];
16657 $dom[$key]['fontsize'] = $dom[$parentkey]['fontsize'];
16658 $dom[$key]['font-stretch'] = $dom[$parentkey]['font-stretch'];
16659 $dom[$key]['letter-spacing'] = $dom[$parentkey]['letter-spacing'];
16660 $dom[$key]['stroke'] = $dom[$parentkey]['stroke'];
16661 $dom[$key]['fill'] = $dom[$parentkey]['fill'];
16662 $dom[$key]['clip'] = $dom[$parentkey]['clip'];
16663 $dom[$key]['line-height'] = $dom[$parentkey]['line-height'];
16664 $dom[$key]['bgcolor'] = $dom[$parentkey]['bgcolor'];
16665 $dom[$key]['fgcolor'] = $dom[$parentkey]['fgcolor'];
16666 $dom[$key]['strokecolor'] = $dom[$parentkey]['strokecolor'];
16667 $dom[$key]['align'] = $dom[$parentkey]['align'];
16668 $dom[$key]['listtype'] = $dom[$parentkey]['listtype'];
16669 $dom[$key]['text-indent'] = $dom[$parentkey]['text-indent'];
16670 $dom[$key]['text-transform'] = $dom[$parentkey]['text-transform'];
16671 $dom[$key]['border'] = array();
16672 $dom[$key]['dir'] = $dom[$parentkey]['dir'];
16673 }
16674 // get attributes
16675 preg_match_all('/([^=\s]*)[\s]*=[\s]*"([^"]*)"/', $element, $attr_array, PREG_PATTERN_ORDER);
16676 $dom[$key]['attribute'] = array(); // reset attribute array
16677 while (list($id, $name) = each($attr_array[1])) {
16678 $dom[$key]['attribute'][strtolower($name)] = $attr_array[2][$id];
16679 }
16680 if (!empty($css)) {
16681 // merge CSS style to current style
16682 list($dom[$key]['csssel'], $dom[$key]['cssdata']) = TCPDF_STATIC::getCSSdataArray($dom, $key, $css);
16683 $dom[$key]['attribute']['style'] = TCPDF_STATIC::getTagStyleFromCSSarray($dom[$key]['cssdata']);
16684 }
16685 // split style attributes
16686 if (isset($dom[$key]['attribute']['style']) AND !empty($dom[$key]['attribute']['style'])) {
16687 // get style attributes
16688 preg_match_all('/([^;:\s]*):([^;]*)/', $dom[$key]['attribute']['style'], $style_array, PREG_PATTERN_ORDER);
16689 $dom[$key]['style'] = array(); // reset style attribute array
16690 while (list($id, $name) = each($style_array[1])) {
16691 // in case of duplicate attribute the last replace the previous
16692 $dom[$key]['style'][strtolower($name)] = trim($style_array[2][$id]);
16693 }
16694 // --- get some style attributes ---
16695 // text direction
16696 if (isset($dom[$key]['style']['direction'])) {
16697 $dom[$key]['dir'] = $dom[$key]['style']['direction'];
16698 }
16699 // display
16700 if (isset($dom[$key]['style']['display'])) {
16701 $dom[$key]['hide'] = (trim(strtolower($dom[$key]['style']['display'])) == 'none');
16702 }
16703 // font family
16704 if (isset($dom[$key]['style']['font-family'])) {
16705 $dom[$key]['fontname'] = $this->getFontFamilyName($dom[$key]['style']['font-family']);
16706 }
16707 // list-style-type
16708 if (isset($dom[$key]['style']['list-style-type'])) {
16709 $dom[$key]['listtype'] = trim(strtolower($dom[$key]['style']['list-style-type']));
16710 if ($dom[$key]['listtype'] == 'inherit') {
16711 $dom[$key]['listtype'] = $dom[$parentkey]['listtype'];
16712 }
16713 }
16714 // text-indent
16715 if (isset($dom[$key]['style']['text-indent'])) {
16716 $dom[$key]['text-indent'] = $this->getHTMLUnitToUnits($dom[$key]['style']['text-indent']);
16717 if ($dom[$key]['text-indent'] == 'inherit') {
16718 $dom[$key]['text-indent'] = $dom[$parentkey]['text-indent'];
16719 }
16720 }
16721 // text-transform
16722 if (isset($dom[$key]['style']['text-transform'])) {
16723 $dom[$key]['text-transform'] = $dom[$key]['style']['text-transform'];
16724 }
16725 // font size
16726 if (isset($dom[$key]['style']['font-size'])) {
16727 $fsize = trim($dom[$key]['style']['font-size']);
16728 $dom[$key]['fontsize'] = $this->getHTMLFontUnits($fsize, $dom[0]['fontsize'], $dom[$parentkey]['fontsize'], 'pt');
16729 }
16730 // font-stretch
16731 if (isset($dom[$key]['style']['font-stretch'])) {
16732 $dom[$key]['font-stretch'] = $this->getCSSFontStretching($dom[$key]['style']['font-stretch'], $dom[$parentkey]['font-stretch']);
16733 }
16734 // letter-spacing
16735 if (isset($dom[$key]['style']['letter-spacing'])) {
16736 $dom[$key]['letter-spacing'] = $this->getCSSFontSpacing($dom[$key]['style']['letter-spacing'], $dom[$parentkey]['letter-spacing']);
16737 }
16738 // line-height (internally is the cell height ratio)
16739 if (isset($dom[$key]['style']['line-height'])) {
16740 $lineheight = trim($dom[$key]['style']['line-height']);
16741 switch ($lineheight) {
16742 // A normal line height. This is default
16743 case 'normal': {
16744 $dom[$key]['line-height'] = $dom[0]['line-height'];
16745 break;
16746 }
16747 case 'inherit': {
16748 $dom[$key]['line-height'] = $dom[$parentkey]['line-height'];
16749 }
16750 default: {
16751 if (is_numeric($lineheight)) {
16752 // convert to percentage of font height
16753 $lineheight = ($lineheight * 100).'%';
16754 }
16755 $dom[$key]['line-height'] = $this->getHTMLUnitToUnits($lineheight, 1, '%', true);
16756 if (substr($lineheight, -1) !== '%') {
16757 if ($dom[$key]['fontsize'] <= 0) {
16758 $dom[$key]['line-height'] = 1;
16759 } else {
16760 $dom[$key]['line-height'] = (($dom[$key]['line-height'] - $this->cell_padding['T'] - $this->cell_padding['B']) / $dom[$key]['fontsize']);
16761 }
16762 }
16763 }
16764 }
16765 }
16766 // font style
16767 if (isset($dom[$key]['style']['font-weight'])) {
16768 if (strtolower($dom[$key]['style']['font-weight'][0]) == 'n') {
16769 if (strpos($dom[$key]['fontstyle'], 'B') !== false) {
16770 $dom[$key]['fontstyle'] = str_replace('B', '', $dom[$key]['fontstyle']);
16771 }
16772 } elseif (strtolower($dom[$key]['style']['font-weight'][0]) == 'b') {
16773 $dom[$key]['fontstyle'] .= 'B';
16774 }
16775 }
16776 if (isset($dom[$key]['style']['font-style']) AND (strtolower($dom[$key]['style']['font-style'][0]) == 'i')) {
16777 $dom[$key]['fontstyle'] .= 'I';
16778 }
16779 // font color
16780 if (isset($dom[$key]['style']['color']) AND (!TCPDF_STATIC::empty_string($dom[$key]['style']['color']))) {
16781 $dom[$key]['fgcolor'] = TCPDF_COLORS::convertHTMLColorToDec($dom[$key]['style']['color'], $this->spot_colors);
16782 } elseif ($dom[$key]['value'] == 'a') {
16783 $dom[$key]['fgcolor'] = $this->htmlLinkColorArray;
16784 }
16785 // background color
16786 if (isset($dom[$key]['style']['background-color']) AND (!TCPDF_STATIC::empty_string($dom[$key]['style']['background-color']))) {
16787 $dom[$key]['bgcolor'] = TCPDF_COLORS::convertHTMLColorToDec($dom[$key]['style']['background-color'], $this->spot_colors);
16788 }
16789 // text-decoration
16790 if (isset($dom[$key]['style']['text-decoration'])) {
16791 $decors = explode(' ', strtolower($dom[$key]['style']['text-decoration']));
16792 foreach ($decors as $dec) {
16793 $dec = trim($dec);
16794 if (!TCPDF_STATIC::empty_string($dec)) {
16795 if ($dec[0] == 'u') {
16796 // underline
16797 $dom[$key]['fontstyle'] .= 'U';
16798 } elseif ($dec[0] == 'l') {
16799 // line-through
16800 $dom[$key]['fontstyle'] .= 'D';
16801 } elseif ($dec[0] == 'o') {
16802 // overline
16803 $dom[$key]['fontstyle'] .= 'O';
16804 }
16805 }
16806 }
16807 } elseif ($dom[$key]['value'] == 'a') {
16808 $dom[$key]['fontstyle'] = $this->htmlLinkFontStyle;
16809 }
16810 // check for width attribute
16811 if (isset($dom[$key]['style']['width'])) {
16812 $dom[$key]['width'] = $dom[$key]['style']['width'];
16813 }
16814 // check for height attribute
16815 if (isset($dom[$key]['style']['height'])) {
16816 $dom[$key]['height'] = $dom[$key]['style']['height'];
16817 }
16818 // check for text alignment
16819 if (isset($dom[$key]['style']['text-align'])) {
16820 $dom[$key]['align'] = strtoupper($dom[$key]['style']['text-align'][0]);
16821 }
16822 // check for CSS border properties
16823 if (isset($dom[$key]['style']['border'])) {
16824 $borderstyle = $this->getCSSBorderStyle($dom[$key]['style']['border']);
16825 if (!empty($borderstyle)) {
16826 $dom[$key]['border']['LTRB'] = $borderstyle;
16827 }
16828 }
16829 if (isset($dom[$key]['style']['border-color'])) {
16830 $brd_colors = preg_split('/[\s]+/', trim($dom[$key]['style']['border-color']));
16831 if (isset($brd_colors[3])) {
16832 $dom[$key]['border']['L']['color'] = TCPDF_COLORS::convertHTMLColorToDec($brd_colors[3], $this->spot_colors);
16833 }
16834 if (isset($brd_colors[1])) {
16835 $dom[$key]['border']['R']['color'] = TCPDF_COLORS::convertHTMLColorToDec($brd_colors[1], $this->spot_colors);
16836 }
16837 if (isset($brd_colors[0])) {
16838 $dom[$key]['border']['T']['color'] = TCPDF_COLORS::convertHTMLColorToDec($brd_colors[0], $this->spot_colors);
16839 }
16840 if (isset($brd_colors[2])) {
16841 $dom[$key]['border']['B']['color'] = TCPDF_COLORS::convertHTMLColorToDec($brd_colors[2], $this->spot_colors);
16842 }
16843 }
16844 if (isset($dom[$key]['style']['border-width'])) {
16845 $brd_widths = preg_split('/[\s]+/', trim($dom[$key]['style']['border-width']));
16846 if (isset($brd_widths[3])) {
16847 $dom[$key]['border']['L']['width'] = $this->getCSSBorderWidth($brd_widths[3]);
16848 }
16849 if (isset($brd_widths[1])) {
16850 $dom[$key]['border']['R']['width'] = $this->getCSSBorderWidth($brd_widths[1]);
16851 }
16852 if (isset($brd_widths[0])) {
16853 $dom[$key]['border']['T']['width'] = $this->getCSSBorderWidth($brd_widths[0]);
16854 }
16855 if (isset($brd_widths[2])) {
16856 $dom[$key]['border']['B']['width'] = $this->getCSSBorderWidth($brd_widths[2]);
16857 }
16858 }
16859 if (isset($dom[$key]['style']['border-style'])) {
16860 $brd_styles = preg_split('/[\s]+/', trim($dom[$key]['style']['border-style']));
16861 if (isset($brd_styles[3]) AND ($brd_styles[3]!='none')) {
16862 $dom[$key]['border']['L']['cap'] = 'square';
16863 $dom[$key]['border']['L']['join'] = 'miter';
16864 $dom[$key]['border']['L']['dash'] = $this->getCSSBorderDashStyle($brd_styles[3]);
16865 if ($dom[$key]['border']['L']['dash'] < 0) {
16866 $dom[$key]['border']['L'] = array();
16867 }
16868 }
16869 if (isset($brd_styles[1])) {
16870 $dom[$key]['border']['R']['cap'] = 'square';
16871 $dom[$key]['border']['R']['join'] = 'miter';
16872 $dom[$key]['border']['R']['dash'] = $this->getCSSBorderDashStyle($brd_styles[1]);
16873 if ($dom[$key]['border']['R']['dash'] < 0) {
16874 $dom[$key]['border']['R'] = array();
16875 }
16876 }
16877 if (isset($brd_styles[0])) {
16878 $dom[$key]['border']['T']['cap'] = 'square';
16879 $dom[$key]['border']['T']['join'] = 'miter';
16880 $dom[$key]['border']['T']['dash'] = $this->getCSSBorderDashStyle($brd_styles[0]);
16881 if ($dom[$key]['border']['T']['dash'] < 0) {
16882 $dom[$key]['border']['T'] = array();
16883 }
16884 }
16885 if (isset($brd_styles[2])) {
16886 $dom[$key]['border']['B']['cap'] = 'square';
16887 $dom[$key]['border']['B']['join'] = 'miter';
16888 $dom[$key]['border']['B']['dash'] = $this->getCSSBorderDashStyle($brd_styles[2]);
16889 if ($dom[$key]['border']['B']['dash'] < 0) {
16890 $dom[$key]['border']['B'] = array();
16891 }
16892 }
16893 }
16894 $cellside = array('L' => 'left', 'R' => 'right', 'T' => 'top', 'B' => 'bottom');
16895 foreach ($cellside as $bsk => $bsv) {
16896 if (isset($dom[$key]['style']['border-'.$bsv])) {
16897 $borderstyle = $this->getCSSBorderStyle($dom[$key]['style']['border-'.$bsv]);
16898 if (!empty($borderstyle)) {
16899 $dom[$key]['border'][$bsk] = $borderstyle;
16900 }
16901 }
16902 if (isset($dom[$key]['style']['border-'.$bsv.'-color'])) {
16903 $dom[$key]['border'][$bsk]['color'] = TCPDF_COLORS::convertHTMLColorToDec($dom[$key]['style']['border-'.$bsv.'-color'], $this->spot_colors);
16904 }
16905 if (isset($dom[$key]['style']['border-'.$bsv.'-width'])) {
16906 $dom[$key]['border'][$bsk]['width'] = $this->getCSSBorderWidth($dom[$key]['style']['border-'.$bsv.'-width']);
16907 }
16908 if (isset($dom[$key]['style']['border-'.$bsv.'-style'])) {
16909 $dom[$key]['border'][$bsk]['dash'] = $this->getCSSBorderDashStyle($dom[$key]['style']['border-'.$bsv.'-style']);
16910 if ($dom[$key]['border'][$bsk]['dash'] < 0) {
16911 $dom[$key]['border'][$bsk] = array();
16912 }
16913 }
16914 }
16915 // check for CSS padding properties
16916 if (isset($dom[$key]['style']['padding'])) {
16917 $dom[$key]['padding'] = $this->getCSSPadding($dom[$key]['style']['padding']);
16918 } else {
16919 $dom[$key]['padding'] = $this->cell_padding;
16920 }
16921 foreach ($cellside as $psk => $psv) {
16922 if (isset($dom[$key]['style']['padding-'.$psv])) {
16923 $dom[$key]['padding'][$psk] = $this->getHTMLUnitToUnits($dom[$key]['style']['padding-'.$psv], 0, 'px', false);
16924 }
16925 }
16926 // check for CSS margin properties
16927 if (isset($dom[$key]['style']['margin'])) {
16928 $dom[$key]['margin'] = $this->getCSSMargin($dom[$key]['style']['margin']);
16929 } else {
16930 $dom[$key]['margin'] = $this->cell_margin;
16931 }
16932 foreach ($cellside as $psk => $psv) {
16933 if (isset($dom[$key]['style']['margin-'.$psv])) {
16934 $dom[$key]['margin'][$psk] = $this->getHTMLUnitToUnits(str_replace('auto', '0', $dom[$key]['style']['margin-'.$psv]), 0, 'px', false);
16935 }
16936 }
16937 // check for CSS border-spacing properties
16938 if (isset($dom[$key]['style']['border-spacing'])) {
16939 $dom[$key]['border-spacing'] = $this->getCSSBorderMargin($dom[$key]['style']['border-spacing']);
16940 }
16941 // page-break-inside
16942 if (isset($dom[$key]['style']['page-break-inside']) AND ($dom[$key]['style']['page-break-inside'] == 'avoid')) {
16943 $dom[$key]['attribute']['nobr'] = 'true';
16944 }
16945 // page-break-before
16946 if (isset($dom[$key]['style']['page-break-before'])) {
16947 if ($dom[$key]['style']['page-break-before'] == 'always') {
16948 $dom[$key]['attribute']['pagebreak'] = 'true';
16949 } elseif ($dom[$key]['style']['page-break-before'] == 'left') {
16950 $dom[$key]['attribute']['pagebreak'] = 'left';
16951 } elseif ($dom[$key]['style']['page-break-before'] == 'right') {
16952 $dom[$key]['attribute']['pagebreak'] = 'right';
16953 }
16954 }
16955 // page-break-after
16956 if (isset($dom[$key]['style']['page-break-after'])) {
16957 if ($dom[$key]['style']['page-break-after'] == 'always') {
16958 $dom[$key]['attribute']['pagebreakafter'] = 'true';
16959 } elseif ($dom[$key]['style']['page-break-after'] == 'left') {
16960 $dom[$key]['attribute']['pagebreakafter'] = 'left';
16961 } elseif ($dom[$key]['style']['page-break-after'] == 'right') {
16962 $dom[$key]['attribute']['pagebreakafter'] = 'right';
16963 }
16964 }
16965 }
16966 if (isset($dom[$key]['attribute']['display'])) {
16967 $dom[$key]['hide'] = (trim(strtolower($dom[$key]['attribute']['display'])) == 'none');
16968 }
16969 if (isset($dom[$key]['attribute']['border']) AND ($dom[$key]['attribute']['border'] != 0)) {
16970 $borderstyle = $this->getCSSBorderStyle($dom[$key]['attribute']['border'].' solid black');
16971 if (!empty($borderstyle)) {
16972 $dom[$key]['border']['LTRB'] = $borderstyle;
16973 }
16974 }
16975 // check for font tag
16976 if ($dom[$key]['value'] == 'font') {
16977 // font family
16978 if (isset($dom[$key]['attribute']['face'])) {
16979 $dom[$key]['fontname'] = $this->getFontFamilyName($dom[$key]['attribute']['face']);
16980 }
16981 // font size
16982 if (isset($dom[$key]['attribute']['size'])) {
16983 if ($key > 0) {
16984 if ($dom[$key]['attribute']['size'][0] == '+') {
16985 $dom[$key]['fontsize'] = $dom[($dom[$key]['parent'])]['fontsize'] + intval(substr($dom[$key]['attribute']['size'], 1));
16986 } elseif ($dom[$key]['attribute']['size'][0] == '-') {
16987 $dom[$key]['fontsize'] = $dom[($dom[$key]['parent'])]['fontsize'] - intval(substr($dom[$key]['attribute']['size'], 1));
16988 } else {
16989 $dom[$key]['fontsize'] = intval($dom[$key]['attribute']['size']);
16990 }
16991 } else {
16992 $dom[$key]['fontsize'] = intval($dom[$key]['attribute']['size']);
16993 }
16994 }
16995 }
16996 // force natural alignment for lists
16997 if ((($dom[$key]['value'] == 'ul') OR ($dom[$key]['value'] == 'ol') OR ($dom[$key]['value'] == 'dl'))
16998 AND (!isset($dom[$key]['align']) OR TCPDF_STATIC::empty_string($dom[$key]['align']) OR ($dom[$key]['align'] != 'J'))) {
16999 if ($this->rtl) {
17000 $dom[$key]['align'] = 'R';
17001 } else {
17002 $dom[$key]['align'] = 'L';
17003 }
17004 }
17005 if (($dom[$key]['value'] == 'small') OR ($dom[$key]['value'] == 'sup') OR ($dom[$key]['value'] == 'sub')) {
17006 if (!isset($dom[$key]['attribute']['size']) AND !isset($dom[$key]['style']['font-size'])) {
17007 $dom[$key]['fontsize'] = $dom[$key]['fontsize'] * K_SMALL_RATIO;
17008 }
17009 }
17010 if (($dom[$key]['value'] == 'strong') OR ($dom[$key]['value'] == 'b')) {
17011 $dom[$key]['fontstyle'] .= 'B';
17012 }
17013 if (($dom[$key]['value'] == 'em') OR ($dom[$key]['value'] == 'i')) {
17014 $dom[$key]['fontstyle'] .= 'I';
17015 }
17016 if ($dom[$key]['value'] == 'u') {
17017 $dom[$key]['fontstyle'] .= 'U';
17018 }
17019 if (($dom[$key]['value'] == 'del') OR ($dom[$key]['value'] == 's') OR ($dom[$key]['value'] == 'strike')) {
17020 $dom[$key]['fontstyle'] .= 'D';
17021 }
17022 if (!isset($dom[$key]['style']['text-decoration']) AND ($dom[$key]['value'] == 'a')) {
17023 $dom[$key]['fontstyle'] = $this->htmlLinkFontStyle;
17024 }
17025 if (($dom[$key]['value'] == 'pre') OR ($dom[$key]['value'] == 'tt')) {
17026 $dom[$key]['fontname'] = $this->default_monospaced_font;
17027 }
17028 if (!empty($dom[$key]['value']) AND ($dom[$key]['value'][0] == 'h') AND (intval($dom[$key]['value']{1}) > 0) AND (intval($dom[$key]['value']{1}) < 7)) {
17029 // headings h1, h2, h3, h4, h5, h6
17030 if (!isset($dom[$key]['attribute']['size']) AND !isset($dom[$key]['style']['font-size'])) {
17031 $headsize = (4 - intval($dom[$key]['value']{1})) * 2;
17032 $dom[$key]['fontsize'] = $dom[0]['fontsize'] + $headsize;
17033 }
17034 if (!isset($dom[$key]['style']['font-weight'])) {
17035 $dom[$key]['fontstyle'] .= 'B';
17036 }
17037 }
17038 if (($dom[$key]['value'] == 'table')) {
17039 $dom[$key]['rows'] = 0; // number of rows
17040 $dom[$key]['trids'] = array(); // IDs of TR elements
17041 $dom[$key]['thead'] = ''; // table header rows
17042 }
17043 if (($dom[$key]['value'] == 'tr')) {
17044 $dom[$key]['cols'] = 0;
17045 if ($thead) {
17046 $dom[$key]['thead'] = true;
17047 // rows on thead block are printed as a separate table
17048 } else {
17049 $dom[$key]['thead'] = false;
17050 // store the number of rows on table element
17051 ++$dom[($dom[$key]['parent'])]['rows'];
17052 // store the TR elements IDs on table element
17053 array_push($dom[($dom[$key]['parent'])]['trids'], $key);
17054 }
17055 }
17056 if (($dom[$key]['value'] == 'th') OR ($dom[$key]['value'] == 'td')) {
17057 if (isset($dom[$key]['attribute']['colspan'])) {
17058 $colspan = intval($dom[$key]['attribute']['colspan']);
17059 } else {
17060 $colspan = 1;
17061 }
17062 $dom[$key]['attribute']['colspan'] = $colspan;
17063 $dom[($dom[$key]['parent'])]['cols'] += $colspan;
17064 }
17065 // text direction
17066 if (isset($dom[$key]['attribute']['dir'])) {
17067 $dom[$key]['dir'] = $dom[$key]['attribute']['dir'];
17068 }
17069 // set foreground color attribute
17070 if (isset($dom[$key]['attribute']['color']) AND (!TCPDF_STATIC::empty_string($dom[$key]['attribute']['color']))) {
17071 $dom[$key]['fgcolor'] = TCPDF_COLORS::convertHTMLColorToDec($dom[$key]['attribute']['color'], $this->spot_colors);
17072 } elseif (!isset($dom[$key]['style']['color']) AND ($dom[$key]['value'] == 'a')) {
17073 $dom[$key]['fgcolor'] = $this->htmlLinkColorArray;
17074 }
17075 // set background color attribute
17076 if (isset($dom[$key]['attribute']['bgcolor']) AND (!TCPDF_STATIC::empty_string($dom[$key]['attribute']['bgcolor']))) {
17077 $dom[$key]['bgcolor'] = TCPDF_COLORS::convertHTMLColorToDec($dom[$key]['attribute']['bgcolor'], $this->spot_colors);
17078 }
17079 // set stroke color attribute
17080 if (isset($dom[$key]['attribute']['strokecolor']) AND (!TCPDF_STATIC::empty_string($dom[$key]['attribute']['strokecolor']))) {
17081 $dom[$key]['strokecolor'] = TCPDF_COLORS::convertHTMLColorToDec($dom[$key]['attribute']['strokecolor'], $this->spot_colors);
17082 }
17083 // check for width attribute
17084 if (isset($dom[$key]['attribute']['width'])) {
17085 $dom[$key]['width'] = $dom[$key]['attribute']['width'];
17086 }
17087 // check for height attribute
17088 if (isset($dom[$key]['attribute']['height'])) {
17089 $dom[$key]['height'] = $dom[$key]['attribute']['height'];
17090 }
17091 // check for text alignment
17092 if (isset($dom[$key]['attribute']['align']) AND (!TCPDF_STATIC::empty_string($dom[$key]['attribute']['align'])) AND ($dom[$key]['value'] !== 'img')) {
17093 $dom[$key]['align'] = strtoupper($dom[$key]['attribute']['align'][0]);
17094 }
17095 // check for text rendering mode (the following attributes do not exist in HTML)
17096 if (isset($dom[$key]['attribute']['stroke'])) {
17097 // font stroke width
17098 $dom[$key]['stroke'] = $this->getHTMLUnitToUnits($dom[$key]['attribute']['stroke'], $dom[$key]['fontsize'], 'pt', true);
17099 }
17100 if (isset($dom[$key]['attribute']['fill'])) {
17101 // font fill
17102 if ($dom[$key]['attribute']['fill'] == 'true') {
17103 $dom[$key]['fill'] = true;
17104 } else {
17105 $dom[$key]['fill'] = false;
17106 }
17107 }
17108 if (isset($dom[$key]['attribute']['clip'])) {
17109 // clipping mode
17110 if ($dom[$key]['attribute']['clip'] == 'true') {
17111 $dom[$key]['clip'] = true;
17112 } else {
17113 $dom[$key]['clip'] = false;
17114 }
17115 }
17116 } // end opening tag
17117 } else {
17118 // text
17119 $dom[$key]['tag'] = false;
17120 $dom[$key]['block'] = false;
17121 $dom[$key]['parent'] = end($level);
17122 $dom[$key]['dir'] = $dom[$dom[$key]['parent']]['dir'];
17123 if (!empty($dom[$dom[$key]['parent']]['text-transform'])) {
17124 // text-transform for unicode requires mb_convert_case (Multibyte String Functions)
17125 if (function_exists('mb_convert_case')) {
17126 $ttm = array('capitalize' => MB_CASE_TITLE, 'uppercase' => MB_CASE_UPPER, 'lowercase' => MB_CASE_LOWER);
17127 if (isset($ttm[$dom[$dom[$key]['parent']]['text-transform']])) {
17128 $element = mb_convert_case($element, $ttm[$dom[$dom[$key]['parent']]['text-transform']], $this->encoding);
17129 }
17130 } elseif (!$this->isunicode) {
17131 switch ($dom[$dom[$key]['parent']]['text-transform']) {
17132 case 'capitalize': {
17133 $element = ucwords(strtolower($element));
17134 break;
17135 }
17136 case 'uppercase': {
17137 $element = strtoupper($element);
17138 break;
17139 }
17140 case 'lowercase': {
17141 $element = strtolower($element);
17142 break;
17143 }
17144 }
17145 }
17146 }
17147 $dom[$key]['value'] = stripslashes($this->unhtmlentities($element));
17148 }
17149 ++$elkey;
17150 ++$key;
17151 }
17152 return $dom;
17153 }
17154
17155 /**
17156 * Returns the string used to find spaces
17157 * @return string
17158 * @protected
17159 * @author Nicola Asuni
17160 * @since 4.8.024 (2010-01-15)
17161 */
17162 protected function getSpaceString() {
17163 $spacestr = chr(32);
17164 if ($this->isUnicodeFont()) {
17165 $spacestr = chr(0).chr(32);
17166 }
17167 return $spacestr;
17168 }
17169
17170 /**
17171 * Serialize an array of parameters to be used with TCPDF tag in HTML code.
17172 * @param $pararray (array) parameters array
17173 * @return sting containing serialized data
17174 * @since 4.9.006 (2010-04-02)
17175 * @public
17176 * @deprecated
17177 */
17178 public function serializeTCPDFtagParameters($pararray) {
17179 return TCPDF_STATIC::serializeTCPDFtagParameters($pararray);
17180 }
17181
17182 /**
17183 * Prints a cell (rectangular area) with optional borders, background color and html text string.
17184 * The upper-left corner of the cell corresponds to the current position. After the call, the current position moves to the right or to the next line.<br />
17185 * If automatic page breaking is enabled and the cell goes beyond the limit, a page break is done before outputting.
17186 * IMPORTANT: The HTML must be well formatted - try to clean-up it using an application like HTML-Tidy before submitting.
17187 * Supported tags are: a, b, blockquote, br, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, img, li, ol, p, pre, small, span, strong, sub, sup, table, tcpdf, td, th, thead, tr, tt, u, ul
17188 * NOTE: all the HTML attributes must be enclosed in double-quote.
17189 * @param $w (float) Cell width. If 0, the cell extends up to the right margin.
17190 * @param $h (float) Cell minimum height. The cell extends automatically if needed.
17191 * @param $x (float) upper-left corner X coordinate
17192 * @param $y (float) upper-left corner Y coordinate
17193 * @param $html (string) html text to print. Default value: empty string.
17194 * @param $border (mixed) Indicates if borders must be drawn around the cell. 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 - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0)))
17195 * @param $ln (int) Indicates where the current position should go after the call. Possible values are:<ul><li>0: to the right (or left for RTL language)</li><li>1: to the beginning of the next line</li><li>2: below</li></ul>
17196Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0.
17197 * @param $fill (boolean) Indicates if the cell background must be painted (true) or transparent (false).
17198 * @param $reseth (boolean) if true reset the last cell height (default true).
17199 * @param $align (string) Allows to center or align the text. Possible values are:<ul><li>L : left align</li><li>C : center</li><li>R : right align</li><li>'' : empty string : left for LTR or right for RTL</li></ul>
17200 * @param $autopadding (boolean) if true, uses internal padding and automatically adjust it to account for line width.
17201 * @see Multicell(), writeHTML()
17202 * @public
17203 */
17204 public function writeHTMLCell($w, $h, $x, $y, $html='', $border=0, $ln=0, $fill=false, $reseth=true, $align='', $autopadding=true) {
17205 return $this->MultiCell($w, $h, $html, $border, $align, $fill, $ln, $x, $y, $reseth, 0, true, $autopadding, 0, 'T', false);
17206 }
17207
17208 /**
17209 * Allows to preserve some HTML formatting (limited support).<br />
17210 * IMPORTANT: The HTML must be well formatted - try to clean-up it using an application like HTML-Tidy before submitting.
17211 * Supported tags are: a, b, blockquote, br, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, img, li, ol, p, pre, small, span, strong, sub, sup, table, tcpdf, td, th, thead, tr, tt, u, ul
17212 * NOTE: all the HTML attributes must be enclosed in double-quote.
17213 * @param $html (string) text to display
17214 * @param $ln (boolean) if true add a new line after text (default = true)
17215 * @param $fill (boolean) Indicates if the background must be painted (true) or transparent (false).
17216 * @param $reseth (boolean) if true reset the last cell height (default false).
17217 * @param $cell (boolean) if true add the current left (or right for RTL) padding to each Write (default false).
17218 * @param $align (string) Allows to center or align the text. Possible values are:<ul><li>L : left align</li><li>C : center</li><li>R : right align</li><li>'' : empty string : left for LTR or right for RTL</li></ul>
17219 * @public
17220 */
17221 public function writeHTML($html, $ln=true, $fill=false, $reseth=false, $cell=false, $align='') {
17222 $gvars = $this->getGraphicVars();
17223 // store current values
17224 $prev_cell_margin = $this->cell_margin;
17225 $prev_cell_padding = $this->cell_padding;
17226 $prevPage = $this->page;
17227 $prevlMargin = $this->lMargin;
17228 $prevrMargin = $this->rMargin;
17229 $curfontname = $this->FontFamily;
17230 $curfontstyle = $this->FontStyle;
17231 $curfontsize = $this->FontSizePt;
17232 $curfontascent = $this->getFontAscent($curfontname, $curfontstyle, $curfontsize);
17233 $curfontdescent = $this->getFontDescent($curfontname, $curfontstyle, $curfontsize);
17234 $curfontstretcing = $this->font_stretching;
17235 $curfonttracking = $this->font_spacing;
17236 $this->newline = true;
17237 $newline = true;
17238 $startlinepage = $this->page;
17239 $minstartliney = $this->y;
17240 $maxbottomliney = 0;
17241 $startlinex = $this->x;
17242 $startliney = $this->y;
17243 $yshift = 0;
17244 $loop = 0;
17245 $curpos = 0;
17246 $this_method_vars = array();
17247 $undo = false;
17248 $fontaligned = false;
17249 $reverse_dir = false; // true when the text direction is reversed
17250 $this->premode = false;
17251 if ($this->inxobj) {
17252 // we are inside an XObject template
17253 $pask = count($this->xobjects[$this->xobjid]['annotations']);
17254 } elseif (isset($this->PageAnnots[$this->page])) {
17255 $pask = count($this->PageAnnots[$this->page]);
17256 } else {
17257 $pask = 0;
17258 }
17259 if ($this->inxobj) {
17260 // we are inside an XObject template
17261 $startlinepos = strlen($this->xobjects[$this->xobjid]['outdata']);
17262 } elseif (!$this->InFooter) {
17263 if (isset($this->footerlen[$this->page])) {
17264 $this->footerpos[$this->page] = $this->pagelen[$this->page] - $this->footerlen[$this->page];
17265 } else {
17266 $this->footerpos[$this->page] = $this->pagelen[$this->page];
17267 }
17268 $startlinepos = $this->footerpos[$this->page];
17269 } else {
17270 // we are inside the footer
17271 $startlinepos = $this->pagelen[$this->page];
17272 }
17273 $lalign = $align;
17274 $plalign = $align;
17275 if ($this->rtl) {
17276 $w = $this->x - $this->lMargin;
17277 } else {
17278 $w = $this->w - $this->rMargin - $this->x;
17279 }
17280 $w -= ($this->cell_padding['L'] + $this->cell_padding['R']);
17281 if ($cell) {
17282 if ($this->rtl) {
17283 $this->x -= $this->cell_padding['R'];
17284 $this->lMargin += $this->cell_padding['R'];
17285 } else {
17286 $this->x += $this->cell_padding['L'];
17287 $this->rMargin += $this->cell_padding['L'];
17288 }
17289 }
17290 if ($this->customlistindent >= 0) {
17291 $this->listindent = $this->customlistindent;
17292 } else {
17293 $this->listindent = $this->GetStringWidth('000000');
17294 }
17295 $this->listindentlevel = 0;
17296 // save previous states
17297 $prev_cell_height_ratio = $this->cell_height_ratio;
17298 $prev_listnum = $this->listnum;
17299 $prev_listordered = $this->listordered;
17300 $prev_listcount = $this->listcount;
17301 $prev_lispacer = $this->lispacer;
17302 $this->listnum = 0;
17303 $this->listordered = array();
17304 $this->listcount = array();
17305 $this->lispacer = '';
17306 if ((TCPDF_STATIC::empty_string($this->lasth)) OR ($reseth)) {
17307 // reset row height
17308 $this->resetLastH();
17309 }
17310 $dom = $this->getHtmlDomArray($html);
17311 $maxel = count($dom);
17312 $key = 0;
17313 while ($key < $maxel) {
17314 if ($dom[$key]['tag'] AND $dom[$key]['opening'] AND $dom[$key]['hide']) {
17315 // store the node key
17316 $hidden_node_key = $key;
17317 if ($dom[$key]['self']) {
17318 // skip just this self-closing tag
17319 ++$key;
17320 } else {
17321 // skip this and all children tags
17322 while (($key < $maxel) AND (!$dom[$key]['tag'] OR $dom[$key]['opening'] OR ($dom[$key]['parent'] != $hidden_node_key))) {
17323 // skip hidden objects
17324 ++$key;
17325 }
17326 ++$key;
17327 }
17328 }
17329 if ($dom[$key]['tag'] AND isset($dom[$key]['attribute']['pagebreak'])) {
17330 // check for pagebreak
17331 if (($dom[$key]['attribute']['pagebreak'] == 'true') OR ($dom[$key]['attribute']['pagebreak'] == 'left') OR ($dom[$key]['attribute']['pagebreak'] == 'right')) {
17332 // add a page (or trig AcceptPageBreak() for multicolumn mode)
17333 $this->checkPageBreak($this->PageBreakTrigger + 1);
17334 $this->htmlvspace = ($this->PageBreakTrigger + 1);
17335 }
17336 if ((($dom[$key]['attribute']['pagebreak'] == 'left') AND (((!$this->rtl) AND (($this->page % 2) == 0)) OR (($this->rtl) AND (($this->page % 2) != 0))))
17337 OR (($dom[$key]['attribute']['pagebreak'] == 'right') AND (((!$this->rtl) AND (($this->page % 2) != 0)) OR (($this->rtl) AND (($this->page % 2) == 0))))) {
17338 // add a page (or trig AcceptPageBreak() for multicolumn mode)
17339 $this->checkPageBreak($this->PageBreakTrigger + 1);
17340 $this->htmlvspace = ($this->PageBreakTrigger + 1);
17341 }
17342 }
17343 if ($dom[$key]['tag'] AND $dom[$key]['opening'] AND isset($dom[$key]['attribute']['nobr']) AND ($dom[$key]['attribute']['nobr'] == 'true')) {
17344 if (isset($dom[($dom[$key]['parent'])]['attribute']['nobr']) AND ($dom[($dom[$key]['parent'])]['attribute']['nobr'] == 'true')) {
17345 $dom[$key]['attribute']['nobr'] = false;
17346 } else {
17347 // store current object
17348 $this->startTransaction();
17349 // save this method vars
17350 $this_method_vars['html'] = $html;
17351 $this_method_vars['ln'] = $ln;
17352 $this_method_vars['fill'] = $fill;
17353 $this_method_vars['reseth'] = $reseth;
17354 $this_method_vars['cell'] = $cell;
17355 $this_method_vars['align'] = $align;
17356 $this_method_vars['gvars'] = $gvars;
17357 $this_method_vars['prevPage'] = $prevPage;
17358 $this_method_vars['prev_cell_margin'] = $prev_cell_margin;
17359 $this_method_vars['prev_cell_padding'] = $prev_cell_padding;
17360 $this_method_vars['prevlMargin'] = $prevlMargin;
17361 $this_method_vars['prevrMargin'] = $prevrMargin;
17362 $this_method_vars['curfontname'] = $curfontname;
17363 $this_method_vars['curfontstyle'] = $curfontstyle;
17364 $this_method_vars['curfontsize'] = $curfontsize;
17365 $this_method_vars['curfontascent'] = $curfontascent;
17366 $this_method_vars['curfontdescent'] = $curfontdescent;
17367 $this_method_vars['curfontstretcing'] = $curfontstretcing;
17368 $this_method_vars['curfonttracking'] = $curfonttracking;
17369 $this_method_vars['minstartliney'] = $minstartliney;
17370 $this_method_vars['maxbottomliney'] = $maxbottomliney;
17371 $this_method_vars['yshift'] = $yshift;
17372 $this_method_vars['startlinepage'] = $startlinepage;
17373 $this_method_vars['startlinepos'] = $startlinepos;
17374 $this_method_vars['startlinex'] = $startlinex;
17375 $this_method_vars['startliney'] = $startliney;
17376 $this_method_vars['newline'] = $newline;
17377 $this_method_vars['loop'] = $loop;
17378 $this_method_vars['curpos'] = $curpos;
17379 $this_method_vars['pask'] = $pask;
17380 $this_method_vars['lalign'] = $lalign;
17381 $this_method_vars['plalign'] = $plalign;
17382 $this_method_vars['w'] = $w;
17383 $this_method_vars['prev_cell_height_ratio'] = $prev_cell_height_ratio;
17384 $this_method_vars['prev_listnum'] = $prev_listnum;
17385 $this_method_vars['prev_listordered'] = $prev_listordered;
17386 $this_method_vars['prev_listcount'] = $prev_listcount;
17387 $this_method_vars['prev_lispacer'] = $prev_lispacer;
17388 $this_method_vars['fontaligned'] = $fontaligned;
17389 $this_method_vars['key'] = $key;
17390 $this_method_vars['dom'] = $dom;
17391 }
17392 }
17393 // print THEAD block
17394 if (($dom[$key]['value'] == 'tr') AND isset($dom[$key]['thead']) AND $dom[$key]['thead']) {
17395 if (isset($dom[$key]['parent']) AND isset($dom[$dom[$key]['parent']]['thead']) AND !TCPDF_STATIC::empty_string($dom[$dom[$key]['parent']]['thead'])) {
17396 $this->inthead = true;
17397 // print table header (thead)
17398 $this->writeHTML($this->thead, false, false, false, false, '');
17399 // check if we are on a new page or on a new column
17400 if (($this->y < $this->start_transaction_y) OR ($this->checkPageBreak($this->lasth, '', false))) {
17401 // we are on a new page or on a new column and the total object height is less than the available vertical space.
17402 // restore previous object
17403 $this->rollbackTransaction(true);
17404 // restore previous values
17405 foreach ($this_method_vars as $vkey => $vval) {
17406 $$vkey = $vval;
17407 }
17408 // disable table header
17409 $tmp_thead = $this->thead;
17410 $this->thead = '';
17411 // add a page (or trig AcceptPageBreak() for multicolumn mode)
17412 $pre_y = $this->y;
17413 if ((!$this->checkPageBreak($this->PageBreakTrigger + 1)) AND ($this->y < $pre_y)) {
17414 // fix for multicolumn mode
17415 $startliney = $this->y;
17416 }
17417 $this->start_transaction_page = $this->page;
17418 $this->start_transaction_y = $this->y;
17419 // restore table header
17420 $this->thead = $tmp_thead;
17421 // fix table border properties
17422 if (isset($dom[$dom[$key]['parent']]['attribute']['cellspacing'])) {
17423 $tmp_cellspacing = $this->getHTMLUnitToUnits($dom[$dom[$key]['parent']]['attribute']['cellspacing'], 1, 'px');
17424 } elseif (isset($dom[$dom[$key]['parent']]['border-spacing'])) {
17425 $tmp_cellspacing = $dom[$dom[$key]['parent']]['border-spacing']['V'];
17426 } else {
17427 $tmp_cellspacing = 0;
17428 }
17429 $dom[$dom[$key]['parent']]['borderposition']['page'] = $this->page;
17430 $dom[$dom[$key]['parent']]['borderposition']['column'] = $this->current_column;
17431 $dom[$dom[$key]['parent']]['borderposition']['y'] = $this->y + $tmp_cellspacing;
17432 $xoffset = ($this->x - $dom[$dom[$key]['parent']]['borderposition']['x']);
17433 $dom[$dom[$key]['parent']]['borderposition']['x'] += $xoffset;
17434 $dom[$dom[$key]['parent']]['borderposition']['xmax'] += $xoffset;
17435 // print table header (thead)
17436 $this->writeHTML($this->thead, false, false, false, false, '');
17437 }
17438 }
17439 // move $key index forward to skip THEAD block
17440 while ( ($key < $maxel) AND (!(
17441 ($dom[$key]['tag'] AND $dom[$key]['opening'] AND ($dom[$key]['value'] == 'tr') AND (!isset($dom[$key]['thead']) OR !$dom[$key]['thead']))
17442 OR ($dom[$key]['tag'] AND (!$dom[$key]['opening']) AND ($dom[$key]['value'] == 'table'))) )) {
17443 ++$key;
17444 }
17445 }
17446 if ($dom[$key]['tag'] OR ($key == 0)) {
17447 if ((($dom[$key]['value'] == 'table') OR ($dom[$key]['value'] == 'tr')) AND (isset($dom[$key]['align']))) {
17448 $dom[$key]['align'] = ($this->rtl) ? 'R' : 'L';
17449 }
17450 // vertically align image in line
17451 if ((!$this->newline) AND ($dom[$key]['value'] == 'img') AND (isset($dom[$key]['height'])) AND ($dom[$key]['height'] > 0)) {
17452 // get image height
17453 $imgh = $this->getHTMLUnitToUnits($dom[$key]['height'], ($dom[$key]['fontsize'] / $this->k), 'px');
17454 $autolinebreak = false;
17455 if (!empty($dom[$key]['width'])) {
17456 $imgw = $this->getHTMLUnitToUnits($dom[$key]['width'], ($dom[$key]['fontsize'] / $this->k), 'px', false);
17457 if (($imgw <= ($this->w - $this->lMargin - $this->rMargin - $this->cell_padding['L'] - $this->cell_padding['R']))
17458 AND ((($this->rtl) AND (($this->x - $imgw) < ($this->lMargin + $this->cell_padding['L'])))
17459 OR ((!$this->rtl) AND (($this->x + $imgw) > ($this->w - $this->rMargin - $this->cell_padding['R']))))) {
17460 // add automatic line break
17461 $autolinebreak = true;
17462 $this->Ln('', $cell);
17463 if ((!$dom[($key-1)]['tag']) AND ($dom[($key-1)]['value'] == ' ')) {
17464 // go back to evaluate this line break
17465 --$key;
17466 }
17467 }
17468 }
17469 if (!$autolinebreak) {
17470 if ($this->inPageBody()) {
17471 $pre_y = $this->y;
17472 // check for page break
17473 if ((!$this->checkPageBreak($imgh)) AND ($this->y < $pre_y)) {
17474 // fix for multicolumn mode
17475 $startliney = $this->y;
17476 }
17477 }
17478 if ($this->page > $startlinepage) {
17479 // fix line splitted over two pages
17480 if (isset($this->footerlen[$startlinepage])) {
17481 $curpos = $this->pagelen[$startlinepage] - $this->footerlen[$startlinepage];
17482 }
17483 // line to be moved one page forward
17484 $pagebuff = $this->getPageBuffer($startlinepage);
17485 $linebeg = substr($pagebuff, $startlinepos, ($curpos - $startlinepos));
17486 $tstart = substr($pagebuff, 0, $startlinepos);
17487 $tend = substr($this->getPageBuffer($startlinepage), $curpos);
17488 // remove line from previous page
17489 $this->setPageBuffer($startlinepage, $tstart.''.$tend);
17490 $pagebuff = $this->getPageBuffer($this->page);
17491 $tstart = substr($pagebuff, 0, $this->cntmrk[$this->page]);
17492 $tend = substr($pagebuff, $this->cntmrk[$this->page]);
17493 // add line start to current page
17494 $yshift = ($minstartliney - $this->y);
17495 if ($fontaligned) {
17496 $yshift += ($curfontsize / $this->k);
17497 }
17498 $try = sprintf('1 0 0 1 0 %F cm', ($yshift * $this->k));
17499 $this->setPageBuffer($this->page, $tstart."\nq\n".$try."\n".$linebeg."\nQ\n".$tend);
17500 // shift the annotations and links
17501 if (isset($this->PageAnnots[$this->page])) {
17502 $next_pask = count($this->PageAnnots[$this->page]);
17503 } else {
17504 $next_pask = 0;
17505 }
17506 if (isset($this->PageAnnots[$startlinepage])) {
17507 foreach ($this->PageAnnots[$startlinepage] as $pak => $pac) {
17508 if ($pak >= $pask) {
17509 $this->PageAnnots[$this->page][] = $pac;
17510 unset($this->PageAnnots[$startlinepage][$pak]);
17511 $npak = count($this->PageAnnots[$this->page]) - 1;
17512 $this->PageAnnots[$this->page][$npak]['y'] -= $yshift;
17513 }
17514 }
17515 }
17516 $pask = $next_pask;
17517 $startlinepos = $this->cntmrk[$this->page];
17518 $startlinepage = $this->page;
17519 $startliney = $this->y;
17520 $this->newline = false;
17521 }
17522 $this->y += ($this->getCellHeight($curfontsize / $this->k) - ($curfontdescent * $this->cell_height_ratio) - $imgh);
17523 $minstartliney = min($this->y, $minstartliney);
17524 $maxbottomliney = ($startliney + $this->getCellHeight($curfontsize / $this->k));
17525 }
17526 } elseif (isset($dom[$key]['fontname']) OR isset($dom[$key]['fontstyle']) OR isset($dom[$key]['fontsize']) OR isset($dom[$key]['line-height'])) {
17527 // account for different font size
17528 $pfontname = $curfontname;
17529 $pfontstyle = $curfontstyle;
17530 $pfontsize = $curfontsize;
17531 $fontname = (isset($dom[$key]['fontname']) ? $dom[$key]['fontname'] : $curfontname);
17532 $fontstyle = (isset($dom[$key]['fontstyle']) ? $dom[$key]['fontstyle'] : $curfontstyle);
17533 $fontsize = (isset($dom[$key]['fontsize']) ? $dom[$key]['fontsize'] : $curfontsize);
17534 $fontascent = $this->getFontAscent($fontname, $fontstyle, $fontsize);
17535 $fontdescent = $this->getFontDescent($fontname, $fontstyle, $fontsize);
17536 if (($fontname != $curfontname) OR ($fontstyle != $curfontstyle) OR ($fontsize != $curfontsize)
17537 OR ($this->cell_height_ratio != $dom[$key]['line-height'])
17538 OR ($dom[$key]['tag'] AND $dom[$key]['opening'] AND ($dom[$key]['value'] == 'li')) ) {
17539 if (($key < ($maxel - 1)) AND (
17540 ($dom[$key]['tag'] AND $dom[$key]['opening'] AND ($dom[$key]['value'] == 'li'))
17541 OR ($this->cell_height_ratio != $dom[$key]['line-height'])
17542 OR (!$this->newline AND is_numeric($fontsize) AND is_numeric($curfontsize)
17543 AND ($fontsize >= 0) AND ($curfontsize >= 0)
17544 AND (($fontsize != $curfontsize) OR ($fontstyle != $curfontstyle) OR ($fontname != $curfontname)))
17545 )) {
17546 if ($this->page > $startlinepage) {
17547 // fix lines splitted over two pages
17548 if (isset($this->footerlen[$startlinepage])) {
17549 $curpos = $this->pagelen[$startlinepage] - $this->footerlen[$startlinepage];
17550 }
17551 // line to be moved one page forward
17552 $pagebuff = $this->getPageBuffer($startlinepage);
17553 $linebeg = substr($pagebuff, $startlinepos, ($curpos - $startlinepos));
17554 $tstart = substr($pagebuff, 0, $startlinepos);
17555 $tend = substr($this->getPageBuffer($startlinepage), $curpos);
17556 // remove line start from previous page
17557 $this->setPageBuffer($startlinepage, $tstart.''.$tend);
17558 $pagebuff = $this->getPageBuffer($this->page);
17559 $tstart = substr($pagebuff, 0, $this->cntmrk[$this->page]);
17560 $tend = substr($pagebuff, $this->cntmrk[$this->page]);
17561 // add line start to current page
17562 $yshift = ($minstartliney - $this->y);
17563 $try = sprintf('1 0 0 1 0 %F cm', ($yshift * $this->k));
17564 $this->setPageBuffer($this->page, $tstart."\nq\n".$try."\n".$linebeg."\nQ\n".$tend);
17565 // shift the annotations and links
17566 if (isset($this->PageAnnots[$this->page])) {
17567 $next_pask = count($this->PageAnnots[$this->page]);
17568 } else {
17569 $next_pask = 0;
17570 }
17571 if (isset($this->PageAnnots[$startlinepage])) {
17572 foreach ($this->PageAnnots[$startlinepage] as $pak => $pac) {
17573 if ($pak >= $pask) {
17574 $this->PageAnnots[$this->page][] = $pac;
17575 unset($this->PageAnnots[$startlinepage][$pak]);
17576 $npak = count($this->PageAnnots[$this->page]) - 1;
17577 $this->PageAnnots[$this->page][$npak]['y'] -= $yshift;
17578 }
17579 }
17580 }
17581 $pask = $next_pask;
17582 $startlinepos = $this->cntmrk[$this->page];
17583 $startlinepage = $this->page;
17584 $startliney = $this->y;
17585 }
17586 if (!isset($dom[$key]['line-height'])) {
17587 $dom[$key]['line-height'] = $this->cell_height_ratio;
17588 }
17589 if (!$dom[$key]['block']) {
17590 if (!(isset($dom[($key + 1)]) AND $dom[($key + 1)]['tag'] AND (!$dom[($key + 1)]['opening']) AND ($dom[($key + 1)]['value'] != 'li') AND $dom[$key]['tag'] AND (!$dom[$key]['opening']))) {
17591 $this->y += (((($curfontsize * $this->cell_height_ratio) - ($fontsize * $dom[$key]['line-height'])) / $this->k) + $curfontascent - $fontascent - $curfontdescent + $fontdescent) / 2;
17592 }
17593 if (($dom[$key]['value'] != 'sup') AND ($dom[$key]['value'] != 'sub')) {
17594 $current_line_align_data = array($key, $minstartliney, $maxbottomliney);
17595 if (isset($line_align_data) AND (($line_align_data[0] == ($key - 1)) OR (($line_align_data[0] == ($key - 2)) AND (isset($dom[($key - 1)])) AND (preg_match('/^([\s]+)$/', $dom[($key - 1)]['value']) > 0)))) {
17596 $minstartliney = min($this->y, $line_align_data[1]);
17597 $maxbottomliney = max(($this->y + $this->getCellHeight($fontsize / $this->k)), $line_align_data[2]);
17598 } else {
17599 $minstartliney = min($this->y, $minstartliney);
17600 $maxbottomliney = max(($this->y + $this->getCellHeight($fontsize / $this->k)), $maxbottomliney);
17601 }
17602 $line_align_data = $current_line_align_data;
17603 }
17604 }
17605 $this->cell_height_ratio = $dom[$key]['line-height'];
17606 $fontaligned = true;
17607 }
17608 $this->SetFont($fontname, $fontstyle, $fontsize);
17609 // reset row height
17610 $this->resetLastH();
17611 $curfontname = $fontname;
17612 $curfontstyle = $fontstyle;
17613 $curfontsize = $fontsize;
17614 $curfontascent = $fontascent;
17615 $curfontdescent = $fontdescent;
17616 }
17617 }
17618 // set text rendering mode
17619 $textstroke = isset($dom[$key]['stroke']) ? $dom[$key]['stroke'] : $this->textstrokewidth;
17620 $textfill = isset($dom[$key]['fill']) ? $dom[$key]['fill'] : (($this->textrendermode % 2) == 0);
17621 $textclip = isset($dom[$key]['clip']) ? $dom[$key]['clip'] : ($this->textrendermode > 3);
17622 $this->setTextRenderingMode($textstroke, $textfill, $textclip);
17623 if (isset($dom[$key]['font-stretch']) AND ($dom[$key]['font-stretch'] !== false)) {
17624 $this->setFontStretching($dom[$key]['font-stretch']);
17625 }
17626 if (isset($dom[$key]['letter-spacing']) AND ($dom[$key]['letter-spacing'] !== false)) {
17627 $this->setFontSpacing($dom[$key]['letter-spacing']);
17628 }
17629 if (($plalign == 'J') AND $dom[$key]['block']) {
17630 $plalign = '';
17631 }
17632 // get current position on page buffer
17633 $curpos = $this->pagelen[$startlinepage];
17634 if (isset($dom[$key]['bgcolor']) AND ($dom[$key]['bgcolor'] !== false)) {
17635 $this->SetFillColorArray($dom[$key]['bgcolor']);
17636 $wfill = true;
17637 } else {
17638 $wfill = $fill | false;
17639 }
17640 if (isset($dom[$key]['fgcolor']) AND ($dom[$key]['fgcolor'] !== false)) {
17641 $this->SetTextColorArray($dom[$key]['fgcolor']);
17642 }
17643 if (isset($dom[$key]['strokecolor']) AND ($dom[$key]['strokecolor'] !== false)) {
17644 $this->SetDrawColorArray($dom[$key]['strokecolor']);
17645 }
17646 if (isset($dom[$key]['align'])) {
17647 $lalign = $dom[$key]['align'];
17648 }
17649 if (TCPDF_STATIC::empty_string($lalign)) {
17650 $lalign = $align;
17651 }
17652 }
17653 // align lines
17654 if ($this->newline AND (strlen($dom[$key]['value']) > 0) AND ($dom[$key]['value'] != 'td') AND ($dom[$key]['value'] != 'th')) {
17655 $newline = true;
17656 $fontaligned = false;
17657 // we are at the beginning of a new line
17658 if (isset($startlinex)) {
17659 $yshift = ($minstartliney - $startliney);
17660 if (($yshift > 0) OR ($this->page > $startlinepage)) {
17661 $yshift = 0;
17662 }
17663 $t_x = 0;
17664 // the last line must be shifted to be aligned as requested
17665 $linew = abs($this->endlinex - $startlinex);
17666 if ($this->inxobj) {
17667 // we are inside an XObject template
17668 $pstart = substr($this->xobjects[$this->xobjid]['outdata'], 0, $startlinepos);
17669 if (isset($opentagpos)) {
17670 $midpos = $opentagpos;
17671 } else {
17672 $midpos = 0;
17673 }
17674 if ($midpos > 0) {
17675 $pmid = substr($this->xobjects[$this->xobjid]['outdata'], $startlinepos, ($midpos - $startlinepos));
17676 $pend = substr($this->xobjects[$this->xobjid]['outdata'], $midpos);
17677 } else {
17678 $pmid = substr($this->xobjects[$this->xobjid]['outdata'], $startlinepos);
17679 $pend = '';
17680 }
17681 } else {
17682 $pstart = substr($this->getPageBuffer($startlinepage), 0, $startlinepos);
17683 if (isset($opentagpos) AND isset($this->footerlen[$startlinepage]) AND (!$this->InFooter)) {
17684 $this->footerpos[$startlinepage] = $this->pagelen[$startlinepage] - $this->footerlen[$startlinepage];
17685 $midpos = min($opentagpos, $this->footerpos[$startlinepage]);
17686 } elseif (isset($opentagpos)) {
17687 $midpos = $opentagpos;
17688 } elseif (isset($this->footerlen[$startlinepage]) AND (!$this->InFooter)) {
17689 $this->footerpos[$startlinepage] = $this->pagelen[$startlinepage] - $this->footerlen[$startlinepage];
17690 $midpos = $this->footerpos[$startlinepage];
17691 } else {
17692 $midpos = 0;
17693 }
17694 if ($midpos > 0) {
17695 $pmid = substr($this->getPageBuffer($startlinepage), $startlinepos, ($midpos - $startlinepos));
17696 $pend = substr($this->getPageBuffer($startlinepage), $midpos);
17697 } else {
17698 $pmid = substr($this->getPageBuffer($startlinepage), $startlinepos);
17699 $pend = '';
17700 }
17701 }
17702 if ((isset($plalign) AND ((($plalign == 'C') OR ($plalign == 'J') OR (($plalign == 'R') AND (!$this->rtl)) OR (($plalign == 'L') AND ($this->rtl)))))) {
17703 // calculate shifting amount
17704 $tw = $w;
17705 if (($plalign == 'J') AND $this->isRTLTextDir() AND ($this->num_columns > 1)) {
17706 $tw += $this->cell_padding['R'];
17707 }
17708 if ($this->lMargin != $prevlMargin) {
17709 $tw += ($prevlMargin - $this->lMargin);
17710 }
17711 if ($this->rMargin != $prevrMargin) {
17712 $tw += ($prevrMargin - $this->rMargin);
17713 }
17714 $one_space_width = $this->GetStringWidth(chr(32));
17715 $no = 0; // number of spaces on a line contained on a single block
17716 if ($this->isRTLTextDir()) { // RTL
17717 // remove left space if exist
17718 $pos1 = TCPDF_STATIC::revstrpos($pmid, '[(');
17719 if ($pos1 > 0) {
17720 $pos1 = intval($pos1);
17721 if ($this->isUnicodeFont()) {
17722 $pos2 = intval(TCPDF_STATIC::revstrpos($pmid, '[('.chr(0).chr(32)));
17723 $spacelen = 2;
17724 } else {
17725 $pos2 = intval(TCPDF_STATIC::revstrpos($pmid, '[('.chr(32)));
17726 $spacelen = 1;
17727 }
17728 if ($pos1 == $pos2) {
17729 $pmid = substr($pmid, 0, ($pos1 + 2)).substr($pmid, ($pos1 + 2 + $spacelen));
17730 if (substr($pmid, $pos1, 4) == '[()]') {
17731 $linew -= $one_space_width;
17732 } elseif ($pos1 == strpos($pmid, '[(')) {
17733 $no = 1;
17734 }
17735 }
17736 }
17737 } else { // LTR
17738 // remove right space if exist
17739 $pos1 = TCPDF_STATIC::revstrpos($pmid, ')]');
17740 if ($pos1 > 0) {
17741 $pos1 = intval($pos1);
17742 if ($this->isUnicodeFont()) {
17743 $pos2 = intval(TCPDF_STATIC::revstrpos($pmid, chr(0).chr(32).')]')) + 2;
17744 $spacelen = 2;
17745 } else {
17746 $pos2 = intval(TCPDF_STATIC::revstrpos($pmid, chr(32).')]')) + 1;
17747 $spacelen = 1;
17748 }
17749 if ($pos1 == $pos2) {
17750 $pmid = substr($pmid, 0, ($pos1 - $spacelen)).substr($pmid, $pos1);
17751 $linew -= $one_space_width;
17752 }
17753 }
17754 }
17755 $mdiff = ($tw - $linew);
17756 if ($plalign == 'C') {
17757 if ($this->rtl) {
17758 $t_x = -($mdiff / 2);
17759 } else {
17760 $t_x = ($mdiff / 2);
17761 }
17762 } elseif ($plalign == 'R') {
17763 // right alignment on LTR document
17764 $t_x = $mdiff;
17765 } elseif ($plalign == 'L') {
17766 // left alignment on RTL document
17767 $t_x = -$mdiff;
17768 } elseif (($plalign == 'J') AND ($plalign == $lalign)) {
17769 // Justification
17770 if ($this->isRTLTextDir()) {
17771 // align text on the left
17772 $t_x = -$mdiff;
17773 }
17774 $ns = 0; // number of spaces
17775 $pmidtemp = $pmid;
17776 // escape special characters
17777 $pmidtemp = preg_replace('/[\\\][\(]/x', '\\#!#OP#!#', $pmidtemp);
17778 $pmidtemp = preg_replace('/[\\\][\)]/x', '\\#!#CP#!#', $pmidtemp);
17779 // search spaces
17780 if (preg_match_all('/\[\(([^\)]*)\)\]/x', $pmidtemp, $lnstring, PREG_PATTERN_ORDER)) {
17781 $spacestr = $this->getSpaceString();
17782 $maxkk = count($lnstring[1]) - 1;
17783 for ($kk=0; $kk <= $maxkk; ++$kk) {
17784 // restore special characters
17785 $lnstring[1][$kk] = str_replace('#!#OP#!#', '(', $lnstring[1][$kk]);
17786 $lnstring[1][$kk] = str_replace('#!#CP#!#', ')', $lnstring[1][$kk]);
17787 // store number of spaces on the strings
17788 $lnstring[2][$kk] = substr_count($lnstring[1][$kk], $spacestr);
17789 // count total spaces on line
17790 $ns += $lnstring[2][$kk];
17791 $lnstring[3][$kk] = $ns;
17792 }
17793 if ($ns == 0) {
17794 $ns = 1;
17795 }
17796 // calculate additional space to add to each existing space
17797 $spacewidth = ($mdiff / ($ns - $no)) * $this->k;
17798 if ($this->FontSize <= 0) {
17799 $this->FontSize = 1;
17800 }
17801 $spacewidthu = -1000 * ($mdiff + (($ns + $no) * $one_space_width)) / $ns / $this->FontSize;
17802 if ($this->font_spacing != 0) {
17803 // fixed spacing mode
17804 $osw = -1000 * $this->font_spacing / $this->FontSize;
17805 $spacewidthu += $osw;
17806 }
17807 $nsmax = $ns;
17808 $ns = 0;
17809 reset($lnstring);
17810 $offset = 0;
17811 $strcount = 0;
17812 $prev_epsposbeg = 0;
17813 $textpos = 0;
17814 if ($this->isRTLTextDir()) {
17815 $textpos = $this->wPt;
17816 }
17817 while (preg_match('/([0-9\.\+\-]*)[\s](Td|cm|m|l|c|re)[\s]/x', $pmid, $strpiece, PREG_OFFSET_CAPTURE, $offset) == 1) {
17818 // check if we are inside a string section '[( ... )]'
17819 $stroffset = strpos($pmid, '[(', $offset);
17820 if (($stroffset !== false) AND ($stroffset <= $strpiece[2][1])) {
17821 // set offset to the end of string section
17822 $offset = strpos($pmid, ')]', $stroffset);
17823 while (($offset !== false) AND ($pmid[($offset - 1)] == '\\')) {
17824 $offset = strpos($pmid, ')]', ($offset + 1));
17825 }
17826 if ($offset === false) {
17827 $this->Error('HTML Justification: malformed PDF code.');
17828 }
17829 continue;
17830 }
17831 if ($this->isRTLTextDir()) {
17832 $spacew = ($spacewidth * ($nsmax - $ns));
17833 } else {
17834 $spacew = ($spacewidth * $ns);
17835 }
17836 $offset = $strpiece[2][1] + strlen($strpiece[2][0]);
17837 $epsposend = strpos($pmid, $this->epsmarker.'Q', $offset);
17838 if ($epsposend !== null) {
17839 $epsposend += strlen($this->epsmarker.'Q');
17840 $epsposbeg = strpos($pmid, 'q'.$this->epsmarker, $offset);
17841 if ($epsposbeg === null) {
17842 $epsposbeg = strpos($pmid, 'q'.$this->epsmarker, ($prev_epsposbeg - 6));
17843 $prev_epsposbeg = $epsposbeg;
17844 }
17845 if (($epsposbeg > 0) AND ($epsposend > 0) AND ($offset > $epsposbeg) AND ($offset < $epsposend)) {
17846 // shift EPS images
17847 $trx = sprintf('1 0 0 1 %F 0 cm', $spacew);
17848 $pmid_b = substr($pmid, 0, $epsposbeg);
17849 $pmid_m = substr($pmid, $epsposbeg, ($epsposend - $epsposbeg));
17850 $pmid_e = substr($pmid, $epsposend);
17851 $pmid = $pmid_b."\nq\n".$trx."\n".$pmid_m."\nQ\n".$pmid_e;
17852 $offset = $epsposend;
17853 continue;
17854 }
17855 }
17856 $currentxpos = 0;
17857 // shift blocks of code
17858 switch ($strpiece[2][0]) {
17859 case 'Td':
17860 case 'cm':
17861 case 'm':
17862 case 'l': {
17863 // get current X position
17864 preg_match('/([0-9\.\+\-]*)[\s]('.$strpiece[1][0].')[\s]('.$strpiece[2][0].')([\s]*)/x', $pmid, $xmatches);
17865 if (!isset($xmatches[1])) {
17866 break;
17867 }
17868 $currentxpos = $xmatches[1];
17869 $textpos = $currentxpos;
17870 if (($strcount <= $maxkk) AND ($strpiece[2][0] == 'Td')) {
17871 $ns = $lnstring[3][$strcount];
17872 if ($this->isRTLTextDir()) {
17873 $spacew = ($spacewidth * ($nsmax - $ns));
17874 }
17875 ++$strcount;
17876 }
17877 // justify block
17878 if (preg_match('/([0-9\.\+\-]*)[\s]('.$strpiece[1][0].')[\s]('.$strpiece[2][0].')([\s]*)/x', $pmid, $pmatch) == 1) {
17879 $newpmid = sprintf('%F',(floatval($pmatch[1]) + $spacew)).' '.$pmatch[2].' x*#!#*x'.$pmatch[3].$pmatch[4];
17880 $pmid = str_replace($pmatch[0], $newpmid, $pmid);
17881 unset($pmatch, $newpmid);
17882 }
17883 break;
17884 }
17885 case 're': {
17886 // justify block
17887 if (!TCPDF_STATIC::empty_string($this->lispacer)) {
17888 $this->lispacer = '';
17889 continue;
17890 }
17891 preg_match('/([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]('.$strpiece[1][0].')[\s](re)([\s]*)/x', $pmid, $xmatches);
17892 if (!isset($xmatches[1])) {
17893 break;
17894 }
17895 $currentxpos = $xmatches[1];
17896 $x_diff = 0;
17897 $w_diff = 0;
17898 if ($this->isRTLTextDir()) { // RTL
17899 if ($currentxpos < $textpos) {
17900 $x_diff = ($spacewidth * ($nsmax - $lnstring[3][$strcount]));
17901 $w_diff = ($spacewidth * $lnstring[2][$strcount]);
17902 } else {
17903 if ($strcount > 0) {
17904 $x_diff = ($spacewidth * ($nsmax - $lnstring[3][($strcount - 1)]));
17905 $w_diff = ($spacewidth * $lnstring[2][($strcount - 1)]);
17906 }
17907 }
17908 } else { // LTR
17909 if ($currentxpos > $textpos) {
17910 if ($strcount > 0) {
17911 $x_diff = ($spacewidth * $lnstring[3][($strcount - 1)]);
17912 }
17913 $w_diff = ($spacewidth * $lnstring[2][$strcount]);
17914 } else {
17915 if ($strcount > 1) {
17916 $x_diff = ($spacewidth * $lnstring[3][($strcount - 2)]);
17917 }
17918 if ($strcount > 0) {
17919 $w_diff = ($spacewidth * $lnstring[2][($strcount - 1)]);
17920 }
17921 }
17922 }
17923 if (preg_match('/('.$xmatches[1].')[\s]('.$xmatches[2].')[\s]('.$xmatches[3].')[\s]('.$strpiece[1][0].')[\s](re)([\s]*)/x', $pmid, $pmatch) == 1) {
17924 $newx = sprintf('%F',(floatval($pmatch[1]) + $x_diff));
17925 $neww = sprintf('%F',(floatval($pmatch[3]) + $w_diff));
17926 $newpmid = $newx.' '.$pmatch[2].' '.$neww.' '.$pmatch[4].' x*#!#*x'.$pmatch[5].$pmatch[6];
17927 $pmid = str_replace($pmatch[0], $newpmid, $pmid);
17928 unset($pmatch, $newpmid, $newx, $neww);
17929 }
17930 break;
17931 }
17932 case 'c': {
17933 // get current X position
17934 preg_match('/([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]([0-9\.\+\-]*)[\s]('.$strpiece[1][0].')[\s](c)([\s]*)/x', $pmid, $xmatches);
17935 if (!isset($xmatches[1])) {
17936 break;
17937 }
17938 $currentxpos = $xmatches[1];
17939 // justify block
17940 if (preg_match('/('.$xmatches[1].')[\s]('.$xmatches[2].')[\s]('.$xmatches[3].')[\s]('.$xmatches[4].')[\s]('.$xmatches[5].')[\s]('.$strpiece[1][0].')[\s](c)([\s]*)/x', $pmid, $pmatch) == 1) {
17941 $newx1 = sprintf('%F',(floatval($pmatch[1]) + $spacew));
17942 $newx2 = sprintf('%F',(floatval($pmatch[3]) + $spacew));
17943 $newx3 = sprintf('%F',(floatval($pmatch[5]) + $spacew));
17944 $newpmid = $newx1.' '.$pmatch[2].' '.$newx2.' '.$pmatch[4].' '.$newx3.' '.$pmatch[6].' x*#!#*x'.$pmatch[7].$pmatch[8];
17945 $pmid = str_replace($pmatch[0], $newpmid, $pmid);
17946 unset($pmatch, $newpmid, $newx1, $newx2, $newx3);
17947 }
17948 break;
17949 }
17950 }
17951 // shift the annotations and links
17952 $cxpos = ($currentxpos / $this->k);
17953 $lmpos = ($this->lMargin + $this->cell_padding['L'] + $this->feps);
17954 if ($this->inxobj) {
17955 // we are inside an XObject template
17956 foreach ($this->xobjects[$this->xobjid]['annotations'] as $pak => $pac) {
17957 if (($pac['y'] >= $minstartliney) AND (($pac['x'] * $this->k) >= ($currentxpos - $this->feps)) AND (($pac['x'] * $this->k) <= ($currentxpos + $this->feps))) {
17958 if ($cxpos > $lmpos) {
17959 $this->xobjects[$this->xobjid]['annotations'][$pak]['x'] += ($spacew / $this->k);
17960 $this->xobjects[$this->xobjid]['annotations'][$pak]['w'] += (($spacewidth * $pac['numspaces']) / $this->k);
17961 } else {
17962 $this->xobjects[$this->xobjid]['annotations'][$pak]['w'] += (($spacewidth * $pac['numspaces']) / $this->k);
17963 }
17964 break;
17965 }
17966 }
17967 } elseif (isset($this->PageAnnots[$this->page])) {
17968 foreach ($this->PageAnnots[$this->page] as $pak => $pac) {
17969 if (($pac['y'] >= $minstartliney) AND (($pac['x'] * $this->k) >= ($currentxpos - $this->feps)) AND (($pac['x'] * $this->k) <= ($currentxpos + $this->feps))) {
17970 if ($cxpos > $lmpos) {
17971 $this->PageAnnots[$this->page][$pak]['x'] += ($spacew / $this->k);
17972 $this->PageAnnots[$this->page][$pak]['w'] += (($spacewidth * $pac['numspaces']) / $this->k);
17973 } else {
17974 $this->PageAnnots[$this->page][$pak]['w'] += (($spacewidth * $pac['numspaces']) / $this->k);
17975 }
17976 break;
17977 }
17978 }
17979 }
17980 } // end of while
17981 // remove markers
17982 $pmid = str_replace('x*#!#*x', '', $pmid);
17983 if ($this->isUnicodeFont()) {
17984 // multibyte characters
17985 $spacew = $spacewidthu;
17986 if ($this->font_stretching != 100) {
17987 // word spacing is affected by stretching
17988 $spacew /= ($this->font_stretching / 100);
17989 }
17990 // escape special characters
17991 $pos = 0;
17992 $pmid = preg_replace('/[\\\][\(]/x', '\\#!#OP#!#', $pmid);
17993 $pmid = preg_replace('/[\\\][\)]/x', '\\#!#CP#!#', $pmid);
17994 if (preg_match_all('/\[\(([^\)]*)\)\]/x', $pmid, $pamatch) > 0) {
17995 foreach($pamatch[0] as $pk => $pmatch) {
17996 $replace = $pamatch[1][$pk];
17997 $replace = str_replace('#!#OP#!#', '(', $replace);
17998 $replace = str_replace('#!#CP#!#', ')', $replace);
17999 $newpmid = '[('.str_replace(chr(0).chr(32), ') '.sprintf('%F', $spacew).' (', $replace).')]';
18000 $pos = strpos($pmid, $pmatch, $pos);
18001 if ($pos !== FALSE) {
18002 $pmid = substr_replace($pmid, $newpmid, $pos, strlen($pmatch));
18003 }
18004 ++$pos;
18005 }
18006 unset($pamatch);
18007 }
18008 if ($this->inxobj) {
18009 // we are inside an XObject template
18010 $this->xobjects[$this->xobjid]['outdata'] = $pstart."\n".$pmid."\n".$pend;
18011 } else {
18012 $this->setPageBuffer($startlinepage, $pstart."\n".$pmid."\n".$pend);
18013 }
18014 $endlinepos = strlen($pstart."\n".$pmid."\n");
18015 } else {
18016 // non-unicode (single-byte characters)
18017 if ($this->font_stretching != 100) {
18018 // word spacing (Tw) is affected by stretching
18019 $spacewidth /= ($this->font_stretching / 100);
18020 }
18021 $rs = sprintf('%F Tw', $spacewidth);
18022 $pmid = preg_replace("/\[\(/x", $rs.' [(', $pmid);
18023 if ($this->inxobj) {
18024 // we are inside an XObject template
18025 $this->xobjects[$this->xobjid]['outdata'] = $pstart."\n".$pmid."\nBT 0 Tw ET\n".$pend;
18026 } else {
18027 $this->setPageBuffer($startlinepage, $pstart."\n".$pmid."\nBT 0 Tw ET\n".$pend);
18028 }
18029 $endlinepos = strlen($pstart."\n".$pmid."\nBT 0 Tw ET\n");
18030 }
18031 }
18032 } // end of J
18033 } // end if $startlinex
18034 if (($t_x != 0) OR ($yshift < 0)) {
18035 // shift the line
18036 $trx = sprintf('1 0 0 1 %F %F cm', ($t_x * $this->k), ($yshift * $this->k));
18037 $pstart .= "\nq\n".$trx."\n".$pmid."\nQ\n";
18038 $endlinepos = strlen($pstart);
18039 if ($this->inxobj) {
18040 // we are inside an XObject template
18041 $this->xobjects[$this->xobjid]['outdata'] = $pstart.$pend;
18042 foreach ($this->xobjects[$this->xobjid]['annotations'] as $pak => $pac) {
18043 if ($pak >= $pask) {
18044 $this->xobjects[$this->xobjid]['annotations'][$pak]['x'] += $t_x;
18045 $this->xobjects[$this->xobjid]['annotations'][$pak]['y'] -= $yshift;
18046 }
18047 }
18048 } else {
18049 $this->setPageBuffer($startlinepage, $pstart.$pend);
18050 // shift the annotations and links
18051 if (isset($this->PageAnnots[$this->page])) {
18052 foreach ($this->PageAnnots[$this->page] as $pak => $pac) {
18053 if ($pak >= $pask) {
18054 $this->PageAnnots[$this->page][$pak]['x'] += $t_x;
18055 $this->PageAnnots[$this->page][$pak]['y'] -= $yshift;
18056 }
18057 }
18058 }
18059 }
18060 $this->y -= $yshift;
18061 }
18062 }
18063 $pbrk = $this->checkPageBreak($this->lasth);
18064 $this->newline = false;
18065 $startlinex = $this->x;
18066 $startliney = $this->y;
18067 if ($dom[$dom[$key]['parent']]['value'] == 'sup') {
18068 $startliney -= ((0.3 * $this->FontSizePt) / $this->k);
18069 } elseif ($dom[$dom[$key]['parent']]['value'] == 'sub') {
18070 $startliney -= (($this->FontSizePt / 0.7) / $this->k);
18071 } else {
18072 $minstartliney = $startliney;
18073 $maxbottomliney = ($this->y + $this->getCellHeight($fontsize / $this->k));
18074 }
18075 $startlinepage = $this->page;
18076 if (isset($endlinepos) AND (!$pbrk)) {
18077 $startlinepos = $endlinepos;
18078 } else {
18079 if ($this->inxobj) {
18080 // we are inside an XObject template
18081 $startlinepos = strlen($this->xobjects[$this->xobjid]['outdata']);
18082 } elseif (!$this->InFooter) {
18083 if (isset($this->footerlen[$this->page])) {
18084 $this->footerpos[$this->page] = $this->pagelen[$this->page] - $this->footerlen[$this->page];
18085 } else {
18086 $this->footerpos[$this->page] = $this->pagelen[$this->page];
18087 }
18088 $startlinepos = $this->footerpos[$this->page];
18089 } else {
18090 $startlinepos = $this->pagelen[$this->page];
18091 }
18092 }
18093 unset($endlinepos);
18094 $plalign = $lalign;
18095 if (isset($this->PageAnnots[$this->page])) {
18096 $pask = count($this->PageAnnots[$this->page]);
18097 } else {
18098 $pask = 0;
18099 }
18100 if (!($dom[$key]['tag'] AND !$dom[$key]['opening'] AND ($dom[$key]['value'] == 'table')
18101 AND (isset($this->emptypagemrk[$this->page]))
18102 AND ($this->emptypagemrk[$this->page] == $this->pagelen[$this->page]))) {
18103 $this->SetFont($fontname, $fontstyle, $fontsize);
18104 if ($wfill) {
18105 $this->SetFillColorArray($this->bgcolor);
18106 }
18107 }
18108 } // end newline
18109 if (isset($opentagpos)) {
18110 unset($opentagpos);
18111 }
18112 if ($dom[$key]['tag']) {
18113 if ($dom[$key]['opening']) {
18114 // get text indentation (if any)
18115 if (isset($dom[$key]['text-indent']) AND $dom[$key]['block']) {
18116 $this->textindent = $dom[$key]['text-indent'];
18117 $this->newline = true;
18118 }
18119 // table
18120 if (($dom[$key]['value'] == 'table') AND isset($dom[$key]['cols']) AND ($dom[$key]['cols'] > 0)) {
18121 // available page width
18122 if ($this->rtl) {
18123 $wtmp = $this->x - $this->lMargin;
18124 } else {
18125 $wtmp = $this->w - $this->rMargin - $this->x;
18126 }
18127 // get cell spacing
18128 if (isset($dom[$key]['attribute']['cellspacing'])) {
18129 $clsp = $this->getHTMLUnitToUnits($dom[$key]['attribute']['cellspacing'], 1, 'px');
18130 $cellspacing = array('H' => $clsp, 'V' => $clsp);
18131 } elseif (isset($dom[$key]['border-spacing'])) {
18132 $cellspacing = $dom[$key]['border-spacing'];
18133 } else {
18134 $cellspacing = array('H' => 0, 'V' => 0);
18135 }
18136 // table width
18137 if (isset($dom[$key]['width'])) {
18138 $table_width = $this->getHTMLUnitToUnits($dom[$key]['width'], $wtmp, 'px');
18139 } else {
18140 $table_width = $wtmp;
18141 }
18142 $table_width -= (2 * $cellspacing['H']);
18143 if (!$this->inthead) {
18144 $this->y += $cellspacing['V'];
18145 }
18146 if ($this->rtl) {
18147 $cellspacingx = -$cellspacing['H'];
18148 } else {
18149 $cellspacingx = $cellspacing['H'];
18150 }
18151 // total table width without cellspaces
18152 $table_columns_width = ($table_width - ($cellspacing['H'] * ($dom[$key]['cols'] - 1)));
18153 // minimum column width
18154 $table_min_column_width = ($table_columns_width / $dom[$key]['cols']);
18155 // array of custom column widths
18156 $table_colwidths = array_fill(0, $dom[$key]['cols'], $table_min_column_width);
18157 }
18158 // table row
18159 if ($dom[$key]['value'] == 'tr') {
18160 // reset column counter
18161 $colid = 0;
18162 }
18163 // table cell
18164 if (($dom[$key]['value'] == 'td') OR ($dom[$key]['value'] == 'th')) {
18165 $trid = $dom[$key]['parent'];
18166 $table_el = $dom[$trid]['parent'];
18167 if (!isset($dom[$table_el]['cols'])) {
18168 $dom[$table_el]['cols'] = $dom[$trid]['cols'];
18169 }
18170 // store border info
18171 $tdborder = 0;
18172 if (isset($dom[$key]['border']) AND !empty($dom[$key]['border'])) {
18173 $tdborder = $dom[$key]['border'];
18174 }
18175 $colspan = intval($dom[$key]['attribute']['colspan']);
18176 if ($colspan <= 0) {
18177 $colspan = 1;
18178 }
18179 $old_cell_padding = $this->cell_padding;
18180 if (isset($dom[($dom[$trid]['parent'])]['attribute']['cellpadding'])) {
18181 $crclpd = $this->getHTMLUnitToUnits($dom[($dom[$trid]['parent'])]['attribute']['cellpadding'], 1, 'px');
18182 $current_cell_padding = array('L' => $crclpd, 'T' => $crclpd, 'R' => $crclpd, 'B' => $crclpd);
18183 } elseif (isset($dom[($dom[$trid]['parent'])]['padding'])) {
18184 $current_cell_padding = $dom[($dom[$trid]['parent'])]['padding'];
18185 } else {
18186 $current_cell_padding = array('L' => 0, 'T' => 0, 'R' => 0, 'B' => 0);
18187 }
18188 $this->cell_padding = $current_cell_padding;
18189 if (isset($dom[$key]['height'])) {
18190 // minimum cell height
18191 $cellh = $this->getHTMLUnitToUnits($dom[$key]['height'], 0, 'px');
18192 } else {
18193 $cellh = 0;
18194 }
18195 if (isset($dom[$key]['content'])) {
18196 $cell_content = stripslashes($dom[$key]['content']);
18197 } else {
18198 $cell_content = '&nbsp;';
18199 }
18200 $tagtype = $dom[$key]['value'];
18201 $parentid = $key;
18202 while (($key < $maxel) AND (!(($dom[$key]['tag']) AND (!$dom[$key]['opening']) AND ($dom[$key]['value'] == $tagtype) AND ($dom[$key]['parent'] == $parentid)))) {
18203 // move $key index forward
18204 ++$key;
18205 }
18206 if (!isset($dom[$trid]['startpage'])) {
18207 $dom[$trid]['startpage'] = $this->page;
18208 } else {
18209 $this->setPage($dom[$trid]['startpage']);
18210 }
18211 if (!isset($dom[$trid]['startcolumn'])) {
18212 $dom[$trid]['startcolumn'] = $this->current_column;
18213 } elseif ($this->current_column != $dom[$trid]['startcolumn']) {
18214 $tmpx = $this->x;
18215 $this->selectColumn($dom[$trid]['startcolumn']);
18216 $this->x = $tmpx;
18217 }
18218 if (!isset($dom[$trid]['starty'])) {
18219 $dom[$trid]['starty'] = $this->y;
18220 } else {
18221 $this->y = $dom[$trid]['starty'];
18222 }
18223 if (!isset($dom[$trid]['startx'])) {
18224 $dom[$trid]['startx'] = $this->x;
18225 $this->x += $cellspacingx;
18226 } else {
18227 $this->x += ($cellspacingx / 2);
18228 }
18229 if (isset($dom[$parentid]['attribute']['rowspan'])) {
18230 $rowspan = intval($dom[$parentid]['attribute']['rowspan']);
18231 } else {
18232 $rowspan = 1;
18233 }
18234 // skip row-spanned cells started on the previous rows
18235 if (isset($dom[$table_el]['rowspans'])) {
18236 $rsk = 0;
18237 $rskmax = count($dom[$table_el]['rowspans']);
18238 while ($rsk < $rskmax) {
18239 $trwsp = $dom[$table_el]['rowspans'][$rsk];
18240 $rsstartx = $trwsp['startx'];
18241 $rsendx = $trwsp['endx'];
18242 // account for margin changes
18243 if ($trwsp['startpage'] < $this->page) {
18244 if (($this->rtl) AND ($this->pagedim[$this->page]['orm'] != $this->pagedim[$trwsp['startpage']]['orm'])) {
18245 $dl = ($this->pagedim[$this->page]['orm'] - $this->pagedim[$trwsp['startpage']]['orm']);
18246 $rsstartx -= $dl;
18247 $rsendx -= $dl;
18248 } elseif ((!$this->rtl) AND ($this->pagedim[$this->page]['olm'] != $this->pagedim[$trwsp['startpage']]['olm'])) {
18249 $dl = ($this->pagedim[$this->page]['olm'] - $this->pagedim[$trwsp['startpage']]['olm']);
18250 $rsstartx += $dl;
18251 $rsendx += $dl;
18252 }
18253 }
18254 if (($trwsp['rowspan'] > 0)
18255 AND ($rsstartx > ($this->x - $cellspacing['H'] - $current_cell_padding['L'] - $this->feps))
18256 AND ($rsstartx < ($this->x + $cellspacing['H'] + $current_cell_padding['R'] + $this->feps))
18257 AND (($trwsp['starty'] < ($this->y - $this->feps)) OR ($trwsp['startpage'] < $this->page) OR ($trwsp['startcolumn'] < $this->current_column))) {
18258 // set the starting X position of the current cell
18259 $this->x = $rsendx + $cellspacingx;
18260 // increment column indicator
18261 $colid += $trwsp['colspan'];
18262 if (($trwsp['rowspan'] == 1)
18263 AND (isset($dom[$trid]['endy']))
18264 AND (isset($dom[$trid]['endpage']))
18265 AND (isset($dom[$trid]['endcolumn']))
18266 AND ($trwsp['endpage'] == $dom[$trid]['endpage'])
18267 AND ($trwsp['endcolumn'] == $dom[$trid]['endcolumn'])) {
18268 // set ending Y position for row
18269 $dom[$table_el]['rowspans'][$rsk]['endy'] = max($dom[$trid]['endy'], $trwsp['endy']);
18270 $dom[$trid]['endy'] = $dom[$table_el]['rowspans'][$rsk]['endy'];
18271 }
18272 $rsk = 0;
18273 } else {
18274 ++$rsk;
18275 }
18276 }
18277 }
18278 if (isset($dom[$parentid]['width'])) {
18279 // user specified width
18280 $cellw = $this->getHTMLUnitToUnits($dom[$parentid]['width'], $table_columns_width, 'px');
18281 $tmpcw = ($cellw / $colspan);
18282 for ($i = 0; $i < $colspan; ++$i) {
18283 $table_colwidths[($colid + $i)] = $tmpcw;
18284 }
18285 } else {
18286 // inherit column width
18287 $cellw = 0;
18288 for ($i = 0; $i < $colspan; ++$i) {
18289 $cellw += $table_colwidths[($colid + $i)];
18290 }
18291 }
18292 $cellw += (($colspan - 1) * $cellspacing['H']);
18293 // increment column indicator
18294 $colid += $colspan;
18295 // add rowspan information to table element
18296 if ($rowspan > 1) {
18297 $trsid = array_push($dom[$table_el]['rowspans'], array('trid' => $trid, 'rowspan' => $rowspan, 'mrowspan' => $rowspan, 'colspan' => $colspan, 'startpage' => $this->page, 'startcolumn' => $this->current_column, 'startx' => $this->x, 'starty' => $this->y));
18298 }
18299 $cellid = array_push($dom[$trid]['cellpos'], array('startx' => $this->x));
18300 if ($rowspan > 1) {
18301 $dom[$trid]['cellpos'][($cellid - 1)]['rowspanid'] = ($trsid - 1);
18302 }
18303 // push background colors
18304 if (isset($dom[$parentid]['bgcolor']) AND ($dom[$parentid]['bgcolor'] !== false)) {
18305 $dom[$trid]['cellpos'][($cellid - 1)]['bgcolor'] = $dom[$parentid]['bgcolor'];
18306 }
18307 // store border info
18308 if (isset($tdborder) AND !empty($tdborder)) {
18309 $dom[$trid]['cellpos'][($cellid - 1)]['border'] = $tdborder;
18310 }
18311 $prevLastH = $this->lasth;
18312 // store some info for multicolumn mode
18313 if ($this->rtl) {
18314 $this->colxshift['x'] = $this->w - $this->x - $this->rMargin;
18315 } else {
18316 $this->colxshift['x'] = $this->x - $this->lMargin;
18317 }
18318 $this->colxshift['s'] = $cellspacing;
18319 $this->colxshift['p'] = $current_cell_padding;
18320 // ****** write the cell content ******
18321 $this->MultiCell($cellw, $cellh, $cell_content, false, $lalign, false, 2, '', '', true, 0, true, true, 0, 'T', false);
18322 // restore some values
18323 $this->colxshift = array('x' => 0, 's' => array('H' => 0, 'V' => 0), 'p' => array('L' => 0, 'T' => 0, 'R' => 0, 'B' => 0));
18324 $this->lasth = $prevLastH;
18325 $this->cell_padding = $old_cell_padding;
18326 $dom[$trid]['cellpos'][($cellid - 1)]['endx'] = $this->x;
18327 // update the end of row position
18328 if ($rowspan <= 1) {
18329 if (isset($dom[$trid]['endy'])) {
18330 if (($this->page == $dom[$trid]['endpage']) AND ($this->current_column == $dom[$trid]['endcolumn'])) {
18331 $dom[$trid]['endy'] = max($this->y, $dom[$trid]['endy']);
18332 } elseif (($this->page > $dom[$trid]['endpage']) OR ($this->current_column > $dom[$trid]['endcolumn'])) {
18333 $dom[$trid]['endy'] = $this->y;
18334 }
18335 } else {
18336 $dom[$trid]['endy'] = $this->y;
18337 }
18338 if (isset($dom[$trid]['endpage'])) {
18339 $dom[$trid]['endpage'] = max($this->page, $dom[$trid]['endpage']);
18340 } else {
18341 $dom[$trid]['endpage'] = $this->page;
18342 }
18343 if (isset($dom[$trid]['endcolumn'])) {
18344 $dom[$trid]['endcolumn'] = max($this->current_column, $dom[$trid]['endcolumn']);
18345 } else {
18346 $dom[$trid]['endcolumn'] = $this->current_column;
18347 }
18348 } else {
18349 // account for row-spanned cells
18350 $dom[$table_el]['rowspans'][($trsid - 1)]['endx'] = $this->x;
18351 $dom[$table_el]['rowspans'][($trsid - 1)]['endy'] = $this->y;
18352 $dom[$table_el]['rowspans'][($trsid - 1)]['endpage'] = $this->page;
18353 $dom[$table_el]['rowspans'][($trsid - 1)]['endcolumn'] = $this->current_column;
18354 }
18355 if (isset($dom[$table_el]['rowspans'])) {
18356 // update endy and endpage on rowspanned cells
18357 foreach ($dom[$table_el]['rowspans'] as $k => $trwsp) {
18358 if ($trwsp['rowspan'] > 0) {
18359 if (isset($dom[$trid]['endpage'])) {
18360 if (($trwsp['endpage'] == $dom[$trid]['endpage']) AND ($trwsp['endcolumn'] == $dom[$trid]['endcolumn'])) {
18361 $dom[$table_el]['rowspans'][$k]['endy'] = max($dom[$trid]['endy'], $trwsp['endy']);
18362 } elseif (($trwsp['endpage'] < $dom[$trid]['endpage']) OR ($trwsp['endcolumn'] < $dom[$trid]['endcolumn'])) {
18363 $dom[$table_el]['rowspans'][$k]['endy'] = $dom[$trid]['endy'];
18364 $dom[$table_el]['rowspans'][$k]['endpage'] = $dom[$trid]['endpage'];
18365 $dom[$table_el]['rowspans'][$k]['endcolumn'] = $dom[$trid]['endcolumn'];
18366 } else {
18367 $dom[$trid]['endy'] = $this->pagedim[$dom[$trid]['endpage']]['hk'] - $this->pagedim[$dom[$trid]['endpage']]['bm'];
18368 }
18369 }
18370 }
18371 }
18372 }
18373 $this->x += ($cellspacingx / 2);
18374 } else {
18375 // opening tag (or self-closing tag)
18376 if (!isset($opentagpos)) {
18377 if ($this->inxobj) {
18378 // we are inside an XObject template
18379 $opentagpos = strlen($this->xobjects[$this->xobjid]['outdata']);
18380 } elseif (!$this->InFooter) {
18381 if (isset($this->footerlen[$this->page])) {
18382 $this->footerpos[$this->page] = $this->pagelen[$this->page] - $this->footerlen[$this->page];
18383 } else {
18384 $this->footerpos[$this->page] = $this->pagelen[$this->page];
18385 }
18386 $opentagpos = $this->footerpos[$this->page];
18387 }
18388 }
18389 $dom = $this->openHTMLTagHandler($dom, $key, $cell);
18390 }
18391 } else { // closing tag
18392 $prev_numpages = $this->numpages;
18393 $old_bordermrk = $this->bordermrk[$this->page];
18394 $dom = $this->closeHTMLTagHandler($dom, $key, $cell, $maxbottomliney);
18395 if ($this->bordermrk[$this->page] > $old_bordermrk) {
18396 $startlinepos += ($this->bordermrk[$this->page] - $old_bordermrk);
18397 }
18398 if ($prev_numpages > $this->numpages) {
18399 $startlinepage = $this->page;
18400 }
18401 }
18402 } elseif (strlen($dom[$key]['value']) > 0) {
18403 // print list-item
18404 if (!TCPDF_STATIC::empty_string($this->lispacer) AND ($this->lispacer != '^')) {
18405 $this->SetFont($pfontname, $pfontstyle, $pfontsize);
18406 $this->resetLastH();
18407 $minstartliney = $this->y;
18408 $maxbottomliney = ($startliney + $this->getCellHeight($this->FontSize));
18409 if (is_numeric($pfontsize) AND ($pfontsize > 0)) {
18410 $this->putHtmlListBullet($this->listnum, $this->lispacer, $pfontsize);
18411 }
18412 $this->SetFont($curfontname, $curfontstyle, $curfontsize);
18413 $this->resetLastH();
18414 if (is_numeric($pfontsize) AND ($pfontsize > 0) AND is_numeric($curfontsize) AND ($curfontsize > 0) AND ($pfontsize != $curfontsize)) {
18415 $pfontascent = $this->getFontAscent($pfontname, $pfontstyle, $pfontsize);
18416 $pfontdescent = $this->getFontDescent($pfontname, $pfontstyle, $pfontsize);
18417 $this->y += ($this->getCellHeight(($pfontsize - $curfontsize) / $this->k) + $pfontascent - $curfontascent - $pfontdescent + $curfontdescent) / 2;
18418 $minstartliney = min($this->y, $minstartliney);
18419 $maxbottomliney = max(($this->y + $this->getCellHeight($pfontsize / $this->k)), $maxbottomliney);
18420 }
18421 }
18422 // text
18423 $this->htmlvspace = 0;
18424 if ((!$this->premode) AND $this->isRTLTextDir()) {
18425 // reverse spaces order
18426 $lsp = ''; // left spaces
18427 $rsp = ''; // right spaces
18428 if (preg_match('/^('.$this->re_space['p'].'+)/'.$this->re_space['m'], $dom[$key]['value'], $matches)) {
18429 $lsp = $matches[1];
18430 }
18431 if (preg_match('/('.$this->re_space['p'].'+)$/'.$this->re_space['m'], $dom[$key]['value'], $matches)) {
18432 $rsp = $matches[1];
18433 }
18434 $dom[$key]['value'] = $rsp.$this->stringTrim($dom[$key]['value']).$lsp;
18435 }
18436 if ($newline) {
18437 if (!$this->premode) {
18438 $prelen = strlen($dom[$key]['value']);
18439 if ($this->isRTLTextDir()) {
18440 // right trim except non-breaking space
18441 $dom[$key]['value'] = $this->stringRightTrim($dom[$key]['value']);
18442 } else {
18443 // left trim except non-breaking space
18444 $dom[$key]['value'] = $this->stringLeftTrim($dom[$key]['value']);
18445 }
18446 $postlen = strlen($dom[$key]['value']);
18447 if (($postlen == 0) AND ($prelen > 0)) {
18448 $dom[$key]['trimmed_space'] = true;
18449 }
18450 }
18451 $newline = false;
18452 $firstblock = true;
18453 } else {
18454 $firstblock = false;
18455 // replace empty multiple spaces string with a single space
18456 $dom[$key]['value'] = preg_replace('/^'.$this->re_space['p'].'+$/'.$this->re_space['m'], chr(32), $dom[$key]['value']);
18457 }
18458 $strrest = '';
18459 if ($this->rtl) {
18460 $this->x -= $this->textindent;
18461 } else {
18462 $this->x += $this->textindent;
18463 }
18464 if (!isset($dom[$key]['trimmed_space']) OR !$dom[$key]['trimmed_space']) {
18465 $strlinelen = $this->GetStringWidth($dom[$key]['value']);
18466 if (!empty($this->HREF) AND (isset($this->HREF['url']))) {
18467 // HTML <a> Link
18468 $hrefcolor = '';
18469 if (isset($dom[($dom[$key]['parent'])]['fgcolor']) AND ($dom[($dom[$key]['parent'])]['fgcolor'] !== false)) {
18470 $hrefcolor = $dom[($dom[$key]['parent'])]['fgcolor'];
18471 }
18472 $hrefstyle = -1;
18473 if (isset($dom[($dom[$key]['parent'])]['fontstyle']) AND ($dom[($dom[$key]['parent'])]['fontstyle'] !== false)) {
18474 $hrefstyle = $dom[($dom[$key]['parent'])]['fontstyle'];
18475 }
18476 $strrest = $this->addHtmlLink($this->HREF['url'], $dom[$key]['value'], $wfill, true, $hrefcolor, $hrefstyle, true);
18477 } else {
18478 $wadj = 0; // space to leave for block continuity
18479 if ($this->rtl) {
18480 $cwa = ($this->x - $this->lMargin);
18481 } else {
18482 $cwa = ($this->w - $this->rMargin - $this->x);
18483 }
18484 if (($strlinelen < $cwa) AND (isset($dom[($key + 1)])) AND ($dom[($key + 1)]['tag']) AND (!$dom[($key + 1)]['block'])) {
18485 // check the next text blocks for continuity
18486 $nkey = ($key + 1);
18487 $write_block = true;
18488 $same_textdir = true;
18489 $tmp_fontname = $this->FontFamily;
18490 $tmp_fontstyle = $this->FontStyle;
18491 $tmp_fontsize = $this->FontSizePt;
18492 while ($write_block AND isset($dom[$nkey])) {
18493 if ($dom[$nkey]['tag']) {
18494 if ($dom[$nkey]['block']) {
18495 // end of block
18496 $write_block = false;
18497 }
18498 $tmp_fontname = isset($dom[$nkey]['fontname']) ? $dom[$nkey]['fontname'] : $this->FontFamily;
18499 $tmp_fontstyle = isset($dom[$nkey]['fontstyle']) ? $dom[$nkey]['fontstyle'] : $this->FontStyle;
18500 $tmp_fontsize = isset($dom[$nkey]['fontsize']) ? $dom[$nkey]['fontsize'] : $this->FontSizePt;
18501 $same_textdir = ($dom[$nkey]['dir'] == $dom[$key]['dir']);
18502 } else {
18503 $nextstr = TCPDF_STATIC::pregSplit('/'.$this->re_space['p'].'+/', $this->re_space['m'], $dom[$nkey]['value']);
18504 if (isset($nextstr[0]) AND $same_textdir) {
18505 $wadj += $this->GetStringWidth($nextstr[0], $tmp_fontname, $tmp_fontstyle, $tmp_fontsize);
18506 if (isset($nextstr[1])) {
18507 $write_block = false;
18508 }
18509 }
18510 }
18511 ++$nkey;
18512 }
18513 }
18514 if (($wadj > 0) AND (($strlinelen + $wadj) >= $cwa)) {
18515 $wadj = 0;
18516 $nextstr = TCPDF_STATIC::pregSplit('/'.$this->re_space['p'].'/', $this->re_space['m'], $dom[$key]['value']);
18517 $numblks = count($nextstr);
18518 if ($numblks > 1) {
18519 // try to split on blank spaces
18520 $wadj = ($cwa - $strlinelen + $this->GetStringWidth($nextstr[($numblks - 1)]));
18521 } else {
18522 // set the entire block on new line
18523 $wadj = $this->GetStringWidth($nextstr[0]);
18524 }
18525 }
18526 // check for reversed text direction
18527 if (($wadj > 0) AND (($this->rtl AND ($this->tmprtl === 'L')) OR (!$this->rtl AND ($this->tmprtl === 'R')))) {
18528 // LTR text on RTL direction or RTL text on LTR direction
18529 $reverse_dir = true;
18530 $this->rtl = !$this->rtl;
18531 $revshift = ($strlinelen + $wadj + 0.000001); // add little quantity for rounding problems
18532 if ($this->rtl) {
18533 $this->x += $revshift;
18534 } else {
18535 $this->x -= $revshift;
18536 }
18537 $xws = $this->x;
18538 }
18539 // ****** write only until the end of the line and get the rest ******
18540 $strrest = $this->Write($this->lasth, $dom[$key]['value'], '', $wfill, '', false, 0, true, $firstblock, 0, $wadj);
18541 // restore default direction
18542 if ($reverse_dir AND ($wadj == 0)) {
18543 $this->x = $xws;
18544 $this->rtl = !$this->rtl;
18545 $reverse_dir = false;
18546 }
18547 }
18548 }
18549 $this->textindent = 0;
18550 if (strlen($strrest) > 0) {
18551 // store the remaining string on the previous $key position
18552 $this->newline = true;
18553 if ($strrest == $dom[$key]['value']) {
18554 // used to avoid infinite loop
18555 ++$loop;
18556 } else {
18557 $loop = 0;
18558 }
18559 $dom[$key]['value'] = $strrest;
18560 if ($cell) {
18561 if ($this->rtl) {
18562 $this->x -= $this->cell_padding['R'];
18563 } else {
18564 $this->x += $this->cell_padding['L'];
18565 }
18566 }
18567 if ($loop < 3) {
18568 --$key;
18569 }
18570 } else {
18571 $loop = 0;
18572 // add the positive font spacing of the last character (if any)
18573 if ($this->font_spacing > 0) {
18574 if ($this->rtl) {
18575 $this->x -= $this->font_spacing;
18576 } else {
18577 $this->x += $this->font_spacing;
18578 }
18579 }
18580 }
18581 }
18582 ++$key;
18583 if (isset($dom[$key]['tag']) AND $dom[$key]['tag'] AND (!isset($dom[$key]['opening']) OR !$dom[$key]['opening']) AND isset($dom[($dom[$key]['parent'])]['attribute']['nobr']) AND ($dom[($dom[$key]['parent'])]['attribute']['nobr'] == 'true')) {
18584 // check if we are on a new page or on a new column
18585 if ((!$undo) AND (($this->y < $this->start_transaction_y) OR (($dom[$key]['value'] == 'tr') AND ($dom[($dom[$key]['parent'])]['endy'] < $this->start_transaction_y)))) {
18586 // we are on a new page or on a new column and the total object height is less than the available vertical space.
18587 // restore previous object
18588 $this->rollbackTransaction(true);
18589 // restore previous values
18590 foreach ($this_method_vars as $vkey => $vval) {
18591 $$vkey = $vval;
18592 }
18593 if (!empty($dom[$key]['thead'])) {
18594 $this->inthead = true;
18595 }
18596 // add a page (or trig AcceptPageBreak() for multicolumn mode)
18597 $pre_y = $this->y;
18598 if ((!$this->checkPageBreak($this->PageBreakTrigger + 1)) AND ($this->y < $pre_y)) {
18599 $startliney = $this->y;
18600 }
18601 $undo = true; // avoid infinite loop
18602 } else {
18603 $undo = false;
18604 }
18605 }
18606 } // end for each $key
18607 // align the last line
18608 if (isset($startlinex)) {
18609 $yshift = ($minstartliney - $startliney);
18610 if (($yshift > 0) OR ($this->page > $startlinepage)) {
18611 $yshift = 0;
18612 }
18613 $t_x = 0;
18614 // the last line must be shifted to be aligned as requested
18615 $linew = abs($this->endlinex - $startlinex);
18616 if ($this->inxobj) {
18617 // we are inside an XObject template
18618 $pstart = substr($this->xobjects[$this->xobjid]['outdata'], 0, $startlinepos);
18619 if (isset($opentagpos)) {
18620 $midpos = $opentagpos;
18621 } else {
18622 $midpos = 0;
18623 }
18624 if ($midpos > 0) {
18625 $pmid = substr($this->xobjects[$this->xobjid]['outdata'], $startlinepos, ($midpos - $startlinepos));
18626 $pend = substr($this->xobjects[$this->xobjid]['outdata'], $midpos);
18627 } else {
18628 $pmid = substr($this->xobjects[$this->xobjid]['outdata'], $startlinepos);
18629 $pend = '';
18630 }
18631 } else {
18632 $pstart = substr($this->getPageBuffer($startlinepage), 0, $startlinepos);
18633 if (isset($opentagpos) AND isset($this->footerlen[$startlinepage]) AND (!$this->InFooter)) {
18634 $this->footerpos[$startlinepage] = $this->pagelen[$startlinepage] - $this->footerlen[$startlinepage];
18635 $midpos = min($opentagpos, $this->footerpos[$startlinepage]);
18636 } elseif (isset($opentagpos)) {
18637 $midpos = $opentagpos;
18638 } elseif (isset($this->footerlen[$startlinepage]) AND (!$this->InFooter)) {
18639 $this->footerpos[$startlinepage] = $this->pagelen[$startlinepage] - $this->footerlen[$startlinepage];
18640 $midpos = $this->footerpos[$startlinepage];
18641 } else {
18642 $midpos = 0;
18643 }
18644 if ($midpos > 0) {
18645 $pmid = substr($this->getPageBuffer($startlinepage), $startlinepos, ($midpos - $startlinepos));
18646 $pend = substr($this->getPageBuffer($startlinepage), $midpos);
18647 } else {
18648 $pmid = substr($this->getPageBuffer($startlinepage), $startlinepos);
18649 $pend = '';
18650 }
18651 }
18652 if ((isset($plalign) AND ((($plalign == 'C') OR (($plalign == 'R') AND (!$this->rtl)) OR (($plalign == 'L') AND ($this->rtl)))))) {
18653 // calculate shifting amount
18654 $tw = $w;
18655 if ($this->lMargin != $prevlMargin) {
18656 $tw += ($prevlMargin - $this->lMargin);
18657 }
18658 if ($this->rMargin != $prevrMargin) {
18659 $tw += ($prevrMargin - $this->rMargin);
18660 }
18661 $one_space_width = $this->GetStringWidth(chr(32));
18662 $no = 0; // number of spaces on a line contained on a single block
18663 if ($this->isRTLTextDir()) { // RTL
18664 // remove left space if exist
18665 $pos1 = TCPDF_STATIC::revstrpos($pmid, '[(');
18666 if ($pos1 > 0) {
18667 $pos1 = intval($pos1);
18668 if ($this->isUnicodeFont()) {
18669 $pos2 = intval(TCPDF_STATIC::revstrpos($pmid, '[('.chr(0).chr(32)));
18670 $spacelen = 2;
18671 } else {
18672 $pos2 = intval(TCPDF_STATIC::revstrpos($pmid, '[('.chr(32)));
18673 $spacelen = 1;
18674 }
18675 if ($pos1 == $pos2) {
18676 $pmid = substr($pmid, 0, ($pos1 + 2)).substr($pmid, ($pos1 + 2 + $spacelen));
18677 if (substr($pmid, $pos1, 4) == '[()]') {
18678 $linew -= $one_space_width;
18679 } elseif ($pos1 == strpos($pmid, '[(')) {
18680 $no = 1;
18681 }
18682 }
18683 }
18684 } else { // LTR
18685 // remove right space if exist
18686 $pos1 = TCPDF_STATIC::revstrpos($pmid, ')]');
18687 if ($pos1 > 0) {
18688 $pos1 = intval($pos1);
18689 if ($this->isUnicodeFont()) {
18690 $pos2 = intval(TCPDF_STATIC::revstrpos($pmid, chr(0).chr(32).')]')) + 2;
18691 $spacelen = 2;
18692 } else {
18693 $pos2 = intval(TCPDF_STATIC::revstrpos($pmid, chr(32).')]')) + 1;
18694 $spacelen = 1;
18695 }
18696 if ($pos1 == $pos2) {
18697 $pmid = substr($pmid, 0, ($pos1 - $spacelen)).substr($pmid, $pos1);
18698 $linew -= $one_space_width;
18699 }
18700 }
18701 }
18702 $mdiff = ($tw - $linew);
18703 if ($plalign == 'C') {
18704 if ($this->rtl) {
18705 $t_x = -($mdiff / 2);
18706 } else {
18707 $t_x = ($mdiff / 2);
18708 }
18709 } elseif ($plalign == 'R') {
18710 // right alignment on LTR document
18711 $t_x = $mdiff;
18712 } elseif ($plalign == 'L') {
18713 // left alignment on RTL document
18714 $t_x = -$mdiff;
18715 }
18716 } // end if startlinex
18717 if (($t_x != 0) OR ($yshift < 0)) {
18718 // shift the line
18719 $trx = sprintf('1 0 0 1 %F %F cm', ($t_x * $this->k), ($yshift * $this->k));
18720 $pstart .= "\nq\n".$trx."\n".$pmid."\nQ\n";
18721 $endlinepos = strlen($pstart);
18722 if ($this->inxobj) {
18723 // we are inside an XObject template
18724 $this->xobjects[$this->xobjid]['outdata'] = $pstart.$pend;
18725 foreach ($this->xobjects[$this->xobjid]['annotations'] as $pak => $pac) {
18726 if ($pak >= $pask) {
18727 $this->xobjects[$this->xobjid]['annotations'][$pak]['x'] += $t_x;
18728 $this->xobjects[$this->xobjid]['annotations'][$pak]['y'] -= $yshift;
18729 }
18730 }
18731 } else {
18732 $this->setPageBuffer($startlinepage, $pstart.$pend);
18733 // shift the annotations and links
18734 if (isset($this->PageAnnots[$this->page])) {
18735 foreach ($this->PageAnnots[$this->page] as $pak => $pac) {
18736 if ($pak >= $pask) {
18737 $this->PageAnnots[$this->page][$pak]['x'] += $t_x;
18738 $this->PageAnnots[$this->page][$pak]['y'] -= $yshift;
18739 }
18740 }
18741 }
18742 }
18743 $this->y -= $yshift;
18744 $yshift = 0;
18745 }
18746 }
18747 // restore previous values
18748 $this->setGraphicVars($gvars);
18749 if ($this->num_columns > 1) {
18750 $this->selectColumn();
18751 } elseif ($this->page > $prevPage) {
18752 $this->lMargin = $this->pagedim[$this->page]['olm'];
18753 $this->rMargin = $this->pagedim[$this->page]['orm'];
18754 }
18755 // restore previous list state
18756 $this->cell_height_ratio = $prev_cell_height_ratio;
18757 $this->listnum = $prev_listnum;
18758 $this->listordered = $prev_listordered;
18759 $this->listcount = $prev_listcount;
18760 $this->lispacer = $prev_lispacer;
18761 if ($ln AND (!($cell AND ($dom[$key-1]['value'] == 'table')))) {
18762 $this->Ln($this->lasth);
18763 if ($this->y < $maxbottomliney) {
18764 $this->y = $maxbottomliney;
18765 }
18766 }
18767 unset($dom);
18768 }
18769
18770 /**
18771 * Process opening tags.
18772 * @param $dom (array) html dom array
18773 * @param $key (int) current element id
18774 * @param $cell (boolean) if true add the default left (or right if RTL) padding to each new line (default false).
18775 * @return $dom array
18776 * @protected
18777 */
18778 protected function openHTMLTagHandler($dom, $key, $cell) {
18779 $tag = $dom[$key];
18780 $parent = $dom[($dom[$key]['parent'])];
18781 $firsttag = ($key == 1);
18782 // check for text direction attribute
18783 if (isset($tag['dir'])) {
18784 $this->setTempRTL($tag['dir']);
18785 } else {
18786 $this->tmprtl = false;
18787 }
18788 if ($tag['block']) {
18789 $hbz = 0; // distance from y to line bottom
18790 $hb = 0; // vertical space between block tags
18791 // calculate vertical space for block tags
18792 if (isset($this->tagvspaces[$tag['value']][0]['h']) AND ($this->tagvspaces[$tag['value']][0]['h'] >= 0)) {
18793 $cur_h = $this->tagvspaces[$tag['value']][0]['h'];
18794 } elseif (isset($tag['fontsize'])) {
18795 $cur_h = $this->getCellHeight($tag['fontsize'] / $this->k);
18796 } else {
18797 $cur_h = $this->getCellHeight($this->FontSize);
18798 }
18799 if (isset($this->tagvspaces[$tag['value']][0]['n'])) {
18800 $on = $this->tagvspaces[$tag['value']][0]['n'];
18801 } elseif (preg_match('/[h][0-9]/', $tag['value']) > 0) {
18802 $on = 0.6;
18803 } else {
18804 $on = 1;
18805 }
18806 if ((!isset($this->tagvspaces[$tag['value']])) AND (in_array($tag['value'], array('div', 'dt', 'dd', 'li', 'br', 'hr')))) {
18807 $hb = 0;
18808 } else {
18809 $hb = ($on * $cur_h);
18810 }
18811 if (($this->htmlvspace <= 0) AND ($on > 0)) {
18812 if (isset($parent['fontsize'])) {
18813 $hbz = (($parent['fontsize'] / $this->k) * $this->cell_height_ratio);
18814 } else {
18815 $hbz = $this->getCellHeight($this->FontSize);
18816 }
18817 }
18818 if (isset($dom[($key - 1)]) AND ($dom[($key - 1)]['value'] == 'table')) {
18819 // fix vertical space after table
18820 $hbz = 0;
18821 }
18822 // closing vertical space
18823 $hbc = 0;
18824 if (isset($this->tagvspaces[$tag['value']][1]['h']) AND ($this->tagvspaces[$tag['value']][1]['h'] >= 0)) {
18825 $pre_h = $this->tagvspaces[$tag['value']][1]['h'];
18826 } elseif (isset($parent['fontsize'])) {
18827 $pre_h = $this->getCellHeight($parent['fontsize'] / $this->k);
18828 } else {
18829 $pre_h = $this->getCellHeight($this->FontSize);
18830 }
18831 if (isset($this->tagvspaces[$tag['value']][1]['n'])) {
18832 $cn = $this->tagvspaces[$tag['value']][1]['n'];
18833 } elseif (preg_match('/[h][0-9]/', $tag['value']) > 0) {
18834 $cn = 0.6;
18835 } else {
18836 $cn = 1;
18837 }
18838 if (isset($this->tagvspaces[$tag['value']][1])) {
18839 $hbc = ($cn * $pre_h);
18840 }
18841 }
18842 // Opening tag
18843 switch($tag['value']) {
18844 case 'table': {
18845 $cp = 0;
18846 $cs = 0;
18847 $dom[$key]['rowspans'] = array();
18848 if (!isset($dom[$key]['attribute']['nested']) OR ($dom[$key]['attribute']['nested'] != 'true')) {
18849 $this->htmlvspace = 0;
18850 // set table header
18851 if (!TCPDF_STATIC::empty_string($dom[$key]['thead'])) {
18852 // set table header
18853 $this->thead = $dom[$key]['thead'];
18854 if (!isset($this->theadMargins) OR (empty($this->theadMargins))) {
18855 $this->theadMargins = array();
18856 $this->theadMargins['cell_padding'] = $this->cell_padding;
18857 $this->theadMargins['lmargin'] = $this->lMargin;
18858 $this->theadMargins['rmargin'] = $this->rMargin;
18859 $this->theadMargins['page'] = $this->page;
18860 $this->theadMargins['cell'] = $cell;
18861 $this->theadMargins['gvars'] = $this->getGraphicVars();
18862 }
18863 }
18864 }
18865 // store current margins and page
18866 $dom[$key]['old_cell_padding'] = $this->cell_padding;
18867 if (isset($tag['attribute']['cellpadding'])) {
18868 $pad = $this->getHTMLUnitToUnits($tag['attribute']['cellpadding'], 1, 'px');
18869 $this->SetCellPadding($pad);
18870 } elseif (isset($tag['padding'])) {
18871 $this->cell_padding = $tag['padding'];
18872 }
18873 if (isset($tag['attribute']['cellspacing'])) {
18874 $cs = $this->getHTMLUnitToUnits($tag['attribute']['cellspacing'], 1, 'px');
18875 } elseif (isset($tag['border-spacing'])) {
18876 $cs = $tag['border-spacing']['V'];
18877 }
18878 $prev_y = $this->y;
18879 if ($this->checkPageBreak(((2 * $cp) + (2 * $cs) + $this->lasth), '', false) OR ($this->y < $prev_y)) {
18880 $this->inthead = true;
18881 // add a page (or trig AcceptPageBreak() for multicolumn mode)
18882 $this->checkPageBreak($this->PageBreakTrigger + 1);
18883 }
18884 break;
18885 }
18886 case 'tr': {
18887 // array of columns positions
18888 $dom[$key]['cellpos'] = array();
18889 break;
18890 }
18891 case 'hr': {
18892 if ((isset($tag['height'])) AND ($tag['height'] != '')) {
18893 $hrHeight = $this->getHTMLUnitToUnits($tag['height'], 1, 'px');
18894 } else {
18895 $hrHeight = $this->GetLineWidth();
18896 }
18897 $this->addHTMLVertSpace($hbz, max($hb, ($hrHeight / 2)), $cell, $firsttag);
18898 $x = $this->GetX();
18899 $y = $this->GetY();
18900 $wtmp = $this->w - $this->lMargin - $this->rMargin;
18901 if ($cell) {
18902 $wtmp -= ($this->cell_padding['L'] + $this->cell_padding['R']);
18903 }
18904 if ((isset($tag['width'])) AND ($tag['width'] != '')) {
18905 $hrWidth = $this->getHTMLUnitToUnits($tag['width'], $wtmp, 'px');
18906 } else {
18907 $hrWidth = $wtmp;
18908 }
18909 $prevlinewidth = $this->GetLineWidth();
18910 $this->SetLineWidth($hrHeight);
18911 $this->Line($x, $y, $x + $hrWidth, $y);
18912 $this->SetLineWidth($prevlinewidth);
18913 $this->addHTMLVertSpace(max($hbc, ($hrHeight / 2)), 0, $cell, !isset($dom[($key + 1)]));
18914 break;
18915 }
18916 case 'a': {
18917 if (array_key_exists('href', $tag['attribute'])) {
18918 $this->HREF['url'] = $tag['attribute']['href'];
18919 }
18920 break;
18921 }
18922 case 'img': {
18923 if (!empty($tag['attribute']['src'])) {
18924 if ($tag['attribute']['src'][0] === '@') {
18925 // data stream
18926 $tag['attribute']['src'] = '@'.base64_decode(substr($tag['attribute']['src'], 1));
18927 $type = '';
18928 } else {
18929 // get image type
18930 $type = TCPDF_IMAGES::getImageFileType($tag['attribute']['src']);
18931 }
18932 if (!isset($tag['width'])) {
18933 $tag['width'] = 0;
18934 }
18935 if (!isset($tag['height'])) {
18936 $tag['height'] = 0;
18937 }
18938 //if (!isset($tag['attribute']['align'])) {
18939 // the only alignment supported is "bottom"
18940 // further development is required for other modes.
18941 $tag['attribute']['align'] = 'bottom';
18942 //}
18943 switch($tag['attribute']['align']) {
18944 case 'top': {
18945 $align = 'T';
18946 break;
18947 }
18948 case 'middle': {
18949 $align = 'M';
18950 break;
18951 }
18952 case 'bottom': {
18953 $align = 'B';
18954 break;
18955 }
18956 default: {
18957 $align = 'B';
18958 break;
18959 }
18960 }
18961 $prevy = $this->y;
18962 $xpos = $this->x;
18963 $imglink = '';
18964 if (isset($this->HREF['url']) AND !TCPDF_STATIC::empty_string($this->HREF['url'])) {
18965 $imglink = $this->HREF['url'];
18966 if ($imglink[0] == '#') {
18967 // convert url to internal link
18968 $lnkdata = explode(',', $imglink);
18969 if (isset($lnkdata[0])) {
18970 $page = intval(substr($lnkdata[0], 1));
18971 if (empty($page) OR ($page <= 0)) {
18972 $page = $this->page;
18973 }
18974 if (isset($lnkdata[1]) AND (strlen($lnkdata[1]) > 0)) {
18975 $lnky = floatval($lnkdata[1]);
18976 } else {
18977 $lnky = 0;
18978 }
18979 $imglink = $this->AddLink();
18980 $this->SetLink($imglink, $lnky, $page);
18981 }
18982 }
18983 }
18984 $border = 0;
18985 if (isset($tag['border']) AND !empty($tag['border'])) {
18986 // currently only support 1 (frame) or a combination of 'LTRB'
18987 $border = $tag['border'];
18988 }
18989 $iw = '';
18990 if (isset($tag['width'])) {
18991 $iw = $this->getHTMLUnitToUnits($tag['width'], ($tag['fontsize'] / $this->k), 'px', false);
18992 }
18993 $ih = '';
18994 if (isset($tag['height'])) {
18995 $ih = $this->getHTMLUnitToUnits($tag['height'], ($tag['fontsize'] / $this->k), 'px', false);
18996 }
18997 if (($type == 'eps') OR ($type == 'ai')) {
18998 $this->ImageEps($tag['attribute']['src'], $xpos, $this->y, $iw, $ih, $imglink, true, $align, '', $border, true);
18999 } elseif ($type == 'svg') {
19000 $this->ImageSVG($tag['attribute']['src'], $xpos, $this->y, $iw, $ih, $imglink, $align, '', $border, true);
19001 } else {
19002 $this->Image($tag['attribute']['src'], $xpos, $this->y, $iw, $ih, '', $imglink, $align, false, 300, '', false, false, $border, false, false, true);
19003 }
19004 switch($align) {
19005 case 'T': {
19006 $this->y = $prevy;
19007 break;
19008 }
19009 case 'M': {
19010 $this->y = (($this->img_rb_y + $prevy - ($this->getCellHeight($tag['fontsize'] / $this->k))) / 2);
19011 break;
19012 }
19013 case 'B': {
19014 $this->y = $this->img_rb_y - ($this->getCellHeight($tag['fontsize'] / $this->k) - ($this->getFontDescent($tag['fontname'], $tag['fontstyle'], $tag['fontsize']) * $this->cell_height_ratio));
19015 break;
19016 }
19017 }
19018 }
19019 break;
19020 }
19021 case 'dl': {
19022 ++$this->listnum;
19023 if ($this->listnum == 1) {
19024 $this->addHTMLVertSpace($hbz, $hb, $cell, $firsttag);
19025 } else {
19026 $this->addHTMLVertSpace(0, 0, $cell, $firsttag);
19027 }
19028 break;
19029 }
19030 case 'dt': {
19031 $this->addHTMLVertSpace($hbz, $hb, $cell, $firsttag);
19032 break;
19033 }
19034 case 'dd': {
19035 if ($this->rtl) {
19036 $this->rMargin += $this->listindent;
19037 } else {
19038 $this->lMargin += $this->listindent;
19039 }
19040 ++$this->listindentlevel;
19041 $this->addHTMLVertSpace($hbz, $hb, $cell, $firsttag);
19042 break;
19043 }
19044 case 'ul':
19045 case 'ol': {
19046 ++$this->listnum;
19047 if ($tag['value'] == 'ol') {
19048 $this->listordered[$this->listnum] = true;
19049 } else {
19050 $this->listordered[$this->listnum] = false;
19051 }
19052 if (isset($tag['attribute']['start'])) {
19053 $this->listcount[$this->listnum] = intval($tag['attribute']['start']) - 1;
19054 } else {
19055 $this->listcount[$this->listnum] = 0;
19056 }
19057 if ($this->rtl) {
19058 $this->rMargin += $this->listindent;
19059 $this->x -= $this->listindent;
19060 } else {
19061 $this->lMargin += $this->listindent;
19062 $this->x += $this->listindent;
19063 }
19064 ++$this->listindentlevel;
19065 if ($this->listnum == 1) {
19066 if ($key > 1) {
19067 $this->addHTMLVertSpace($hbz, $hb, $cell, $firsttag);
19068 }
19069 } else {
19070 $this->addHTMLVertSpace(0, 0, $cell, $firsttag);
19071 }
19072 break;
19073 }
19074 case 'li': {
19075 if ($key > 2) {
19076 $this->addHTMLVertSpace($hbz, $hb, $cell, $firsttag);
19077 }
19078 if ($this->listordered[$this->listnum]) {
19079 // ordered item
19080 if (isset($parent['attribute']['type']) AND !TCPDF_STATIC::empty_string($parent['attribute']['type'])) {
19081 $this->lispacer = $parent['attribute']['type'];
19082 } elseif (isset($parent['listtype']) AND !TCPDF_STATIC::empty_string($parent['listtype'])) {
19083 $this->lispacer = $parent['listtype'];
19084 } elseif (isset($this->lisymbol) AND !TCPDF_STATIC::empty_string($this->lisymbol)) {
19085 $this->lispacer = $this->lisymbol;
19086 } else {
19087 $this->lispacer = '#';
19088 }
19089 ++$this->listcount[$this->listnum];
19090 if (isset($tag['attribute']['value'])) {
19091 $this->listcount[$this->listnum] = intval($tag['attribute']['value']);
19092 }
19093 } else {
19094 // unordered item
19095 if (isset($parent['attribute']['type']) AND !TCPDF_STATIC::empty_string($parent['attribute']['type'])) {
19096 $this->lispacer = $parent['attribute']['type'];
19097 } elseif (isset($parent['listtype']) AND !TCPDF_STATIC::empty_string($parent['listtype'])) {
19098 $this->lispacer = $parent['listtype'];
19099 } elseif (isset($this->lisymbol) AND !TCPDF_STATIC::empty_string($this->lisymbol)) {
19100 $this->lispacer = $this->lisymbol;
19101 } else {
19102 $this->lispacer = '!';
19103 }
19104 }
19105 break;
19106 }
19107 case 'blockquote': {
19108 if ($this->rtl) {
19109 $this->rMargin += $this->listindent;
19110 } else {
19111 $this->lMargin += $this->listindent;
19112 }
19113 ++$this->listindentlevel;
19114 $this->addHTMLVertSpace($hbz, $hb, $cell, $firsttag);
19115 break;
19116 }
19117 case 'br': {
19118 $this->addHTMLVertSpace($hbz, $hb, $cell, $firsttag);
19119 break;
19120 }
19121 case 'div': {
19122 $this->addHTMLVertSpace($hbz, $hb, $cell, $firsttag);
19123 break;
19124 }
19125 case 'p': {
19126 $this->addHTMLVertSpace($hbz, $hb, $cell, $firsttag);
19127 break;
19128 }
19129 case 'pre': {
19130 $this->addHTMLVertSpace($hbz, $hb, $cell, $firsttag);
19131 $this->premode = true;
19132 break;
19133 }
19134 case 'sup': {
19135 $this->SetXY($this->GetX(), $this->GetY() - ((0.7 * $this->FontSizePt) / $this->k));
19136 break;
19137 }
19138 case 'sub': {
19139 $this->SetXY($this->GetX(), $this->GetY() + ((0.3 * $this->FontSizePt) / $this->k));
19140 break;
19141 }
19142 case 'h1':
19143 case 'h2':
19144 case 'h3':
19145 case 'h4':
19146 case 'h5':
19147 case 'h6': {
19148 $this->addHTMLVertSpace($hbz, $hb, $cell, $firsttag);
19149 break;
19150 }
19151 // Form fields (since 4.8.000 - 2009-09-07)
19152 case 'form': {
19153 if (isset($tag['attribute']['action'])) {
19154 $this->form_action = $tag['attribute']['action'];
19155 } else {
19156 $this->Error('Please explicitly set action attribute path!');
19157 }
19158 if (isset($tag['attribute']['enctype'])) {
19159 $this->form_enctype = $tag['attribute']['enctype'];
19160 } else {
19161 $this->form_enctype = 'application/x-www-form-urlencoded';
19162 }
19163 if (isset($tag['attribute']['method'])) {
19164 $this->form_mode = $tag['attribute']['method'];
19165 } else {
19166 $this->form_mode = 'post';
19167 }
19168 break;
19169 }
19170 case 'input': {
19171 if (isset($tag['attribute']['name']) AND !TCPDF_STATIC::empty_string($tag['attribute']['name'])) {
19172 $name = $tag['attribute']['name'];
19173 } else {
19174 break;
19175 }
19176 $prop = array();
19177 $opt = array();
19178 if (isset($tag['attribute']['readonly']) AND !TCPDF_STATIC::empty_string($tag['attribute']['readonly'])) {
19179 $prop['readonly'] = true;
19180 }
19181 if (isset($tag['attribute']['value']) AND !TCPDF_STATIC::empty_string($tag['attribute']['value'])) {
19182 $value = $tag['attribute']['value'];
19183 }
19184 if (isset($tag['attribute']['maxlength']) AND !TCPDF_STATIC::empty_string($tag['attribute']['maxlength'])) {
19185 $opt['maxlen'] = intval($tag['attribute']['maxlength']);
19186 }
19187 $h = $this->getCellHeight($this->FontSize);
19188 if (isset($tag['attribute']['size']) AND !TCPDF_STATIC::empty_string($tag['attribute']['size'])) {
19189 $w = intval($tag['attribute']['size']) * $this->GetStringWidth(chr(32)) * 2;
19190 } else {
19191 $w = $h;
19192 }
19193 if (isset($tag['attribute']['checked']) AND (($tag['attribute']['checked'] == 'checked') OR ($tag['attribute']['checked'] == 'true'))) {
19194 $checked = true;
19195 } else {
19196 $checked = false;
19197 }
19198 if (isset($tag['align'])) {
19199 switch ($tag['align']) {
19200 case 'C': {
19201 $opt['q'] = 1;
19202 break;
19203 }
19204 case 'R': {
19205 $opt['q'] = 2;
19206 break;
19207 }
19208 case 'L':
19209 default: {
19210 break;
19211 }
19212 }
19213 }
19214 switch ($tag['attribute']['type']) {
19215 case 'text': {
19216 if (isset($value)) {
19217 $opt['v'] = $value;
19218 }
19219 $this->TextField($name, $w, $h, $prop, $opt, '', '', false);
19220 break;
19221 }
19222 case 'password': {
19223 if (isset($value)) {
19224 $opt['v'] = $value;
19225 }
19226 $prop['password'] = 'true';
19227 $this->TextField($name, $w, $h, $prop, $opt, '', '', false);
19228 break;
19229 }
19230 case 'checkbox': {
19231 if (!isset($value)) {
19232 break;
19233 }
19234 $this->CheckBox($name, $w, $checked, $prop, $opt, $value, '', '', false);
19235 break;
19236 }
19237 case 'radio': {
19238 if (!isset($value)) {
19239 break;
19240 }
19241 $this->RadioButton($name, $w, $prop, $opt, $value, $checked, '', '', false);
19242 break;
19243 }
19244 case 'submit': {
19245 if (!isset($value)) {
19246 $value = 'submit';
19247 }
19248 $w = $this->GetStringWidth($value) * 1.5;
19249 $h *= 1.6;
19250 $prop = array('lineWidth'=>1, 'borderStyle'=>'beveled', 'fillColor'=>array(196, 196, 196), 'strokeColor'=>array(255, 255, 255));
19251 $action = array();
19252 $action['S'] = 'SubmitForm';
19253 $action['F'] = $this->form_action;
19254 if ($this->form_enctype != 'FDF') {
19255 $action['Flags'] = array('ExportFormat');
19256 }
19257 if ($this->form_mode == 'get') {
19258 $action['Flags'] = array('GetMethod');
19259 }
19260 $this->Button($name, $w, $h, $value, $action, $prop, $opt, '', '', false);
19261 break;
19262 }
19263 case 'reset': {
19264 if (!isset($value)) {
19265 $value = 'reset';
19266 }
19267 $w = $this->GetStringWidth($value) * 1.5;
19268 $h *= 1.6;
19269 $prop = array('lineWidth'=>1, 'borderStyle'=>'beveled', 'fillColor'=>array(196, 196, 196), 'strokeColor'=>array(255, 255, 255));
19270 $this->Button($name, $w, $h, $value, array('S'=>'ResetForm'), $prop, $opt, '', '', false);
19271 break;
19272 }
19273 case 'file': {
19274 $prop['fileSelect'] = 'true';
19275 $this->TextField($name, $w, $h, $prop, $opt, '', '', false);
19276 if (!isset($value)) {
19277 $value = '*';
19278 }
19279 $w = $this->GetStringWidth($value) * 2;
19280 $h *= 1.2;
19281 $prop = array('lineWidth'=>1, 'borderStyle'=>'beveled', 'fillColor'=>array(196, 196, 196), 'strokeColor'=>array(255, 255, 255));
19282 $jsaction = 'var f=this.getField(\''.$name.'\'); f.browseForFileToSubmit();';
19283 $this->Button('FB_'.$name, $w, $h, $value, $jsaction, $prop, $opt, '', '', false);
19284 break;
19285 }
19286 case 'hidden': {
19287 if (isset($value)) {
19288 $opt['v'] = $value;
19289 }
19290 $opt['f'] = array('invisible', 'hidden');
19291 $this->TextField($name, 0, 0, $prop, $opt, '', '', false);
19292 break;
19293 }
19294 case 'image': {
19295 // THIS TYPE MUST BE FIXED
19296 if (isset($tag['attribute']['src']) AND !TCPDF_STATIC::empty_string($tag['attribute']['src'])) {
19297 $img = $tag['attribute']['src'];
19298 } else {
19299 break;
19300 }
19301 $value = 'img';
19302 //$opt['mk'] = array('i'=>$img, 'tp'=>1, 'if'=>array('sw'=>'A', 's'=>'A', 'fb'=>false));
19303 if (isset($tag['attribute']['onclick']) AND !empty($tag['attribute']['onclick'])) {
19304 $jsaction = $tag['attribute']['onclick'];
19305 } else {
19306 $jsaction = '';
19307 }
19308 $this->Button($name, $w, $h, $value, $jsaction, $prop, $opt, '', '', false);
19309 break;
19310 }
19311 case 'button': {
19312 if (!isset($value)) {
19313 $value = ' ';
19314 }
19315 $w = $this->GetStringWidth($value) * 1.5;
19316 $h *= 1.6;
19317 $prop = array('lineWidth'=>1, 'borderStyle'=>'beveled', 'fillColor'=>array(196, 196, 196), 'strokeColor'=>array(255, 255, 255));
19318 if (isset($tag['attribute']['onclick']) AND !empty($tag['attribute']['onclick'])) {
19319 $jsaction = $tag['attribute']['onclick'];
19320 } else {
19321 $jsaction = '';
19322 }
19323 $this->Button($name, $w, $h, $value, $jsaction, $prop, $opt, '', '', false);
19324 break;
19325 }
19326 }
19327 break;
19328 }
19329 case 'textarea': {
19330 $prop = array();
19331 $opt = array();
19332 if (isset($tag['attribute']['readonly']) AND !TCPDF_STATIC::empty_string($tag['attribute']['readonly'])) {
19333 $prop['readonly'] = true;
19334 }
19335 if (isset($tag['attribute']['name']) AND !TCPDF_STATIC::empty_string($tag['attribute']['name'])) {
19336 $name = $tag['attribute']['name'];
19337 } else {
19338 break;
19339 }
19340 if (isset($tag['attribute']['value']) AND !TCPDF_STATIC::empty_string($tag['attribute']['value'])) {
19341 $opt['v'] = $tag['attribute']['value'];
19342 }
19343 if (isset($tag['attribute']['cols']) AND !TCPDF_STATIC::empty_string($tag['attribute']['cols'])) {
19344 $w = intval($tag['attribute']['cols']) * $this->GetStringWidth(chr(32)) * 2;
19345 } else {
19346 $w = 40;
19347 }
19348 if (isset($tag['attribute']['rows']) AND !TCPDF_STATIC::empty_string($tag['attribute']['rows'])) {
19349 $h = intval($tag['attribute']['rows']) * $this->getCellHeight($this->FontSize);
19350 } else {
19351 $h = 10;
19352 }
19353 $prop['multiline'] = 'true';
19354 $this->TextField($name, $w, $h, $prop, $opt, '', '', false);
19355 break;
19356 }
19357 case 'select': {
19358 $h = $this->getCellHeight($this->FontSize);
19359 if (isset($tag['attribute']['size']) AND !TCPDF_STATIC::empty_string($tag['attribute']['size'])) {
19360 $h *= ($tag['attribute']['size'] + 1);
19361 }
19362 $prop = array();
19363 $opt = array();
19364 if (isset($tag['attribute']['name']) AND !TCPDF_STATIC::empty_string($tag['attribute']['name'])) {
19365 $name = $tag['attribute']['name'];
19366 } else {
19367 break;
19368 }
19369 $w = 0;
19370 if (isset($tag['attribute']['opt']) AND !TCPDF_STATIC::empty_string($tag['attribute']['opt'])) {
19371 $options = explode('#!NwL!#', $tag['attribute']['opt']);
19372 $values = array();
19373 foreach ($options as $val) {
19374 if (strpos($val, '#!TaB!#') !== false) {
19375 $opts = explode('#!TaB!#', $val);
19376 $values[] = $opts;
19377 $w = max($w, $this->GetStringWidth($opts[1]));
19378 } else {
19379 $values[] = $val;
19380 $w = max($w, $this->GetStringWidth($val));
19381 }
19382 }
19383 } else {
19384 break;
19385 }
19386 $w *= 2;
19387 if (isset($tag['attribute']['multiple']) AND ($tag['attribute']['multiple']='multiple')) {
19388 $prop['multipleSelection'] = 'true';
19389 $this->ListBox($name, $w, $h, $values, $prop, $opt, '', '', false);
19390 } else {
19391 $this->ComboBox($name, $w, $h, $values, $prop, $opt, '', '', false);
19392 }
19393 break;
19394 }
19395 case 'tcpdf': {
19396 if (defined('K_TCPDF_CALLS_IN_HTML') AND (K_TCPDF_CALLS_IN_HTML === true)) {
19397 // Special tag used to call TCPDF methods
19398 if (isset($tag['attribute']['method'])) {
19399 $tcpdf_method = $tag['attribute']['method'];
19400 if (method_exists($this, $tcpdf_method)) {
19401 if (isset($tag['attribute']['params']) AND (!empty($tag['attribute']['params']))) {
19402 $params = TCPDF_STATIC::unserializeTCPDFtagParameters($tag['attribute']['params']);
19403 call_user_func_array(array($this, $tcpdf_method), $params);
19404 } else {
19405 $this->$tcpdf_method();
19406 }
19407 $this->newline = true;
19408 }
19409 }
19410 }
19411 break;
19412 }
19413 default: {
19414 break;
19415 }
19416 }
19417 // define tags that support borders and background colors
19418 $bordertags = array('blockquote','br','dd','dl','div','dt','h1','h2','h3','h4','h5','h6','hr','li','ol','p','pre','ul','tcpdf','table');
19419 if (in_array($tag['value'], $bordertags)) {
19420 // set border
19421 $dom[$key]['borderposition'] = $this->getBorderStartPosition();
19422 }
19423 if ($dom[$key]['self'] AND isset($dom[$key]['attribute']['pagebreakafter'])) {
19424 $pba = $dom[$key]['attribute']['pagebreakafter'];
19425 // check for pagebreak
19426 if (($pba == 'true') OR ($pba == 'left') OR ($pba == 'right')) {
19427 // add a page (or trig AcceptPageBreak() for multicolumn mode)
19428 $this->checkPageBreak($this->PageBreakTrigger + 1);
19429 }
19430 if ((($pba == 'left') AND (((!$this->rtl) AND (($this->page % 2) == 0)) OR (($this->rtl) AND (($this->page % 2) != 0))))
19431 OR (($pba == 'right') AND (((!$this->rtl) AND (($this->page % 2) != 0)) OR (($this->rtl) AND (($this->page % 2) == 0))))) {
19432 // add a page (or trig AcceptPageBreak() for multicolumn mode)
19433 $this->checkPageBreak($this->PageBreakTrigger + 1);
19434 }
19435 }
19436 return $dom;
19437 }
19438
19439 /**
19440 * Process closing tags.
19441 * @param $dom (array) html dom array
19442 * @param $key (int) current element id
19443 * @param $cell (boolean) if true add the default left (or right if RTL) padding to each new line (default false).
19444 * @param $maxbottomliney (int) maximum y value of current line
19445 * @return $dom array
19446 * @protected
19447 */
19448 protected function closeHTMLTagHandler($dom, $key, $cell, $maxbottomliney=0) {
19449 $tag = $dom[$key];
19450 $parent = $dom[($dom[$key]['parent'])];
19451 $lasttag = ((!isset($dom[($key + 1)])) OR ((!isset($dom[($key + 2)])) AND ($dom[($key + 1)]['value'] == 'marker')));
19452 $in_table_head = false;
19453 // maximum x position (used to draw borders)
19454 if ($this->rtl) {
19455 $xmax = $this->w;
19456 } else {
19457 $xmax = 0;
19458 }
19459 if ($tag['block']) {
19460 $hbz = 0; // distance from y to line bottom
19461 $hb = 0; // vertical space between block tags
19462 // calculate vertical space for block tags
19463 if (isset($this->tagvspaces[$tag['value']][1]['h']) AND ($this->tagvspaces[$tag['value']][1]['h'] >= 0)) {
19464 $pre_h = $this->tagvspaces[$tag['value']][1]['h'];
19465 } elseif (isset($parent['fontsize'])) {
19466 $pre_h = $this->getCellHeight($parent['fontsize'] / $this->k);
19467 } else {
19468 $pre_h = $this->getCellHeight($this->FontSize);
19469 }
19470 if (isset($this->tagvspaces[$tag['value']][1]['n'])) {
19471 $cn = $this->tagvspaces[$tag['value']][1]['n'];
19472 } elseif (preg_match('/[h][0-9]/', $tag['value']) > 0) {
19473 $cn = 0.6;
19474 } else {
19475 $cn = 1;
19476 }
19477 if ((!isset($this->tagvspaces[$tag['value']])) AND ($tag['value'] == 'div')) {
19478 $hb = 0;
19479 } else {
19480 $hb = ($cn * $pre_h);
19481 }
19482 if ($maxbottomliney > $this->PageBreakTrigger) {
19483 $hbz = $this->getCellHeight($this->FontSize);
19484 } elseif ($this->y < $maxbottomliney) {
19485 $hbz = ($maxbottomliney - $this->y);
19486 }
19487 }
19488 // Closing tag
19489 switch($tag['value']) {
19490 case 'tr': {
19491 $table_el = $dom[($dom[$key]['parent'])]['parent'];
19492 if (!isset($parent['endy'])) {
19493 $dom[($dom[$key]['parent'])]['endy'] = $this->y;
19494 $parent['endy'] = $this->y;
19495 }
19496 if (!isset($parent['endpage'])) {
19497 $dom[($dom[$key]['parent'])]['endpage'] = $this->page;
19498 $parent['endpage'] = $this->page;
19499 }
19500 if (!isset($parent['endcolumn'])) {
19501 $dom[($dom[$key]['parent'])]['endcolumn'] = $this->current_column;
19502 $parent['endcolumn'] = $this->current_column;
19503 }
19504 // update row-spanned cells
19505 if (isset($dom[$table_el]['rowspans'])) {
19506 foreach ($dom[$table_el]['rowspans'] as $k => $trwsp) {
19507 $dom[$table_el]['rowspans'][$k]['rowspan'] -= 1;
19508 if ($dom[$table_el]['rowspans'][$k]['rowspan'] == 0) {
19509 if (($dom[$table_el]['rowspans'][$k]['endpage'] == $parent['endpage']) AND ($dom[$table_el]['rowspans'][$k]['endcolumn'] == $parent['endcolumn'])) {
19510 $dom[($dom[$key]['parent'])]['endy'] = max($dom[$table_el]['rowspans'][$k]['endy'], $parent['endy']);
19511 } elseif (($dom[$table_el]['rowspans'][$k]['endpage'] > $parent['endpage']) OR ($dom[$table_el]['rowspans'][$k]['endcolumn'] > $parent['endcolumn'])) {
19512 $dom[($dom[$key]['parent'])]['endy'] = $dom[$table_el]['rowspans'][$k]['endy'];
19513 $dom[($dom[$key]['parent'])]['endpage'] = $dom[$table_el]['rowspans'][$k]['endpage'];
19514 $dom[($dom[$key]['parent'])]['endcolumn'] = $dom[$table_el]['rowspans'][$k]['endcolumn'];
19515 }
19516 }
19517 }
19518 // report new endy and endpage to the rowspanned cells
19519 foreach ($dom[$table_el]['rowspans'] as $k => $trwsp) {
19520 if ($dom[$table_el]['rowspans'][$k]['rowspan'] == 0) {
19521 $dom[$table_el]['rowspans'][$k]['endpage'] = max($dom[$table_el]['rowspans'][$k]['endpage'], $dom[($dom[$key]['parent'])]['endpage']);
19522 $dom[($dom[$key]['parent'])]['endpage'] = $dom[$table_el]['rowspans'][$k]['endpage'];
19523 $dom[$table_el]['rowspans'][$k]['endcolumn'] = max($dom[$table_el]['rowspans'][$k]['endcolumn'], $dom[($dom[$key]['parent'])]['endcolumn']);
19524 $dom[($dom[$key]['parent'])]['endcolumn'] = $dom[$table_el]['rowspans'][$k]['endcolumn'];
19525 $dom[$table_el]['rowspans'][$k]['endy'] = max($dom[$table_el]['rowspans'][$k]['endy'], $dom[($dom[$key]['parent'])]['endy']);
19526 $dom[($dom[$key]['parent'])]['endy'] = $dom[$table_el]['rowspans'][$k]['endy'];
19527 }
19528 }
19529 // update remaining rowspanned cells
19530 foreach ($dom[$table_el]['rowspans'] as $k => $trwsp) {
19531 if ($dom[$table_el]['rowspans'][$k]['rowspan'] == 0) {
19532 $dom[$table_el]['rowspans'][$k]['endpage'] = $dom[($dom[$key]['parent'])]['endpage'];
19533 $dom[$table_el]['rowspans'][$k]['endcolumn'] = $dom[($dom[$key]['parent'])]['endcolumn'];
19534 $dom[$table_el]['rowspans'][$k]['endy'] = $dom[($dom[$key]['parent'])]['endy'];
19535 }
19536 }
19537 }
19538 $prev_page = $this->page;
19539 $this->setPage($dom[($dom[$key]['parent'])]['endpage']);
19540 if ($this->num_columns > 1) {
19541 if ((($this->current_column == 0) AND ($dom[($dom[$key]['parent'])]['endcolumn'] == ($this->num_columns - 1)))
19542 OR (($this->current_column == $dom[($dom[$key]['parent'])]['endcolumn']) AND ($prev_page < $this->page))) {
19543 // page jump
19544 $this->selectColumn(0);
19545 $dom[($dom[$key]['parent'])]['endcolumn'] = 0;
19546 $dom[($dom[$key]['parent'])]['endy'] = $this->y;
19547 } else {
19548 $this->selectColumn($dom[($dom[$key]['parent'])]['endcolumn']);
19549 $this->y = $dom[($dom[$key]['parent'])]['endy'];
19550 }
19551 } else {
19552 $this->y = $dom[($dom[$key]['parent'])]['endy'];
19553 }
19554 if (isset($dom[$table_el]['attribute']['cellspacing'])) {
19555 $this->y += $this->getHTMLUnitToUnits($dom[$table_el]['attribute']['cellspacing'], 1, 'px');
19556 } elseif (isset($dom[$table_el]['border-spacing'])) {
19557 $this->y += $dom[$table_el]['border-spacing']['V'];
19558 }
19559 $this->Ln(0, $cell);
19560 if ($this->current_column == $parent['startcolumn']) {
19561 $this->x = $parent['startx'];
19562 }
19563 // account for booklet mode
19564 if ($this->page > $parent['startpage']) {
19565 if (($this->rtl) AND ($this->pagedim[$this->page]['orm'] != $this->pagedim[$parent['startpage']]['orm'])) {
19566 $this->x -= ($this->pagedim[$this->page]['orm'] - $this->pagedim[$parent['startpage']]['orm']);
19567 } elseif ((!$this->rtl) AND ($this->pagedim[$this->page]['olm'] != $this->pagedim[$parent['startpage']]['olm'])) {
19568 $this->x += ($this->pagedim[$this->page]['olm'] - $this->pagedim[$parent['startpage']]['olm']);
19569 }
19570 }
19571 break;
19572 }
19573 case 'tablehead':
19574 // closing tag used for the thead part
19575 $in_table_head = true;
19576 $this->inthead = false;
19577 case 'table': {
19578 $table_el = $parent;
19579 // set default border
19580 if (isset($table_el['attribute']['border']) AND ($table_el['attribute']['border'] > 0)) {
19581 // set default border
19582 $border = array('LTRB' => array('width' => $this->getCSSBorderWidth($table_el['attribute']['border']), 'cap'=>'square', 'join'=>'miter', 'dash'=> 0, 'color'=>array(0,0,0)));
19583 } else {
19584 $border = 0;
19585 }
19586 $default_border = $border;
19587 // fix bottom line alignment of last line before page break
19588 foreach ($dom[($dom[$key]['parent'])]['trids'] as $j => $trkey) {
19589 // update row-spanned cells
19590 if (isset($dom[($dom[$key]['parent'])]['rowspans'])) {
19591 foreach ($dom[($dom[$key]['parent'])]['rowspans'] as $k => $trwsp) {
19592 if (isset($prevtrkey) AND ($trwsp['trid'] == $prevtrkey) AND ($trwsp['mrowspan'] > 0)) {
19593 $dom[($dom[$key]['parent'])]['rowspans'][$k]['trid'] = $trkey;
19594 }
19595 if ($dom[($dom[$key]['parent'])]['rowspans'][$k]['trid'] == $trkey) {
19596 $dom[($dom[$key]['parent'])]['rowspans'][$k]['mrowspan'] -= 1;
19597 }
19598 }
19599 }
19600 if (isset($prevtrkey) AND ($dom[$trkey]['startpage'] > $dom[$prevtrkey]['endpage'])) {
19601 $pgendy = $this->pagedim[$dom[$prevtrkey]['endpage']]['hk'] - $this->pagedim[$dom[$prevtrkey]['endpage']]['bm'];
19602 $dom[$prevtrkey]['endy'] = $pgendy;
19603 // update row-spanned cells
19604 if (isset($dom[($dom[$key]['parent'])]['rowspans'])) {
19605 foreach ($dom[($dom[$key]['parent'])]['rowspans'] as $k => $trwsp) {
19606 if (($trwsp['trid'] == $prevtrkey) AND ($trwsp['mrowspan'] >= 0) AND ($trwsp['endpage'] == $dom[$prevtrkey]['endpage'])) {
19607 $dom[($dom[$key]['parent'])]['rowspans'][$k]['endy'] = $pgendy;
19608 $dom[($dom[$key]['parent'])]['rowspans'][$k]['mrowspan'] = -1;
19609 }
19610 }
19611 }
19612 }
19613 $prevtrkey = $trkey;
19614 $table_el = $dom[($dom[$key]['parent'])];
19615 }
19616 // for each row
19617 if (count($table_el['trids']) > 0) {
19618 unset($xmax);
19619 }
19620 foreach ($table_el['trids'] as $j => $trkey) {
19621 $parent = $dom[$trkey];
19622 if (!isset($xmax)) {
19623 $xmax = $parent['cellpos'][(count($parent['cellpos']) - 1)]['endx'];
19624 }
19625 // for each cell on the row
19626 foreach ($parent['cellpos'] as $k => $cellpos) {
19627 if (isset($cellpos['rowspanid']) AND ($cellpos['rowspanid'] >= 0)) {
19628 $cellpos['startx'] = $table_el['rowspans'][($cellpos['rowspanid'])]['startx'];
19629 $cellpos['endx'] = $table_el['rowspans'][($cellpos['rowspanid'])]['endx'];
19630 $endy = $table_el['rowspans'][($cellpos['rowspanid'])]['endy'];
19631 $startpage = $table_el['rowspans'][($cellpos['rowspanid'])]['startpage'];
19632 $endpage = $table_el['rowspans'][($cellpos['rowspanid'])]['endpage'];
19633 $startcolumn = $table_el['rowspans'][($cellpos['rowspanid'])]['startcolumn'];
19634 $endcolumn = $table_el['rowspans'][($cellpos['rowspanid'])]['endcolumn'];
19635 } else {
19636 $endy = $parent['endy'];
19637 $startpage = $parent['startpage'];
19638 $endpage = $parent['endpage'];
19639 $startcolumn = $parent['startcolumn'];
19640 $endcolumn = $parent['endcolumn'];
19641 }
19642 if ($this->num_columns == 0) {
19643 $this->num_columns = 1;
19644 }
19645 if (isset($cellpos['border'])) {
19646 $border = $cellpos['border'];
19647 }
19648 if (isset($cellpos['bgcolor']) AND ($cellpos['bgcolor']) !== false) {
19649 $this->SetFillColorArray($cellpos['bgcolor']);
19650 $fill = true;
19651 } else {
19652 $fill = false;
19653 }
19654 $x = $cellpos['startx'];
19655 $y = $parent['starty'];
19656 $starty = $y;
19657 $w = abs($cellpos['endx'] - $cellpos['startx']);
19658 // get border modes
19659 $border_start = TCPDF_STATIC::getBorderMode($border, $position='start', $this->opencell);
19660 $border_end = TCPDF_STATIC::getBorderMode($border, $position='end', $this->opencell);
19661 $border_middle = TCPDF_STATIC::getBorderMode($border, $position='middle', $this->opencell);
19662 // design borders around HTML cells.
19663 for ($page = $startpage; $page <= $endpage; ++$page) { // for each page
19664 $ccode = '';
19665 $this->setPage($page);
19666 if ($this->num_columns < 2) {
19667 // single-column mode
19668 $this->x = $x;
19669 $this->y = $this->tMargin;
19670 }
19671 // account for margin changes
19672 if ($page > $startpage) {
19673 if (($this->rtl) AND ($this->pagedim[$page]['orm'] != $this->pagedim[$startpage]['orm'])) {
19674 $this->x -= ($this->pagedim[$page]['orm'] - $this->pagedim[$startpage]['orm']);
19675 } elseif ((!$this->rtl) AND ($this->pagedim[$page]['olm'] != $this->pagedim[$startpage]['olm'])) {
19676 $this->x += ($this->pagedim[$page]['olm'] - $this->pagedim[$startpage]['olm']);
19677 }
19678 }
19679 if ($startpage == $endpage) { // single page
19680 $deltacol = 0;
19681 $deltath = 0;
19682 for ($column = $startcolumn; $column <= $endcolumn; ++$column) { // for each column
19683 $this->selectColumn($column);
19684 if ($startcolumn == $endcolumn) { // single column
19685 $cborder = $border;
19686 $h = $endy - $parent['starty'];
19687 $this->y = $y;
19688 $this->x = $x;
19689 } elseif ($column == $startcolumn) { // first column
19690 $cborder = $border_start;
19691 $this->y = $starty;
19692 $this->x = $x;
19693 $h = $this->h - $this->y - $this->bMargin;
19694 if ($this->rtl) {
19695 $deltacol = $this->x + $this->rMargin - $this->w;
19696 } else {
19697 $deltacol = $this->x - $this->lMargin;
19698 }
19699 } elseif ($column == $endcolumn) { // end column
19700 $cborder = $border_end;
19701 if (isset($this->columns[$column]['th']['\''.$page.'\''])) {
19702 $this->y = $this->columns[$column]['th']['\''.$page.'\''];
19703 }
19704 $this->x += $deltacol;
19705 $h = $endy - $this->y;
19706 } else { // middle column
19707 $cborder = $border_middle;
19708 if (isset($this->columns[$column]['th']['\''.$page.'\''])) {
19709 $this->y = $this->columns[$column]['th']['\''.$page.'\''];
19710 }
19711 $this->x += $deltacol;
19712 $h = $this->h - $this->y - $this->bMargin;
19713 }
19714 $ccode .= $this->getCellCode($w, $h, '', $cborder, 1, '', $fill, '', 0, true)."\n";
19715 } // end for each column
19716 } elseif ($page == $startpage) { // first page
19717 $deltacol = 0;
19718 $deltath = 0;
19719 for ($column = $startcolumn; $column < $this->num_columns; ++$column) { // for each column
19720 $this->selectColumn($column);
19721 if ($column == $startcolumn) { // first column
19722 $cborder = $border_start;
19723 $this->y = $starty;
19724 $this->x = $x;
19725 $h = $this->h - $this->y - $this->bMargin;
19726 if ($this->rtl) {
19727 $deltacol = $this->x + $this->rMargin - $this->w;
19728 } else {
19729 $deltacol = $this->x - $this->lMargin;
19730 }
19731 } else { // middle column
19732 $cborder = $border_middle;
19733 if (isset($this->columns[$column]['th']['\''.$page.'\''])) {
19734 $this->y = $this->columns[$column]['th']['\''.$page.'\''];
19735 }
19736 $this->x += $deltacol;
19737 $h = $this->h - $this->y - $this->bMargin;
19738 }
19739 $ccode .= $this->getCellCode($w, $h, '', $cborder, 1, '', $fill, '', 0, true)."\n";
19740 } // end for each column
19741 } elseif ($page == $endpage) { // last page
19742 $deltacol = 0;
19743 $deltath = 0;
19744 for ($column = 0; $column <= $endcolumn; ++$column) { // for each column
19745 $this->selectColumn($column);
19746 if ($column == $endcolumn) { // end column
19747 $cborder = $border_end;
19748 if (isset($this->columns[$column]['th']['\''.$page.'\''])) {
19749 $this->y = $this->columns[$column]['th']['\''.$page.'\''];
19750 }
19751 $this->x += $deltacol;
19752 $h = $endy - $this->y;
19753 } else { // middle column
19754 $cborder = $border_middle;
19755 if (isset($this->columns[$column]['th']['\''.$page.'\''])) {
19756 $this->y = $this->columns[$column]['th']['\''.$page.'\''];
19757 }
19758 $this->x += $deltacol;
19759 $h = $this->h - $this->y - $this->bMargin;
19760 }
19761 $ccode .= $this->getCellCode($w, $h, '', $cborder, 1, '', $fill, '', 0, true)."\n";
19762 } // end for each column
19763 } else { // middle page
19764 $deltacol = 0;
19765 $deltath = 0;
19766 for ($column = 0; $column < $this->num_columns; ++$column) { // for each column
19767 $this->selectColumn($column);
19768 $cborder = $border_middle;
19769 if (isset($this->columns[$column]['th']['\''.$page.'\''])) {
19770 $this->y = $this->columns[$column]['th']['\''.$page.'\''];
19771 }
19772 $this->x += $deltacol;
19773 $h = $this->h - $this->y - $this->bMargin;
19774 $ccode .= $this->getCellCode($w, $h, '', $cborder, 1, '', $fill, '', 0, true)."\n";
19775 } // end for each column
19776 }
19777 if ($cborder OR $fill) {
19778 $offsetlen = strlen($ccode);
19779 // draw border and fill
19780 if ($this->inxobj) {
19781 // we are inside an XObject template
19782 if (end($this->xobjects[$this->xobjid]['transfmrk']) !== false) {
19783 $pagemarkkey = key($this->xobjects[$this->xobjid]['transfmrk']);
19784 $pagemark = $this->xobjects[$this->xobjid]['transfmrk'][$pagemarkkey];
19785 $this->xobjects[$this->xobjid]['transfmrk'][$pagemarkkey] += $offsetlen;
19786 } else {
19787 $pagemark = $this->xobjects[$this->xobjid]['intmrk'];
19788 $this->xobjects[$this->xobjid]['intmrk'] += $offsetlen;
19789 }
19790 $pagebuff = $this->xobjects[$this->xobjid]['outdata'];
19791 $pstart = substr($pagebuff, 0, $pagemark);
19792 $pend = substr($pagebuff, $pagemark);
19793 $this->xobjects[$this->xobjid]['outdata'] = $pstart.$ccode.$pend;
19794 } else {
19795 // draw border and fill
19796 if (end($this->transfmrk[$this->page]) !== false) {
19797 $pagemarkkey = key($this->transfmrk[$this->page]);
19798 $pagemark = $this->transfmrk[$this->page][$pagemarkkey];
19799 } elseif ($this->InFooter) {
19800 $pagemark = $this->footerpos[$this->page];
19801 } else {
19802 $pagemark = $this->intmrk[$this->page];
19803 }
19804 $pagebuff = $this->getPageBuffer($this->page);
19805 $pstart = substr($pagebuff, 0, $pagemark);
19806 $pend = substr($pagebuff, $pagemark);
19807 $this->setPageBuffer($this->page, $pstart.$ccode.$pend);
19808 }
19809 }
19810 } // end for each page
19811 // restore default border
19812 $border = $default_border;
19813 } // end for each cell on the row
19814 if (isset($table_el['attribute']['cellspacing'])) {
19815 $this->y += $this->getHTMLUnitToUnits($table_el['attribute']['cellspacing'], 1, 'px');
19816 } elseif (isset($table_el['border-spacing'])) {
19817 $this->y += $table_el['border-spacing']['V'];
19818 }
19819 $this->Ln(0, $cell);
19820 $this->x = $parent['startx'];
19821 if ($endpage > $startpage) {
19822 if (($this->rtl) AND ($this->pagedim[$endpage]['orm'] != $this->pagedim[$startpage]['orm'])) {
19823 $this->x += ($this->pagedim[$endpage]['orm'] - $this->pagedim[$startpage]['orm']);
19824 } elseif ((!$this->rtl) AND ($this->pagedim[$endpage]['olm'] != $this->pagedim[$startpage]['olm'])) {
19825 $this->x += ($this->pagedim[$endpage]['olm'] - $this->pagedim[$startpage]['olm']);
19826 }
19827 }
19828 }
19829 if (!$in_table_head) { // we are not inside a thead section
19830 $this->cell_padding = $table_el['old_cell_padding'];
19831 // reset row height
19832 $this->resetLastH();
19833 if (($this->page == ($this->numpages - 1)) AND ($this->pageopen[$this->numpages])) {
19834 $plendiff = ($this->pagelen[$this->numpages] - $this->emptypagemrk[$this->numpages]);
19835 if (($plendiff > 0) AND ($plendiff < 60)) {
19836 $pagediff = substr($this->getPageBuffer($this->numpages), $this->emptypagemrk[$this->numpages], $plendiff);
19837 if (substr($pagediff, 0, 5) == 'BT /F') {
19838 // the difference is only a font setting
19839 $plendiff = 0;
19840 }
19841 }
19842 if ($plendiff == 0) {
19843 // remove last blank page
19844 $this->deletePage($this->numpages);
19845 }
19846 }
19847 if (isset($this->theadMargins['top'])) {
19848 // restore top margin
19849 $this->tMargin = $this->theadMargins['top'];
19850 }
19851 if (!isset($table_el['attribute']['nested']) OR ($table_el['attribute']['nested'] != 'true')) {
19852 // reset main table header
19853 $this->thead = '';
19854 $this->theadMargins = array();
19855 $this->pagedim[$this->page]['tm'] = $this->tMargin;
19856 }
19857 }
19858 $parent = $table_el;
19859 break;
19860 }
19861 case 'a': {
19862 $this->HREF = '';
19863 break;
19864 }
19865 case 'sup': {
19866 $this->SetXY($this->GetX(), $this->GetY() + ((0.7 * $parent['fontsize']) / $this->k));
19867 break;
19868 }
19869 case 'sub': {
19870 $this->SetXY($this->GetX(), $this->GetY() - ((0.3 * $parent['fontsize']) / $this->k));
19871 break;
19872 }
19873 case 'div': {
19874 $this->addHTMLVertSpace($hbz, $hb, $cell, false, $lasttag);
19875 break;
19876 }
19877 case 'blockquote': {
19878 if ($this->rtl) {
19879 $this->rMargin -= $this->listindent;
19880 } else {
19881 $this->lMargin -= $this->listindent;
19882 }
19883 --$this->listindentlevel;
19884 $this->addHTMLVertSpace($hbz, $hb, $cell, false, $lasttag);
19885 break;
19886 }
19887 case 'p': {
19888 $this->addHTMLVertSpace($hbz, $hb, $cell, false, $lasttag);
19889 break;
19890 }
19891 case 'pre': {
19892 $this->addHTMLVertSpace($hbz, $hb, $cell, false, $lasttag);
19893 $this->premode = false;
19894 break;
19895 }
19896 case 'dl': {
19897 --$this->listnum;
19898 if ($this->listnum <= 0) {
19899 $this->listnum = 0;
19900 $this->addHTMLVertSpace($hbz, $hb, $cell, false, $lasttag);
19901 } else {
19902 $this->addHTMLVertSpace(0, 0, $cell, false, $lasttag);
19903 }
19904 $this->resetLastH();
19905 break;
19906 }
19907 case 'dt': {
19908 $this->lispacer = '';
19909 $this->addHTMLVertSpace(0, 0, $cell, false, $lasttag);
19910 break;
19911 }
19912 case 'dd': {
19913 $this->lispacer = '';
19914 if ($this->rtl) {
19915 $this->rMargin -= $this->listindent;
19916 } else {
19917 $this->lMargin -= $this->listindent;
19918 }
19919 --$this->listindentlevel;
19920 $this->addHTMLVertSpace(0, 0, $cell, false, $lasttag);
19921 break;
19922 }
19923 case 'ul':
19924 case 'ol': {
19925 --$this->listnum;
19926 $this->lispacer = '';
19927 if ($this->rtl) {
19928 $this->rMargin -= $this->listindent;
19929 } else {
19930 $this->lMargin -= $this->listindent;
19931 }
19932 --$this->listindentlevel;
19933 if ($this->listnum <= 0) {
19934 $this->listnum = 0;
19935 $this->addHTMLVertSpace($hbz, $hb, $cell, false, $lasttag);
19936 } else {
19937 $this->addHTMLVertSpace(0, 0, $cell, false, $lasttag);
19938 }
19939 $this->resetLastH();
19940 break;
19941 }
19942 case 'li': {
19943 $this->lispacer = '';
19944 $this->addHTMLVertSpace(0, 0, $cell, false, $lasttag);
19945 break;
19946 }
19947 case 'h1':
19948 case 'h2':
19949 case 'h3':
19950 case 'h4':
19951 case 'h5':
19952 case 'h6': {
19953 $this->addHTMLVertSpace($hbz, $hb, $cell, false, $lasttag);
19954 break;
19955 }
19956 // Form fields (since 4.8.000 - 2009-09-07)
19957 case 'form': {
19958 $this->form_action = '';
19959 $this->form_enctype = 'application/x-www-form-urlencoded';
19960 break;
19961 }
19962 default : {
19963 break;
19964 }
19965 }
19966 // draw border and background (if any)
19967 $this->drawHTMLTagBorder($parent, $xmax);
19968 if (isset($dom[($dom[$key]['parent'])]['attribute']['pagebreakafter'])) {
19969 $pba = $dom[($dom[$key]['parent'])]['attribute']['pagebreakafter'];
19970 // check for pagebreak
19971 if (($pba == 'true') OR ($pba == 'left') OR ($pba == 'right')) {
19972 // add a page (or trig AcceptPageBreak() for multicolumn mode)
19973 $this->checkPageBreak($this->PageBreakTrigger + 1);
19974 }
19975 if ((($pba == 'left') AND (((!$this->rtl) AND (($this->page % 2) == 0)) OR (($this->rtl) AND (($this->page % 2) != 0))))
19976 OR (($pba == 'right') AND (((!$this->rtl) AND (($this->page % 2) != 0)) OR (($this->rtl) AND (($this->page % 2) == 0))))) {
19977 // add a page (or trig AcceptPageBreak() for multicolumn mode)
19978 $this->checkPageBreak($this->PageBreakTrigger + 1);
19979 }
19980 }
19981 $this->tmprtl = false;
19982 return $dom;
19983 }
19984
19985 /**
19986 * Add vertical spaces if needed.
19987 * @param $hbz (string) Distance between current y and line bottom.
19988 * @param $hb (string) The height of the break.
19989 * @param $cell (boolean) if true add the default left (or right if RTL) padding to each new line (default false).
19990 * @param $firsttag (boolean) set to true when the tag is the first.
19991 * @param $lasttag (boolean) set to true when the tag is the last.
19992 * @protected
19993 */
19994 protected function addHTMLVertSpace($hbz=0, $hb=0, $cell=false, $firsttag=false, $lasttag=false) {
19995 if ($firsttag) {
19996 $this->Ln(0, $cell);
19997 $this->htmlvspace = 0;
19998 return;
19999 }
20000 if ($lasttag) {
20001 $this->Ln($hbz, $cell);
20002 $this->htmlvspace = 0;
20003 return;
20004 }
20005 if ($hb < $this->htmlvspace) {
20006 $hd = 0;
20007 } else {
20008 $hd = $hb - $this->htmlvspace;
20009 $this->htmlvspace = $hb;
20010 }
20011 $this->Ln(($hbz + $hd), $cell);
20012 }
20013
20014 /**
20015 * Return the starting coordinates to draw an html border
20016 * @return array containing top-left border coordinates
20017 * @protected
20018 * @since 5.7.000 (2010-08-03)
20019 */
20020 protected function getBorderStartPosition() {
20021 if ($this->rtl) {
20022 $xmax = $this->lMargin;
20023 } else {
20024 $xmax = $this->w - $this->rMargin;
20025 }
20026 return array('page' => $this->page, 'column' => $this->current_column, 'x' => $this->x, 'y' => $this->y, 'xmax' => $xmax);
20027 }
20028
20029 /**
20030 * Draw an HTML block border and fill
20031 * @param $tag (array) array of tag properties.
20032 * @param $xmax (int) end X coordinate for border.
20033 * @protected
20034 * @since 5.7.000 (2010-08-03)
20035 */
20036 protected function drawHTMLTagBorder($tag, $xmax) {
20037 if (!isset($tag['borderposition'])) {
20038 // nothing to draw
20039 return;
20040 }
20041 $prev_x = $this->x;
20042 $prev_y = $this->y;
20043 $prev_lasth = $this->lasth;
20044 $border = 0;
20045 $fill = false;
20046 $this->lasth = 0;
20047 if (isset($tag['border']) AND !empty($tag['border'])) {
20048 // get border style
20049 $border = $tag['border'];
20050 if (!TCPDF_STATIC::empty_string($this->thead) AND (!$this->inthead)) {
20051 // border for table header
20052 $border = TCPDF_STATIC::getBorderMode($border, $position='middle', $this->opencell);
20053 }
20054 }
20055 if (isset($tag['bgcolor']) AND ($tag['bgcolor'] !== false)) {
20056 // get background color
20057 $old_bgcolor = $this->bgcolor;
20058 $this->SetFillColorArray($tag['bgcolor']);
20059 $fill = true;
20060 }
20061 if (!$border AND !$fill) {
20062 // nothing to draw
20063 return;
20064 }
20065 if (isset($tag['attribute']['cellspacing'])) {
20066 $clsp = $this->getHTMLUnitToUnits($tag['attribute']['cellspacing'], 1, 'px');
20067 $cellspacing = array('H' => $clsp, 'V' => $clsp);
20068 } elseif (isset($tag['border-spacing'])) {
20069 $cellspacing = $tag['border-spacing'];
20070 } else {
20071 $cellspacing = array('H' => 0, 'V' => 0);
20072 }
20073 if (($tag['value'] != 'table') AND (is_array($border)) AND (!empty($border))) {
20074 // draw the border externally respect the sqare edge.
20075 $border['mode'] = 'ext';
20076 }
20077 if ($this->rtl) {
20078 if ($xmax >= $tag['borderposition']['x']) {
20079 $xmax = $tag['borderposition']['xmax'];
20080 }
20081 $w = ($tag['borderposition']['x'] - $xmax);
20082 } else {
20083 if ($xmax <= $tag['borderposition']['x']) {
20084 $xmax = $tag['borderposition']['xmax'];
20085 }
20086 $w = ($xmax - $tag['borderposition']['x']);
20087 }
20088 if ($w <= 0) {
20089 return;
20090 }
20091 $w += $cellspacing['H'];
20092 $startpage = $tag['borderposition']['page'];
20093 $startcolumn = $tag['borderposition']['column'];
20094 $x = $tag['borderposition']['x'];
20095 $y = $tag['borderposition']['y'];
20096 $endpage = $this->page;
20097 $starty = $tag['borderposition']['y'] - $cellspacing['V'];
20098 $currentY = $this->y;
20099 $this->x = $x;
20100 // get latest column
20101 $endcolumn = $this->current_column;
20102 if ($this->num_columns == 0) {
20103 $this->num_columns = 1;
20104 }
20105 // get border modes
20106 $border_start = TCPDF_STATIC::getBorderMode($border, $position='start', $this->opencell);
20107 $border_end = TCPDF_STATIC::getBorderMode($border, $position='end', $this->opencell);
20108 $border_middle = TCPDF_STATIC::getBorderMode($border, $position='middle', $this->opencell);
20109 // temporary disable page regions
20110 $temp_page_regions = $this->page_regions;
20111 $this->page_regions = array();
20112 // design borders around HTML cells.
20113 for ($page = $startpage; $page <= $endpage; ++$page) { // for each page
20114 $ccode = '';
20115 $this->setPage($page);
20116 if ($this->num_columns < 2) {
20117 // single-column mode
20118 $this->x = $x;
20119 $this->y = $this->tMargin;
20120 }
20121 // account for margin changes
20122 if ($page > $startpage) {
20123 if (($this->rtl) AND ($this->pagedim[$page]['orm'] != $this->pagedim[$startpage]['orm'])) {
20124 $this->x -= ($this->pagedim[$page]['orm'] - $this->pagedim[$startpage]['orm']);
20125 } elseif ((!$this->rtl) AND ($this->pagedim[$page]['olm'] != $this->pagedim[$startpage]['olm'])) {
20126 $this->x += ($this->pagedim[$page]['olm'] - $this->pagedim[$startpage]['olm']);
20127 }
20128 }
20129 if ($startpage == $endpage) {
20130 // single page
20131 for ($column = $startcolumn; $column <= $endcolumn; ++$column) { // for each column
20132 $this->selectColumn($column);
20133 if ($startcolumn == $endcolumn) { // single column
20134 $cborder = $border;
20135 $h = ($currentY - $y) + $cellspacing['V'];
20136 $this->y = $starty;
20137 } elseif ($column == $startcolumn) { // first column
20138 $cborder = $border_start;
20139 $this->y = $starty;
20140 $h = $this->h - $this->y - $this->bMargin;
20141 } elseif ($column == $endcolumn) { // end column
20142 $cborder = $border_end;
20143 $h = $currentY - $this->y;
20144 } else { // middle column
20145 $cborder = $border_middle;
20146 $h = $this->h - $this->y - $this->bMargin;
20147 }
20148 $ccode .= $this->getCellCode($w, $h, '', $cborder, 1, '', $fill, '', 0, true)."\n";
20149 } // end for each column
20150 } elseif ($page == $startpage) { // first page
20151 for ($column = $startcolumn; $column < $this->num_columns; ++$column) { // for each column
20152 $this->selectColumn($column);
20153 if ($column == $startcolumn) { // first column
20154 $cborder = $border_start;
20155 $this->y = $starty;
20156 $h = $this->h - $this->y - $this->bMargin;
20157 } else { // middle column
20158 $cborder = $border_middle;
20159 $h = $this->h - $this->y - $this->bMargin;
20160 }
20161 $ccode .= $this->getCellCode($w, $h, '', $cborder, 1, '', $fill, '', 0, true)."\n";
20162 } // end for each column
20163 } elseif ($page == $endpage) { // last page
20164 for ($column = 0; $column <= $endcolumn; ++$column) { // for each column
20165 $this->selectColumn($column);
20166 if ($column == $endcolumn) {
20167 // end column
20168 $cborder = $border_end;
20169 $h = $currentY - $this->y;
20170 } else {
20171 // middle column
20172 $cborder = $border_middle;
20173 $h = $this->h - $this->y - $this->bMargin;
20174 }
20175 $ccode .= $this->getCellCode($w, $h, '', $cborder, 1, '', $fill, '', 0, true)."\n";
20176 } // end for each column
20177 } else { // middle page
20178 for ($column = 0; $column < $this->num_columns; ++$column) { // for each column
20179 $this->selectColumn($column);
20180 $cborder = $border_middle;
20181 $h = $this->h - $this->y - $this->bMargin;
20182 $ccode .= $this->getCellCode($w, $h, '', $cborder, 1, '', $fill, '', 0, true)."\n";
20183 } // end for each column
20184 }
20185 if ($cborder OR $fill) {
20186 $offsetlen = strlen($ccode);
20187 // draw border and fill
20188 if ($this->inxobj) {
20189 // we are inside an XObject template
20190 if (end($this->xobjects[$this->xobjid]['transfmrk']) !== false) {
20191 $pagemarkkey = key($this->xobjects[$this->xobjid]['transfmrk']);
20192 $pagemark = $this->xobjects[$this->xobjid]['transfmrk'][$pagemarkkey];
20193 $this->xobjects[$this->xobjid]['transfmrk'][$pagemarkkey] += $offsetlen;
20194 } else {
20195 $pagemark = $this->xobjects[$this->xobjid]['intmrk'];
20196 $this->xobjects[$this->xobjid]['intmrk'] += $offsetlen;
20197 }
20198 $pagebuff = $this->xobjects[$this->xobjid]['outdata'];
20199 $pstart = substr($pagebuff, 0, $pagemark);
20200 $pend = substr($pagebuff, $pagemark);
20201 $this->xobjects[$this->xobjid]['outdata'] = $pstart.$ccode.$pend;
20202 } else {
20203 if (end($this->transfmrk[$this->page]) !== false) {
20204 $pagemarkkey = key($this->transfmrk[$this->page]);
20205 $pagemark = $this->transfmrk[$this->page][$pagemarkkey];
20206 } elseif ($this->InFooter) {
20207 $pagemark = $this->footerpos[$this->page];
20208 } else {
20209 $pagemark = $this->intmrk[$this->page];
20210 }
20211 $pagebuff = $this->getPageBuffer($this->page);
20212 $pstart = substr($pagebuff, 0, $pagemark);
20213 $pend = substr($pagebuff, $pagemark);
20214 $this->setPageBuffer($this->page, $pstart.$ccode.$pend);
20215 $this->bordermrk[$this->page] += $offsetlen;
20216 $this->cntmrk[$this->page] += $offsetlen;
20217 }
20218 }
20219 } // end for each page
20220 // restore page regions
20221 $this->page_regions = $temp_page_regions;
20222 if (isset($old_bgcolor)) {
20223 // restore background color
20224 $this->SetFillColorArray($old_bgcolor);
20225 }
20226 // restore pointer position
20227 $this->x = $prev_x;
20228 $this->y = $prev_y;
20229 $this->lasth = $prev_lasth;
20230 }
20231
20232 /**
20233 * Set the default bullet to be used as LI bullet symbol
20234 * @param $symbol (string) character or string to be used (legal values are: '' = automatic, '!' = auto bullet, '#' = auto numbering, 'disc', 'disc', 'circle', 'square', '1', 'decimal', 'decimal-leading-zero', 'i', 'lower-roman', 'I', 'upper-roman', 'a', 'lower-alpha', 'lower-latin', 'A', 'upper-alpha', 'upper-latin', 'lower-greek', 'img|type|width|height|image.ext')
20235 * @public
20236 * @since 4.0.028 (2008-09-26)
20237 */
20238 public function setLIsymbol($symbol='!') {
20239 // check for custom image symbol
20240 if (substr($symbol, 0, 4) == 'img|') {
20241 $this->lisymbol = $symbol;
20242 return;
20243 }
20244 $symbol = strtolower($symbol);
20245 $valid_symbols = array('!', '#', 'disc', 'circle', 'square', '1', 'decimal', 'decimal-leading-zero', 'i', 'lower-roman', 'I', 'upper-roman', 'a', 'lower-alpha', 'lower-latin', 'A', 'upper-alpha', 'upper-latin', 'lower-greek');
20246 if (in_array($symbol, $valid_symbols)) {
20247 $this->lisymbol = $symbol;
20248 } else {
20249 $this->lisymbol = '';
20250 }
20251 }
20252
20253 /**
20254 * Set the booklet mode for double-sided pages.
20255 * @param $booklet (boolean) true set the booklet mode on, false otherwise.
20256 * @param $inner (float) Inner page margin.
20257 * @param $outer (float) Outer page margin.
20258 * @public
20259 * @since 4.2.000 (2008-10-29)
20260 */
20261 public function SetBooklet($booklet=true, $inner=-1, $outer=-1) {
20262 $this->booklet = $booklet;
20263 if ($inner >= 0) {
20264 $this->lMargin = $inner;
20265 }
20266 if ($outer >= 0) {
20267 $this->rMargin = $outer;
20268 }
20269 }
20270
20271 /**
20272 * Swap the left and right margins.
20273 * @param $reverse (boolean) if true swap left and right margins.
20274 * @protected
20275 * @since 4.2.000 (2008-10-29)
20276 */
20277 protected function swapMargins($reverse=true) {
20278 if ($reverse) {
20279 // swap left and right margins
20280 $mtemp = $this->original_lMargin;
20281 $this->original_lMargin = $this->original_rMargin;
20282 $this->original_rMargin = $mtemp;
20283 $deltam = $this->original_lMargin - $this->original_rMargin;
20284 $this->lMargin += $deltam;
20285 $this->rMargin -= $deltam;
20286 }
20287 }
20288
20289 /**
20290 * Set the vertical spaces for HTML tags.
20291 * The array must have the following structure (example):
20292 * $tagvs = array('h1' => array(0 => array('h' => '', 'n' => 2), 1 => array('h' => 1.3, 'n' => 1)));
20293 * The first array level contains the tag names,
20294 * the second level contains 0 for opening tags or 1 for closing tags,
20295 * the third level contains the vertical space unit (h) and the number spaces to add (n).
20296 * If the h parameter is not specified, default values are used.
20297 * @param $tagvs (array) array of tags and relative vertical spaces.
20298 * @public
20299 * @since 4.2.001 (2008-10-30)
20300 */
20301 public function setHtmlVSpace($tagvs) {
20302 $this->tagvspaces = $tagvs;
20303 }
20304
20305 /**
20306 * Set custom width for list indentation.
20307 * @param $width (float) width of the indentation. Use negative value to disable it.
20308 * @public
20309 * @since 4.2.007 (2008-11-12)
20310 */
20311 public function setListIndentWidth($width) {
20312 return $this->customlistindent = floatval($width);
20313 }
20314
20315 /**
20316 * Set the top/bottom cell sides to be open or closed when the cell cross the page.
20317 * @param $isopen (boolean) if true keeps the top/bottom border open for the cell sides that cross the page.
20318 * @public
20319 * @since 4.2.010 (2008-11-14)
20320 */
20321 public function setOpenCell($isopen) {
20322 $this->opencell = $isopen;
20323 }
20324
20325 /**
20326 * Set the color and font style for HTML links.
20327 * @param $color (array) RGB array of colors
20328 * @param $fontstyle (string) additional font styles to add
20329 * @public
20330 * @since 4.4.003 (2008-12-09)
20331 */
20332 public function setHtmlLinksStyle($color=array(0,0,255), $fontstyle='U') {
20333 $this->htmlLinkColorArray = $color;
20334 $this->htmlLinkFontStyle = $fontstyle;
20335 }
20336
20337 /**
20338 * Convert HTML string containing value and unit of measure to user's units or points.
20339 * @param $htmlval (string) String containing values and unit.
20340 * @param $refsize (string) Reference value in points.
20341 * @param $defaultunit (string) Default unit (can be one of the following: %, em, ex, px, in, mm, pc, pt).
20342 * @param $points (boolean) If true returns points, otherwise returns value in user's units.
20343 * @return float value in user's unit or point if $points=true
20344 * @public
20345 * @since 4.4.004 (2008-12-10)
20346 */
20347 public function getHTMLUnitToUnits($htmlval, $refsize=1, $defaultunit='px', $points=false) {
20348 $supportedunits = array('%', 'em', 'ex', 'px', 'in', 'cm', 'mm', 'pc', 'pt');
20349 $retval = 0;
20350 $value = 0;
20351 $unit = 'px';
20352 if ($points) {
20353 $k = 1;
20354 } else {
20355 $k = $this->k;
20356 }
20357 if (in_array($defaultunit, $supportedunits)) {
20358 $unit = $defaultunit;
20359 }
20360 if (is_numeric($htmlval)) {
20361 $value = floatval($htmlval);
20362 } elseif (preg_match('/([0-9\.\-\+]+)/', $htmlval, $mnum)) {
20363 $value = floatval($mnum[1]);
20364 if (preg_match('/([a-z%]+)/', $htmlval, $munit)) {
20365 if (in_array($munit[1], $supportedunits)) {
20366 $unit = $munit[1];
20367 }
20368 }
20369 }
20370 switch ($unit) {
20371 // percentage
20372 case '%': {
20373 $retval = (($value * $refsize) / 100);
20374 break;
20375 }
20376 // relative-size
20377 case 'em': {
20378 $retval = ($value * $refsize);
20379 break;
20380 }
20381 // height of lower case 'x' (about half the font-size)
20382 case 'ex': {
20383 $retval = ($value * ($refsize / 2));
20384 break;
20385 }
20386 // absolute-size
20387 case 'in': {
20388 $retval = (($value * $this->dpi) / $k);
20389 break;
20390 }
20391 // centimeters
20392 case 'cm': {
20393 $retval = (($value / 2.54 * $this->dpi) / $k);
20394 break;
20395 }
20396 // millimeters
20397 case 'mm': {
20398 $retval = (($value / 25.4 * $this->dpi) / $k);
20399 break;
20400 }
20401 // one pica is 12 points
20402 case 'pc': {
20403 $retval = (($value * 12) / $k);
20404 break;
20405 }
20406 // points
20407 case 'pt': {
20408 $retval = ($value / $k);
20409 break;
20410 }
20411 // pixels
20412 case 'px': {
20413 $retval = $this->pixelsToUnits($value);
20414 if ($points) {
20415 $retval *= $this->k;
20416 }
20417 break;
20418 }
20419 }
20420 return $retval;
20421 }
20422
20423 /**
20424 * Output an HTML list bullet or ordered item symbol
20425 * @param $listdepth (int) list nesting level
20426 * @param $listtype (string) type of list
20427 * @param $size (float) current font size
20428 * @protected
20429 * @since 4.4.004 (2008-12-10)
20430 */
20431 protected function putHtmlListBullet($listdepth, $listtype='', $size=10) {
20432 if ($this->state != 2) {
20433 return;
20434 }
20435 $size /= $this->k;
20436 $fill = '';
20437 $bgcolor = $this->bgcolor;
20438 $color = $this->fgcolor;
20439 $strokecolor = $this->strokecolor;
20440 $width = 0;
20441 $textitem = '';
20442 $tmpx = $this->x;
20443 $lspace = $this->GetStringWidth(' ');
20444 if ($listtype == '^') {
20445 // special symbol used for avoid justification of rect bullet
20446 $this->lispacer = '';
20447 return;
20448 } elseif ($listtype == '!') {
20449 // set default list type for unordered list
20450 $deftypes = array('disc', 'circle', 'square');
20451 $listtype = $deftypes[($listdepth - 1) % 3];
20452 } elseif ($listtype == '#') {
20453 // set default list type for ordered list
20454 $listtype = 'decimal';
20455 } elseif (substr($listtype, 0, 4) == 'img|') {
20456 // custom image type ('img|type|width|height|image.ext')
20457 $img = explode('|', $listtype);
20458 $listtype = 'img';
20459 }
20460 switch ($listtype) {
20461 // unordered types
20462 case 'none': {
20463 break;
20464 }
20465 case 'disc': {
20466 $r = $size / 6;
20467 $lspace += (2 * $r);
20468 if ($this->rtl) {
20469 $this->x += $lspace;
20470 } else {
20471 $this->x -= $lspace;
20472 }
20473 $this->Circle(($this->x + $r), ($this->y + ($this->lasth / 2)), $r, 0, 360, 'F', array(), $color, 8);
20474 break;
20475 }
20476 case 'circle': {
20477 $r = $size / 6;
20478 $lspace += (2 * $r);
20479 if ($this->rtl) {
20480 $this->x += $lspace;
20481 } else {
20482 $this->x -= $lspace;
20483 }
20484 $prev_line_style = $this->linestyleWidth.' '.$this->linestyleCap.' '.$this->linestyleJoin.' '.$this->linestyleDash.' '.$this->DrawColor;
20485 $new_line_style = array('width' => ($r / 3), 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'phase' => 0, 'color'=>$color);
20486 $this->Circle(($this->x + $r), ($this->y + ($this->lasth / 2)), ($r * (1 - (1/6))), 0, 360, 'D', $new_line_style, array(), 8);
20487 $this->_out($prev_line_style); // restore line settings
20488 break;
20489 }
20490 case 'square': {
20491 $l = $size / 3;
20492 $lspace += $l;
20493 if ($this->rtl) {;
20494 $this->x += $lspace;
20495 } else {
20496 $this->x -= $lspace;
20497 }
20498 $this->Rect($this->x, ($this->y + (($this->lasth - $l) / 2)), $l, $l, 'F', array(), $color);
20499 break;
20500 }
20501 case 'img': {
20502 // 1=>type, 2=>width, 3=>height, 4=>image.ext
20503 $lspace += $img[2];
20504 if ($this->rtl) {;
20505 $this->x += $lspace;
20506 } else {
20507 $this->x -= $lspace;
20508 }
20509 $imgtype = strtolower($img[1]);
20510 $prev_y = $this->y;
20511 switch ($imgtype) {
20512 case 'svg': {
20513 $this->ImageSVG($img[4], $this->x, ($this->y + (($this->lasth - $img[3]) / 2)), $img[2], $img[3], '', 'T', '', 0, false);
20514 break;
20515 }
20516 case 'ai':
20517 case 'eps': {
20518 $this->ImageEps($img[4], $this->x, ($this->y + (($this->lasth - $img[3]) / 2)), $img[2], $img[3], '', true, 'T', '', 0, false);
20519 break;
20520 }
20521 default: {
20522 $this->Image($img[4], $this->x, ($this->y + (($this->lasth - $img[3]) / 2)), $img[2], $img[3], $img[1], '', 'T', false, 300, '', false, false, 0, false, false, false);
20523 break;
20524 }
20525 }
20526 $this->y = $prev_y;
20527 break;
20528 }
20529 // ordered types
20530 // $this->listcount[$this->listnum];
20531 // $textitem
20532 case '1':
20533 case 'decimal': {
20534 $textitem = $this->listcount[$this->listnum];
20535 break;
20536 }
20537 case 'decimal-leading-zero': {
20538 $textitem = sprintf('%02d', $this->listcount[$this->listnum]);
20539 break;
20540 }
20541 case 'i':
20542 case 'lower-roman': {
20543 $textitem = strtolower(TCPDF_STATIC::intToRoman($this->listcount[$this->listnum]));
20544 break;
20545 }
20546 case 'I':
20547 case 'upper-roman': {
20548 $textitem = TCPDF_STATIC::intToRoman($this->listcount[$this->listnum]);
20549 break;
20550 }
20551 case 'a':
20552 case 'lower-alpha':
20553 case 'lower-latin': {
20554 $textitem = chr(97 + $this->listcount[$this->listnum] - 1);
20555 break;
20556 }
20557 case 'A':
20558 case 'upper-alpha':
20559 case 'upper-latin': {
20560 $textitem = chr(65 + $this->listcount[$this->listnum] - 1);
20561 break;
20562 }
20563 case 'lower-greek': {
20564 $textitem = TCPDF_FONTS::unichr((945 + $this->listcount[$this->listnum] - 1), $this->isunicode);
20565 break;
20566 }
20567 /*
20568 // Types to be implemented (special handling)
20569 case 'hebrew': {
20570 break;
20571 }
20572 case 'armenian': {
20573 break;
20574 }
20575 case 'georgian': {
20576 break;
20577 }
20578 case 'cjk-ideographic': {
20579 break;
20580 }
20581 case 'hiragana': {
20582 break;
20583 }
20584 case 'katakana': {
20585 break;
20586 }
20587 case 'hiragana-iroha': {
20588 break;
20589 }
20590 case 'katakana-iroha': {
20591 break;
20592 }
20593 */
20594 default: {
20595 $textitem = $this->listcount[$this->listnum];
20596 }
20597 }
20598 if (!TCPDF_STATIC::empty_string($textitem)) {
20599 // Check whether we need a new page or new column
20600 $prev_y = $this->y;
20601 $h = $this->getCellHeight($this->FontSize);
20602 if ($this->checkPageBreak($h) OR ($this->y < $prev_y)) {
20603 $tmpx = $this->x;
20604 }
20605 // print ordered item
20606 if ($this->rtl) {
20607 $textitem = '.'.$textitem;
20608 } else {
20609 $textitem = $textitem.'.';
20610 }
20611 $lspace += $this->GetStringWidth($textitem);
20612 if ($this->rtl) {
20613 $this->x += $lspace;
20614 } else {
20615 $this->x -= $lspace;
20616 }
20617 $this->Write($this->lasth, $textitem, '', false, '', false, 0, false);
20618 }
20619 $this->x = $tmpx;
20620 $this->lispacer = '^';
20621 // restore colors
20622 $this->SetFillColorArray($bgcolor);
20623 $this->SetDrawColorArray($strokecolor);
20624 $this->SettextColorArray($color);
20625 }
20626
20627 /**
20628 * Returns current graphic variables as array.
20629 * @return array of graphic variables
20630 * @protected
20631 * @since 4.2.010 (2008-11-14)
20632 */
20633 protected function getGraphicVars() {
20634 $grapvars = array(
20635 'FontFamily' => $this->FontFamily,
20636 'FontStyle' => $this->FontStyle,
20637 'FontSizePt' => $this->FontSizePt,
20638 'rMargin' => $this->rMargin,
20639 'lMargin' => $this->lMargin,
20640 'cell_padding' => $this->cell_padding,
20641 'cell_margin' => $this->cell_margin,
20642 'LineWidth' => $this->LineWidth,
20643 'linestyleWidth' => $this->linestyleWidth,
20644 'linestyleCap' => $this->linestyleCap,
20645 'linestyleJoin' => $this->linestyleJoin,
20646 'linestyleDash' => $this->linestyleDash,
20647 'textrendermode' => $this->textrendermode,
20648 'textstrokewidth' => $this->textstrokewidth,
20649 'DrawColor' => $this->DrawColor,
20650 'FillColor' => $this->FillColor,
20651 'TextColor' => $this->TextColor,
20652 'ColorFlag' => $this->ColorFlag,
20653 'bgcolor' => $this->bgcolor,
20654 'fgcolor' => $this->fgcolor,
20655 'htmlvspace' => $this->htmlvspace,
20656 'listindent' => $this->listindent,
20657 'listindentlevel' => $this->listindentlevel,
20658 'listnum' => $this->listnum,
20659 'listordered' => $this->listordered,
20660 'listcount' => $this->listcount,
20661 'lispacer' => $this->lispacer,
20662 'cell_height_ratio' => $this->cell_height_ratio,
20663 'font_stretching' => $this->font_stretching,
20664 'font_spacing' => $this->font_spacing,
20665 'alpha' => $this->alpha,
20666 // extended
20667 'lasth' => $this->lasth,
20668 'tMargin' => $this->tMargin,
20669 'bMargin' => $this->bMargin,
20670 'AutoPageBreak' => $this->AutoPageBreak,
20671 'PageBreakTrigger' => $this->PageBreakTrigger,
20672 'x' => $this->x,
20673 'y' => $this->y,
20674 'w' => $this->w,
20675 'h' => $this->h,
20676 'wPt' => $this->wPt,
20677 'hPt' => $this->hPt,
20678 'fwPt' => $this->fwPt,
20679 'fhPt' => $this->fhPt,
20680 'page' => $this->page,
20681 'current_column' => $this->current_column,
20682 'num_columns' => $this->num_columns
20683 );
20684 return $grapvars;
20685 }
20686
20687 /**
20688 * Set graphic variables.
20689 * @param $gvars (array) array of graphic variablesto restore
20690 * @param $extended (boolean) if true restore extended graphic variables
20691 * @protected
20692 * @since 4.2.010 (2008-11-14)
20693 */
20694 protected function setGraphicVars($gvars, $extended=false) {
20695 if ($this->state != 2) {
20696 return;
20697 }
20698 $this->FontFamily = $gvars['FontFamily'];
20699 $this->FontStyle = $gvars['FontStyle'];
20700 $this->FontSizePt = $gvars['FontSizePt'];
20701 $this->rMargin = $gvars['rMargin'];
20702 $this->lMargin = $gvars['lMargin'];
20703 $this->cell_padding = $gvars['cell_padding'];
20704 $this->cell_margin = $gvars['cell_margin'];
20705 $this->LineWidth = $gvars['LineWidth'];
20706 $this->linestyleWidth = $gvars['linestyleWidth'];
20707 $this->linestyleCap = $gvars['linestyleCap'];
20708 $this->linestyleJoin = $gvars['linestyleJoin'];
20709 $this->linestyleDash = $gvars['linestyleDash'];
20710 $this->textrendermode = $gvars['textrendermode'];
20711 $this->textstrokewidth = $gvars['textstrokewidth'];
20712 $this->DrawColor = $gvars['DrawColor'];
20713 $this->FillColor = $gvars['FillColor'];
20714 $this->TextColor = $gvars['TextColor'];
20715 $this->ColorFlag = $gvars['ColorFlag'];
20716 $this->bgcolor = $gvars['bgcolor'];
20717 $this->fgcolor = $gvars['fgcolor'];
20718 $this->htmlvspace = $gvars['htmlvspace'];
20719 $this->listindent = $gvars['listindent'];
20720 $this->listindentlevel = $gvars['listindentlevel'];
20721 $this->listnum = $gvars['listnum'];
20722 $this->listordered = $gvars['listordered'];
20723 $this->listcount = $gvars['listcount'];
20724 $this->lispacer = $gvars['lispacer'];
20725 $this->cell_height_ratio = $gvars['cell_height_ratio'];
20726 $this->font_stretching = $gvars['font_stretching'];
20727 $this->font_spacing = $gvars['font_spacing'];
20728 $this->alpha = $gvars['alpha'];
20729 if ($extended) {
20730 // restore extended values
20731 $this->lasth = $gvars['lasth'];
20732 $this->tMargin = $gvars['tMargin'];
20733 $this->bMargin = $gvars['bMargin'];
20734 $this->AutoPageBreak = $gvars['AutoPageBreak'];
20735 $this->PageBreakTrigger = $gvars['PageBreakTrigger'];
20736 $this->x = $gvars['x'];
20737 $this->y = $gvars['y'];
20738 $this->w = $gvars['w'];
20739 $this->h = $gvars['h'];
20740 $this->wPt = $gvars['wPt'];
20741 $this->hPt = $gvars['hPt'];
20742 $this->fwPt = $gvars['fwPt'];
20743 $this->fhPt = $gvars['fhPt'];
20744 $this->page = $gvars['page'];
20745 $this->current_column = $gvars['current_column'];
20746 $this->num_columns = $gvars['num_columns'];
20747 }
20748 $this->_out(''.$this->linestyleWidth.' '.$this->linestyleCap.' '.$this->linestyleJoin.' '.$this->linestyleDash.' '.$this->DrawColor.' '.$this->FillColor.'');
20749 if (!TCPDF_STATIC::empty_string($this->FontFamily)) {
20750 $this->SetFont($this->FontFamily, $this->FontStyle, $this->FontSizePt);
20751 }
20752 }
20753
20754 /**
20755 * Outputs the "save graphics state" operator 'q'
20756 * @protected
20757 */
20758 protected function _outSaveGraphicsState() {
20759 $this->_out('q');
20760 }
20761
20762 /**
20763 * Outputs the "restore graphics state" operator 'Q'
20764 * @protected
20765 */
20766 protected function _outRestoreGraphicsState() {
20767 $this->_out('Q');
20768 }
20769
20770 /**
20771 * Writes data to a temporary file on filesystem.
20772 * @param $filename (string) file name
20773 * @param $data (mixed) data to write on file
20774 * @param $append (boolean) if true append data, false replace.
20775 * @param $serialize (boolean) if true serialize data.
20776 * @since 4.5.000 (2008-12-31)
20777 * @protected
20778 */
20779 protected function writeDiskCache($filename, $data, $append=false, $serialize=false) {
20780 if ($append) {
20781 $fmode = 'ab+';
20782 } else {
20783 $fmode = 'wb+';
20784 }
20785 $f = @fopen($filename, $fmode);
20786 if (!$f) {
20787 $this->Error('Unable to write cache file: '.$filename);
20788 }
20789 if ($serialize) {
20790 $data = $this->file_id.serialize($data);
20791 }
20792 fwrite($f, $data);
20793 fclose($f);
20794 // update file length (needed for transactions)
20795 if (!isset($this->cache_file_length['_'.$filename])) {
20796 $this->cache_file_length['_'.$filename] = strlen($data);
20797 } else {
20798 $this->cache_file_length['_'.$filename] += strlen($data);
20799 }
20800 }
20801
20802 /**
20803 * Read data from a temporary file on filesystem.
20804 * @param $filename (string) file name
20805 * @param $unserialize (boolean) if true unserialize data.
20806 * @return mixed retrieved data
20807 * @since 4.5.000 (2008-12-31)
20808 * @protected
20809 */
20810 protected function readDiskCache($filename, $unserialize=false) {
20811 $data = file_get_contents($filename);
20812 if ($data === FALSE) {
20813 $this->Error('Unable to read the file: '.$filename);
20814 }
20815 if ($unserialize) {
20816 if (substr($data, 0, 32) != $this->file_id) {
20817 $this->Error('Invalid cache file: '.$filename);
20818 }
20819 $data = unserialize(substr($data, 32));
20820 }
20821 return $data;
20822 }
20823
20824 /**
20825 * Set buffer content (always append data).
20826 * @param $data (string) data
20827 * @protected
20828 * @since 4.5.000 (2009-01-02)
20829 */
20830 protected function setBuffer($data) {
20831 $this->bufferlen += strlen($data);
20832 if ($this->diskcache) {
20833 if (!isset($this->buffer) OR TCPDF_STATIC::empty_string($this->buffer)) {
20834 $this->buffer = TCPDF_STATIC::getObjFilename('buf');
20835 }
20836 $this->writeDiskCache($this->buffer, $data, true, false);
20837 } else {
20838 $this->buffer .= $data;
20839 }
20840 }
20841
20842 /**
20843 * Replace the buffer content
20844 * @param $data (string) data
20845 * @protected
20846 * @since 5.5.000 (2010-06-22)
20847 */
20848 protected function replaceBuffer($data) {
20849 $this->bufferlen = strlen($data);
20850 if ($this->diskcache) {
20851 if (!isset($this->buffer) OR TCPDF_STATIC::empty_string($this->buffer)) {
20852 $this->buffer = TCPDF_STATIC::getObjFilename('buf');
20853 }
20854 $this->writeDiskCache($this->buffer, $data, false, false);
20855 } else {
20856 $this->buffer = $data;
20857 }
20858 }
20859
20860 /**
20861 * Get buffer content.
20862 * @return string buffer content
20863 * @protected
20864 * @since 4.5.000 (2009-01-02)
20865 */
20866 protected function getBuffer() {
20867 if ($this->diskcache) {
20868 return $this->readDiskCache($this->buffer, false);
20869 } else {
20870 return $this->buffer;
20871 }
20872 }
20873
20874 /**
20875 * Set page buffer content.
20876 * @param $page (int) page number
20877 * @param $data (string) page data
20878 * @param $append (boolean) if true append data, false replace.
20879 * @protected
20880 * @since 4.5.000 (2008-12-31)
20881 */
20882 protected function setPageBuffer($page, $data, $append=false) {
20883 if ($this->diskcache) {
20884 if (!isset($this->pages[$page])) {
20885 $this->pages[$page] = TCPDF_STATIC::getObjFilename('page');
20886 }
20887 $this->writeDiskCache($this->pages[$page], $data, $append, false);
20888 } else {
20889 if ($append) {
20890 $this->pages[$page] .= $data;
20891 } else {
20892 $this->pages[$page] = $data;
20893 }
20894 }
20895 if ($append AND isset($this->pagelen[$page])) {
20896 $this->pagelen[$page] += strlen($data);
20897 } else {
20898 $this->pagelen[$page] = strlen($data);
20899 }
20900 }
20901
20902 /**
20903 * Get page buffer content.
20904 * @param $page (int) page number
20905 * @return string page buffer content or false in case of error
20906 * @protected
20907 * @since 4.5.000 (2008-12-31)
20908 */
20909 protected function getPageBuffer($page) {
20910 if ($this->diskcache) {
20911 return $this->readDiskCache($this->pages[$page], false);
20912 } elseif (isset($this->pages[$page])) {
20913 return $this->pages[$page];
20914 }
20915 return false;
20916 }
20917
20918 /**
20919 * Set image buffer content.
20920 * @param $image (string) image key
20921 * @param $data (array) image data
20922 * @return int image index number
20923 * @protected
20924 * @since 4.5.000 (2008-12-31)
20925 */
20926 protected function setImageBuffer($image, $data) {
20927 if (($data['i'] = array_search($image, $this->imagekeys)) === FALSE) {
20928 $this->imagekeys[$this->numimages] = $image;
20929 $data['i'] = $this->numimages;
20930 ++$this->numimages;
20931 }
20932 if ($this->diskcache) {
20933 if (!isset($this->images[$image])) {
20934 $this->images[$image] = TCPDF_STATIC::getObjFilename('img');
20935 }
20936 $this->writeDiskCache($this->images[$image], $data, false, true);
20937 } else {
20938 $this->images[$image] = $data;
20939 }
20940 return $data['i'];
20941 }
20942
20943 /**
20944 * Set image buffer content for a specified sub-key.
20945 * @param $image (string) image key
20946 * @param $key (string) image sub-key
20947 * @param $data (array) image data
20948 * @protected
20949 * @since 4.5.000 (2008-12-31)
20950 */
20951 protected function setImageSubBuffer($image, $key, $data) {
20952 if (!isset($this->images[$image])) {
20953 $this->setImageBuffer($image, array());
20954 }
20955 if ($this->diskcache) {
20956 $tmpimg = $this->getImageBuffer($image);
20957 $tmpimg[$key] = $data;
20958 $this->writeDiskCache($this->images[$image], $tmpimg, false, true);
20959 } else {
20960 $this->images[$image][$key] = $data;
20961 }
20962 }
20963
20964 /**
20965 * Get image buffer content.
20966 * @param $image (string) image key
20967 * @return string image buffer content or false in case of error
20968 * @protected
20969 * @since 4.5.000 (2008-12-31)
20970 */
20971 protected function getImageBuffer($image) {
20972 if ($this->diskcache AND isset($this->images[$image])) {
20973 return $this->readDiskCache($this->images[$image], true);
20974 } elseif (isset($this->images[$image])) {
20975 return $this->images[$image];
20976 }
20977 return false;
20978 }
20979
20980 /**
20981 * Set font buffer content.
20982 * @param $font (string) font key
20983 * @param $data (array) font data
20984 * @protected
20985 * @since 4.5.000 (2009-01-02)
20986 */
20987 protected function setFontBuffer($font, $data) {
20988 if ($this->diskcache) {
20989 if (!isset($this->fonts[$font])) {
20990 $this->fonts[$font] = TCPDF_STATIC::getObjFilename('font');
20991 }
20992 $this->writeDiskCache($this->fonts[$font], $data, false, true);
20993 } else {
20994 $this->fonts[$font] = $data;
20995 }
20996 if (!in_array($font, $this->fontkeys)) {
20997 $this->fontkeys[] = $font;
20998 // store object ID for current font
20999 ++$this->n;
21000 $this->font_obj_ids[$font] = $this->n;
21001 $this->setFontSubBuffer($font, 'n', $this->n);
21002 }
21003 }
21004
21005 /**
21006 * Set font buffer content.
21007 * @param $font (string) font key
21008 * @param $key (string) font sub-key
21009 * @param $data (array) font data
21010 * @protected
21011 * @since 4.5.000 (2009-01-02)
21012 */
21013 protected function setFontSubBuffer($font, $key, $data) {
21014 if (!isset($this->fonts[$font])) {
21015 $this->setFontBuffer($font, array());
21016 }
21017 if ($this->diskcache) {
21018 $tmpfont = $this->getFontBuffer($font);
21019 $tmpfont[$key] = $data;
21020 $this->writeDiskCache($this->fonts[$font], $tmpfont, false, true);
21021 } else {
21022 $this->fonts[$font][$key] = $data;
21023 }
21024 }
21025
21026 /**
21027 * Get font buffer content.
21028 * @param $font (string) font key
21029 * @return string font buffer content or false in case of error
21030 * @protected
21031 * @since 4.5.000 (2009-01-02)
21032 */
21033 protected function getFontBuffer($font) {
21034 if ($this->diskcache AND isset($this->fonts[$font])) {
21035 return $this->readDiskCache($this->fonts[$font], true);
21036 } elseif (isset($this->fonts[$font])) {
21037 return $this->fonts[$font];
21038 }
21039 return false;
21040 }
21041
21042 /**
21043 * Move a page to a previous position.
21044 * @param $frompage (int) number of the source page
21045 * @param $topage (int) number of the destination page (must be less than $frompage)
21046 * @return true in case of success, false in case of error.
21047 * @public
21048 * @since 4.5.000 (2009-01-02)
21049 */
21050 public function movePage($frompage, $topage) {
21051 if (($frompage > $this->numpages) OR ($frompage <= $topage)) {
21052 return false;
21053 }
21054 if ($frompage == $this->page) {
21055 // close the page before moving it
21056 $this->endPage();
21057 }
21058 // move all page-related states
21059 $tmppage = $this->getPageBuffer($frompage);
21060 $tmppagedim = $this->pagedim[$frompage];
21061 $tmppagelen = $this->pagelen[$frompage];
21062 $tmpintmrk = $this->intmrk[$frompage];
21063 $tmpbordermrk = $this->bordermrk[$frompage];
21064 $tmpcntmrk = $this->cntmrk[$frompage];
21065 $tmppageobjects = $this->pageobjects[$frompage];
21066 if (isset($this->footerpos[$frompage])) {
21067 $tmpfooterpos = $this->footerpos[$frompage];
21068 }
21069 if (isset($this->footerlen[$frompage])) {
21070 $tmpfooterlen = $this->footerlen[$frompage];
21071 }
21072 if (isset($this->transfmrk[$frompage])) {
21073 $tmptransfmrk = $this->transfmrk[$frompage];
21074 }
21075 if (isset($this->PageAnnots[$frompage])) {
21076 $tmpannots = $this->PageAnnots[$frompage];
21077 }
21078 if (isset($this->newpagegroup) AND !empty($this->newpagegroup)) {
21079 for ($i = $frompage; $i > $topage; --$i) {
21080 if (isset($this->newpagegroup[$i]) AND (($i + $this->pagegroups[$this->newpagegroup[$i]]) > $frompage)) {
21081 --$this->pagegroups[$this->newpagegroup[$i]];
21082 break;
21083 }
21084 }
21085 for ($i = $topage; $i > 0; --$i) {
21086 if (isset($this->newpagegroup[$i]) AND (($i + $this->pagegroups[$this->newpagegroup[$i]]) > $topage)) {
21087 ++$this->pagegroups[$this->newpagegroup[$i]];
21088 break;
21089 }
21090 }
21091 }
21092 for ($i = $frompage; $i > $topage; --$i) {
21093 $j = $i - 1;
21094 // shift pages down
21095 $this->setPageBuffer($i, $this->getPageBuffer($j));
21096 $this->pagedim[$i] = $this->pagedim[$j];
21097 $this->pagelen[$i] = $this->pagelen[$j];
21098 $this->intmrk[$i] = $this->intmrk[$j];
21099 $this->bordermrk[$i] = $this->bordermrk[$j];
21100 $this->cntmrk[$i] = $this->cntmrk[$j];
21101 $this->pageobjects[$i] = $this->pageobjects[$j];
21102 if (isset($this->footerpos[$j])) {
21103 $this->footerpos[$i] = $this->footerpos[$j];
21104 } elseif (isset($this->footerpos[$i])) {
21105 unset($this->footerpos[$i]);
21106 }
21107 if (isset($this->footerlen[$j])) {
21108 $this->footerlen[$i] = $this->footerlen[$j];
21109 } elseif (isset($this->footerlen[$i])) {
21110 unset($this->footerlen[$i]);
21111 }
21112 if (isset($this->transfmrk[$j])) {
21113 $this->transfmrk[$i] = $this->transfmrk[$j];
21114 } elseif (isset($this->transfmrk[$i])) {
21115 unset($this->transfmrk[$i]);
21116 }
21117 if (isset($this->PageAnnots[$j])) {
21118 $this->PageAnnots[$i] = $this->PageAnnots[$j];
21119 } elseif (isset($this->PageAnnots[$i])) {
21120 unset($this->PageAnnots[$i]);
21121 }
21122 if (isset($this->newpagegroup[$j])) {
21123 $this->newpagegroup[$i] = $this->newpagegroup[$j];
21124 unset($this->newpagegroup[$j]);
21125 }
21126 if ($this->currpagegroup == $j) {
21127 $this->currpagegroup = $i;
21128 }
21129 }
21130 $this->setPageBuffer($topage, $tmppage);
21131 $this->pagedim[$topage] = $tmppagedim;
21132 $this->pagelen[$topage] = $tmppagelen;
21133 $this->intmrk[$topage] = $tmpintmrk;
21134 $this->bordermrk[$topage] = $tmpbordermrk;
21135 $this->cntmrk[$topage] = $tmpcntmrk;
21136 $this->pageobjects[$topage] = $tmppageobjects;
21137 if (isset($tmpfooterpos)) {
21138 $this->footerpos[$topage] = $tmpfooterpos;
21139 } elseif (isset($this->footerpos[$topage])) {
21140 unset($this->footerpos[$topage]);
21141 }
21142 if (isset($tmpfooterlen)) {
21143 $this->footerlen[$topage] = $tmpfooterlen;
21144 } elseif (isset($this->footerlen[$topage])) {
21145 unset($this->footerlen[$topage]);
21146 }
21147 if (isset($tmptransfmrk)) {
21148 $this->transfmrk[$topage] = $tmptransfmrk;
21149 } elseif (isset($this->transfmrk[$topage])) {
21150 unset($this->transfmrk[$topage]);
21151 }
21152 if (isset($tmpannots)) {
21153 $this->PageAnnots[$topage] = $tmpannots;
21154 } elseif (isset($this->PageAnnots[$topage])) {
21155 unset($this->PageAnnots[$topage]);
21156 }
21157 // adjust outlines
21158 $tmpoutlines = $this->outlines;
21159 foreach ($tmpoutlines as $key => $outline) {
21160 if (!$outline['f']) {
21161 if (($outline['p'] >= $topage) AND ($outline['p'] < $frompage)) {
21162 $this->outlines[$key]['p'] = ($outline['p'] + 1);
21163 } elseif ($outline['p'] == $frompage) {
21164 $this->outlines[$key]['p'] = $topage;
21165 }
21166 }
21167 }
21168 // adjust dests
21169 $tmpdests = $this->dests;
21170 foreach ($tmpdests as $key => $dest) {
21171 if (!$dest['f']) {
21172 if (($dest['p'] >= $topage) AND ($dest['p'] < $frompage)) {
21173 $this->dests[$key]['p'] = ($dest['p'] + 1);
21174 } elseif ($dest['p'] == $frompage) {
21175 $this->dests[$key]['p'] = $topage;
21176 }
21177 }
21178 }
21179 // adjust links
21180 $tmplinks = $this->links;
21181 foreach ($tmplinks as $key => $link) {
21182 if (!$link['f']) {
21183 if (($link['p'] >= $topage) AND ($link['p'] < $frompage)) {
21184 $this->links[$key]['p'] = ($link['p'] + 1);
21185 } elseif ($link['p'] == $frompage) {
21186 $this->links[$key]['p'] = $topage;
21187 }
21188 }
21189 }
21190 // adjust javascript
21191 $jfrompage = $frompage;
21192 $jtopage = $topage;
21193 if (preg_match_all('/this\.addField\(\'([^\']*)\',\'([^\']*)\',([0-9]+)/', $this->javascript, $pamatch) > 0) {
21194 foreach($pamatch[0] as $pk => $pmatch) {
21195 $pagenum = intval($pamatch[3][$pk]) + 1;
21196 if (($pagenum >= $jtopage) AND ($pagenum < $jfrompage)) {
21197 $newpage = ($pagenum + 1);
21198 } elseif ($pagenum == $jfrompage) {
21199 $newpage = $jtopage;
21200 } else {
21201 $newpage = $pagenum;
21202 }
21203 --$newpage;
21204 $newjs = "this.addField(\'".$pamatch[1][$pk]."\',\'".$pamatch[2][$pk]."\',".$newpage;
21205 $this->javascript = str_replace($pmatch, $newjs, $this->javascript);
21206 }
21207 unset($pamatch);
21208 }
21209 // return to last page
21210 $this->lastPage(true);
21211 return true;
21212 }
21213
21214 /**
21215 * Remove the specified page.
21216 * @param $page (int) page to remove
21217 * @return true in case of success, false in case of error.
21218 * @public
21219 * @since 4.6.004 (2009-04-23)
21220 */
21221 public function deletePage($page) {
21222 if (($page < 1) OR ($page > $this->numpages)) {
21223 return false;
21224 }
21225 // delete current page
21226 unset($this->pages[$page]);
21227 unset($this->pagedim[$page]);
21228 unset($this->pagelen[$page]);
21229 unset($this->intmrk[$page]);
21230 unset($this->bordermrk[$page]);
21231 unset($this->cntmrk[$page]);
21232 foreach ($this->pageobjects[$page] as $oid) {
21233 if (isset($this->offsets[$oid])){
21234 unset($this->offsets[$oid]);
21235 }
21236 }
21237 unset($this->pageobjects[$page]);
21238 if (isset($this->footerpos[$page])) {
21239 unset($this->footerpos[$page]);
21240 }
21241 if (isset($this->footerlen[$page])) {
21242 unset($this->footerlen[$page]);
21243 }
21244 if (isset($this->transfmrk[$page])) {
21245 unset($this->transfmrk[$page]);
21246 }
21247 if (isset($this->PageAnnots[$page])) {
21248 unset($this->PageAnnots[$page]);
21249 }
21250 if (isset($this->newpagegroup) AND !empty($this->newpagegroup)) {
21251 for ($i = $page; $i > 0; --$i) {
21252 if (isset($this->newpagegroup[$i]) AND (($i + $this->pagegroups[$this->newpagegroup[$i]]) > $page)) {
21253 --$this->pagegroups[$this->newpagegroup[$i]];
21254 break;
21255 }
21256 }
21257 }
21258 if (isset($this->pageopen[$page])) {
21259 unset($this->pageopen[$page]);
21260 }
21261 if ($page < $this->numpages) {
21262 // update remaining pages
21263 for ($i = $page; $i < $this->numpages; ++$i) {
21264 $j = $i + 1;
21265 // shift pages
21266 $this->setPageBuffer($i, $this->getPageBuffer($j));
21267 $this->pagedim[$i] = $this->pagedim[$j];
21268 $this->pagelen[$i] = $this->pagelen[$j];
21269 $this->intmrk[$i] = $this->intmrk[$j];
21270 $this->bordermrk[$i] = $this->bordermrk[$j];
21271 $this->cntmrk[$i] = $this->cntmrk[$j];
21272 $this->pageobjects[$i] = $this->pageobjects[$j];
21273 if (isset($this->footerpos[$j])) {
21274 $this->footerpos[$i] = $this->footerpos[$j];
21275 } elseif (isset($this->footerpos[$i])) {
21276 unset($this->footerpos[$i]);
21277 }
21278 if (isset($this->footerlen[$j])) {
21279 $this->footerlen[$i] = $this->footerlen[$j];
21280 } elseif (isset($this->footerlen[$i])) {
21281 unset($this->footerlen[$i]);
21282 }
21283 if (isset($this->transfmrk[$j])) {
21284 $this->transfmrk[$i] = $this->transfmrk[$j];
21285 } elseif (isset($this->transfmrk[$i])) {
21286 unset($this->transfmrk[$i]);
21287 }
21288 if (isset($this->PageAnnots[$j])) {
21289 $this->PageAnnots[$i] = $this->PageAnnots[$j];
21290 } elseif (isset($this->PageAnnots[$i])) {
21291 unset($this->PageAnnots[$i]);
21292 }
21293 if (isset($this->newpagegroup[$j])) {
21294 $this->newpagegroup[$i] = $this->newpagegroup[$j];
21295 unset($this->newpagegroup[$j]);
21296 }
21297 if ($this->currpagegroup == $j) {
21298 $this->currpagegroup = $i;
21299 }
21300 if (isset($this->pageopen[$j])) {
21301 $this->pageopen[$i] = $this->pageopen[$j];
21302 } elseif (isset($this->pageopen[$i])) {
21303 unset($this->pageopen[$i]);
21304 }
21305 }
21306 // remove last page
21307 unset($this->pages[$this->numpages]);
21308 unset($this->pagedim[$this->numpages]);
21309 unset($this->pagelen[$this->numpages]);
21310 unset($this->intmrk[$this->numpages]);
21311 unset($this->bordermrk[$this->numpages]);
21312 unset($this->cntmrk[$this->numpages]);
21313 foreach ($this->pageobjects[$this->numpages] as $oid) {
21314 if (isset($this->offsets[$oid])){
21315 unset($this->offsets[$oid]);
21316 }
21317 }
21318 unset($this->pageobjects[$this->numpages]);
21319 if (isset($this->footerpos[$this->numpages])) {
21320 unset($this->footerpos[$this->numpages]);
21321 }
21322 if (isset($this->footerlen[$this->numpages])) {
21323 unset($this->footerlen[$this->numpages]);
21324 }
21325 if (isset($this->transfmrk[$this->numpages])) {
21326 unset($this->transfmrk[$this->numpages]);
21327 }
21328 if (isset($this->PageAnnots[$this->numpages])) {
21329 unset($this->PageAnnots[$this->numpages]);
21330 }
21331 if (isset($this->newpagegroup[$this->numpages])) {
21332 unset($this->newpagegroup[$this->numpages]);
21333 }
21334 if ($this->currpagegroup == $this->numpages) {
21335 $this->currpagegroup = ($this->numpages - 1);
21336 }
21337 if (isset($this->pagegroups[$this->numpages])) {
21338 unset($this->pagegroups[$this->numpages]);
21339 }
21340 if (isset($this->pageopen[$this->numpages])) {
21341 unset($this->pageopen[$this->numpages]);
21342 }
21343 }
21344 --$this->numpages;
21345 $this->page = $this->numpages;
21346 // adjust outlines
21347 $tmpoutlines = $this->outlines;
21348 foreach ($tmpoutlines as $key => $outline) {
21349 if (!$outline['f']) {
21350 if ($outline['p'] > $page) {
21351 $this->outlines[$key]['p'] = $outline['p'] - 1;
21352 } elseif ($outline['p'] == $page) {
21353 unset($this->outlines[$key]);
21354 }
21355 }
21356 }
21357 // adjust dests
21358 $tmpdests = $this->dests;
21359 foreach ($tmpdests as $key => $dest) {
21360 if (!$dest['f']) {
21361 if ($dest['p'] > $page) {
21362 $this->dests[$key]['p'] = $dest['p'] - 1;
21363 } elseif ($dest['p'] == $page) {
21364 unset($this->dests[$key]);
21365 }
21366 }
21367 }
21368 // adjust links
21369 $tmplinks = $this->links;
21370 foreach ($tmplinks as $key => $link) {
21371 if (!$link['f']) {
21372 if ($link['p'] > $page) {
21373 $this->links[$key]['p'] = $link['p'] - 1;
21374 } elseif ($link['p'] == $page) {
21375 unset($this->links[$key]);
21376 }
21377 }
21378 }
21379 // adjust javascript
21380 $jpage = $page;
21381 if (preg_match_all('/this\.addField\(\'([^\']*)\',\'([^\']*)\',([0-9]+)/', $this->javascript, $pamatch) > 0) {
21382 foreach($pamatch[0] as $pk => $pmatch) {
21383 $pagenum = intval($pamatch[3][$pk]) + 1;
21384 if ($pagenum >= $jpage) {
21385 $newpage = ($pagenum - 1);
21386 } elseif ($pagenum == $jpage) {
21387 $newpage = 1;
21388 } else {
21389 $newpage = $pagenum;
21390 }
21391 --$newpage;
21392 $newjs = "this.addField(\'".$pamatch[1][$pk]."\',\'".$pamatch[2][$pk]."\',".$newpage;
21393 $this->javascript = str_replace($pmatch, $newjs, $this->javascript);
21394 }
21395 unset($pamatch);
21396 }
21397 // return to last page
21398 if ($this->numpages > 0) {
21399 $this->lastPage(true);
21400 }
21401 return true;
21402 }
21403
21404 /**
21405 * Clone the specified page to a new page.
21406 * @param $page (int) number of page to copy (0 = current page)
21407 * @return true in case of success, false in case of error.
21408 * @public
21409 * @since 4.9.015 (2010-04-20)
21410 */
21411 public function copyPage($page=0) {
21412 if ($page == 0) {
21413 // default value
21414 $page = $this->page;
21415 }
21416 if (($page < 1) OR ($page > $this->numpages)) {
21417 return false;
21418 }
21419 // close the last page
21420 $this->endPage();
21421 // copy all page-related states
21422 ++$this->numpages;
21423 $this->page = $this->numpages;
21424 $this->setPageBuffer($this->page, $this->getPageBuffer($page));
21425 $this->pagedim[$this->page] = $this->pagedim[$page];
21426 $this->pagelen[$this->page] = $this->pagelen[$page];
21427 $this->intmrk[$this->page] = $this->intmrk[$page];
21428 $this->bordermrk[$this->page] = $this->bordermrk[$page];
21429 $this->cntmrk[$this->page] = $this->cntmrk[$page];
21430 $this->pageobjects[$this->page] = $this->pageobjects[$page];
21431 $this->pageopen[$this->page] = false;
21432 if (isset($this->footerpos[$page])) {
21433 $this->footerpos[$this->page] = $this->footerpos[$page];
21434 }
21435 if (isset($this->footerlen[$page])) {
21436 $this->footerlen[$this->page] = $this->footerlen[$page];
21437 }
21438 if (isset($this->transfmrk[$page])) {
21439 $this->transfmrk[$this->page] = $this->transfmrk[$page];
21440 }
21441 if (isset($this->PageAnnots[$page])) {
21442 $this->PageAnnots[$this->page] = $this->PageAnnots[$page];
21443 }
21444 if (isset($this->newpagegroup[$page])) {
21445 // start a new group
21446 $this->newpagegroup[$this->page] = sizeof($this->newpagegroup) + 1;
21447 $this->currpagegroup = $this->newpagegroup[$this->page];
21448 $this->pagegroups[$this->currpagegroup] = 1;
21449 } elseif (isset($this->currpagegroup) AND ($this->currpagegroup > 0)) {
21450 ++$this->pagegroups[$this->currpagegroup];
21451 }
21452 // copy outlines
21453 $tmpoutlines = $this->outlines;
21454 foreach ($tmpoutlines as $key => $outline) {
21455 if ($outline['p'] == $page) {
21456 $this->outlines[] = array('t' => $outline['t'], 'l' => $outline['l'], 'x' => $outline['x'], 'y' => $outline['y'], 'p' => $this->page, 'f' => $outline['f'], 's' => $outline['s'], 'c' => $outline['c']);
21457 }
21458 }
21459 // copy links
21460 $tmplinks = $this->links;
21461 foreach ($tmplinks as $key => $link) {
21462 if ($link['p'] == $page) {
21463 $this->links[] = array('p' => $this->page, 'y' => $link['y'], 'f' => $link['f']);
21464 }
21465 }
21466 // return to last page
21467 $this->lastPage(true);
21468 return true;
21469 }
21470
21471 /**
21472 * Output a Table of Content Index (TOC).
21473 * This method must be called after all Bookmarks were set.
21474 * Before calling this method you have to open the page using the addTOCPage() method.
21475 * After calling this method you have to call endTOCPage() to close the TOC page.
21476 * You can override this method to achieve different styles.
21477 * @param $page (int) page number where this TOC should be inserted (leave empty for current page).
21478 * @param $numbersfont (string) set the font for page numbers (please use monospaced font for better alignment).
21479 * @param $filler (string) string used to fill the space between text and page number.
21480 * @param $toc_name (string) name to use for TOC bookmark.
21481 * @param $style (string) Font style for title: B = Bold, I = Italic, BI = Bold + Italic.
21482 * @param $color (array) RGB color array for bookmark title (values from 0 to 255).
21483 * @public
21484 * @author Nicola Asuni
21485 * @since 4.5.000 (2009-01-02)
21486 * @see addTOCPage(), endTOCPage(), addHTMLTOC()
21487 */
21488 public function addTOC($page='', $numbersfont='', $filler='.', $toc_name='TOC', $style='', $color=array(0,0,0)) {
21489 $fontsize = $this->FontSizePt;
21490 $fontfamily = $this->FontFamily;
21491 $fontstyle = $this->FontStyle;
21492 $w = $this->w - $this->lMargin - $this->rMargin;
21493 $spacer = $this->GetStringWidth(chr(32)) * 4;
21494 $lmargin = $this->lMargin;
21495 $rmargin = $this->rMargin;
21496 $x_start = $this->GetX();
21497 $page_first = $this->page;
21498 $current_page = $this->page;
21499 $page_fill_start = false;
21500 $page_fill_end = false;
21501 $current_column = $this->current_column;
21502 if (TCPDF_STATIC::empty_string($numbersfont)) {
21503 $numbersfont = $this->default_monospaced_font;
21504 }
21505 if (TCPDF_STATIC::empty_string($filler)) {
21506 $filler = ' ';
21507 }
21508 if (TCPDF_STATIC::empty_string($page)) {
21509 $gap = ' ';
21510 } else {
21511 $gap = '';
21512 if ($page < 1) {
21513 $page = 1;
21514 }
21515 }
21516 $this->SetFont($numbersfont, $fontstyle, $fontsize);
21517 $numwidth = $this->GetStringWidth('00000');
21518 $maxpage = 0; //used for pages on attached documents
21519 foreach ($this->outlines as $key => $outline) {
21520 // check for extra pages (used for attachments)
21521 if (($this->page > $page_first) AND ($outline['p'] >= $this->numpages)) {
21522 $outline['p'] += ($this->page - $page_first);
21523 }
21524 if ($this->rtl) {
21525 $aligntext = 'R';
21526 $alignnum = 'L';
21527 } else {
21528 $aligntext = 'L';
21529 $alignnum = 'R';
21530 }
21531 if ($outline['l'] == 0) {
21532 $this->SetFont($fontfamily, $outline['s'].'B', $fontsize);
21533 } else {
21534 $this->SetFont($fontfamily, $outline['s'], $fontsize - $outline['l']);
21535 }
21536 $this->SetTextColorArray($outline['c']);
21537 // check for page break
21538 $this->checkPageBreak(2 * $this->getCellHeight($this->FontSize));
21539 // set margins and X position
21540 if (($this->page == $current_page) AND ($this->current_column == $current_column)) {
21541 $this->lMargin = $lmargin;
21542 $this->rMargin = $rmargin;
21543 } else {
21544 if ($this->current_column != $current_column) {
21545 if ($this->rtl) {
21546 $x_start = $this->w - $this->columns[$this->current_column]['x'];
21547 } else {
21548 $x_start = $this->columns[$this->current_column]['x'];
21549 }
21550 }
21551 $lmargin = $this->lMargin;
21552 $rmargin = $this->rMargin;
21553 $current_page = $this->page;
21554 $current_column = $this->current_column;
21555 }
21556 $this->SetX($x_start);
21557 $indent = ($spacer * $outline['l']);
21558 if ($this->rtl) {
21559 $this->x -= $indent;
21560 $this->rMargin = $this->w - $this->x;
21561 } else {
21562 $this->x += $indent;
21563 $this->lMargin = $this->x;
21564 }
21565 $link = $this->AddLink();
21566 $this->SetLink($link, $outline['y'], $outline['p']);
21567 // write the text
21568 if ($this->rtl) {
21569 $txt = ' '.$outline['t'];
21570 } else {
21571 $txt = $outline['t'].' ';
21572 }
21573 $this->Write(0, $txt, $link, false, $aligntext, false, 0, false, false, 0, $numwidth, '');
21574 if ($this->rtl) {
21575 $tw = $this->x - $this->lMargin;
21576 } else {
21577 $tw = $this->w - $this->rMargin - $this->x;
21578 }
21579 $this->SetFont($numbersfont, $fontstyle, $fontsize);
21580 if (TCPDF_STATIC::empty_string($page)) {
21581 $pagenum = $outline['p'];
21582 } else {
21583 // placemark to be replaced with the correct number
21584 $pagenum = '{#'.($outline['p']).'}';
21585 if ($this->isUnicodeFont()) {
21586 $pagenum = '{'.$pagenum.'}';
21587 }
21588 $maxpage = max($maxpage, $outline['p']);
21589 }
21590 $fw = ($tw - $this->GetStringWidth($pagenum.$filler));
21591 $wfiller = $this->GetStringWidth($filler);
21592 if ($wfiller > 0) {
21593 $numfills = floor($fw / $wfiller);
21594 } else {
21595 $numfills = 0;
21596 }
21597 if ($numfills > 0) {
21598 $rowfill = str_repeat($filler, $numfills);
21599 } else {
21600 $rowfill = '';
21601 }
21602 if ($this->rtl) {
21603 $pagenum = $pagenum.$gap.$rowfill;
21604 } else {
21605 $pagenum = $rowfill.$gap.$pagenum;
21606 }
21607 // write the number
21608 $this->Cell($tw, 0, $pagenum, 0, 1, $alignnum, 0, $link, 0);
21609 }
21610 $page_last = $this->getPage();
21611 $numpages = ($page_last - $page_first + 1);
21612 // account for booklet mode
21613 if ($this->booklet) {
21614 // check if a blank page is required before TOC
21615 $page_fill_start = ((($page_first % 2) == 0) XOR (($page % 2) == 0));
21616 $page_fill_end = (!((($numpages % 2) == 0) XOR ($page_fill_start)));
21617 if ($page_fill_start) {
21618 // add a page at the end (to be moved before TOC)
21619 $this->addPage();
21620 ++$page_last;
21621 ++$numpages;
21622 }
21623 if ($page_fill_end) {
21624 // add a page at the end
21625 $this->addPage();
21626 ++$page_last;
21627 ++$numpages;
21628 }
21629 }
21630 $maxpage = max($maxpage, $page_last);
21631 if (!TCPDF_STATIC::empty_string($page)) {
21632 for ($p = $page_first; $p <= $page_last; ++$p) {
21633 // get page data
21634 $temppage = $this->getPageBuffer($p);
21635 for ($n = 1; $n <= $maxpage; ++$n) {
21636 // update page numbers
21637 $a = '{#'.$n.'}';
21638 // get page number aliases
21639 $pnalias = $this->getInternalPageNumberAliases($a);
21640 // calculate replacement number
21641 if (($n >= $page) AND ($n <= $this->numpages)) {
21642 $np = $n + $numpages;
21643 } else {
21644 $np = $n;
21645 }
21646 $na = TCPDF_STATIC::formatTOCPageNumber(($this->starting_page_number + $np - 1));
21647 $nu = TCPDF_FONTS::UTF8ToUTF16BE($na, false, $this->isunicode, $this->CurrentFont);
21648 // replace aliases with numbers
21649 foreach ($pnalias['u'] as $u) {
21650 $sfill = str_repeat($filler, max(0, (strlen($u) - strlen($nu.' '))));
21651 if ($this->rtl) {
21652 $nr = $nu.TCPDF_FONTS::UTF8ToUTF16BE(' '.$sfill, false, $this->isunicode, $this->CurrentFont);
21653 } else {
21654 $nr = TCPDF_FONTS::UTF8ToUTF16BE($sfill.' ', false, $this->isunicode, $this->CurrentFont).$nu;
21655 }
21656 $temppage = str_replace($u, $nr, $temppage);
21657 }
21658 foreach ($pnalias['a'] as $a) {
21659 $sfill = str_repeat($filler, max(0, (strlen($a) - strlen($na.' '))));
21660 if ($this->rtl) {
21661 $nr = $na.' '.$sfill;
21662 } else {
21663 $nr = $sfill.' '.$na;
21664 }
21665 $temppage = str_replace($a, $nr, $temppage);
21666 }
21667 }
21668 // save changes
21669 $this->setPageBuffer($p, $temppage);
21670 }
21671 // move pages
21672 $this->Bookmark($toc_name, 0, 0, $page_first, $style, $color);
21673 if ($page_fill_start) {
21674 $this->movePage($page_last, $page_first);
21675 }
21676 for ($i = 0; $i < $numpages; ++$i) {
21677 $this->movePage($page_last, $page);
21678 }
21679 }
21680 }
21681
21682 /**
21683 * Output a Table Of Content Index (TOC) using HTML templates.
21684 * This method must be called after all Bookmarks were set.
21685 * Before calling this method you have to open the page using the addTOCPage() method.
21686 * After calling this method you have to call endTOCPage() to close the TOC page.
21687 * @param $page (int) page number where this TOC should be inserted (leave empty for current page).
21688 * @param $toc_name (string) name to use for TOC bookmark.
21689 * @param $templates (array) array of html templates. Use: "#TOC_DESCRIPTION#" for bookmark title, "#TOC_PAGE_NUMBER#" for page number.
21690 * @param $correct_align (boolean) if true correct the number alignment (numbers must be in monospaced font like courier and right aligned on LTR, or left aligned on RTL)
21691 * @param $style (string) Font style for title: B = Bold, I = Italic, BI = Bold + Italic.
21692 * @param $color (array) RGB color array for title (values from 0 to 255).
21693 * @public
21694 * @author Nicola Asuni
21695 * @since 5.0.001 (2010-05-06)
21696 * @see addTOCPage(), endTOCPage(), addTOC()
21697 */
21698 public function addHTMLTOC($page='', $toc_name='TOC', $templates=array(), $correct_align=true, $style='', $color=array(0,0,0)) {
21699 $filler = ' ';
21700 $prev_htmlLinkColorArray = $this->htmlLinkColorArray;
21701 $prev_htmlLinkFontStyle = $this->htmlLinkFontStyle;
21702 // set new style for link
21703 $this->htmlLinkColorArray = array();
21704 $this->htmlLinkFontStyle = '';
21705 $page_first = $this->getPage();
21706 $page_fill_start = false;
21707 $page_fill_end = false;
21708 // get the font type used for numbers in each template
21709 $current_font = $this->FontFamily;
21710 foreach ($templates as $level => $html) {
21711 $dom = $this->getHtmlDomArray($html);
21712 foreach ($dom as $key => $value) {
21713 if ($value['value'] == '#TOC_PAGE_NUMBER#') {
21714 $this->SetFont($dom[($key - 1)]['fontname']);
21715 $templates['F'.$level] = $this->isUnicodeFont();
21716 }
21717 }
21718 }
21719 $this->SetFont($current_font);
21720 $maxpage = 0; //used for pages on attached documents
21721 foreach ($this->outlines as $key => $outline) {
21722 // get HTML template
21723 $row = $templates[$outline['l']];
21724 if (TCPDF_STATIC::empty_string($page)) {
21725 $pagenum = $outline['p'];
21726 } else {
21727 // placemark to be replaced with the correct number
21728 $pagenum = '{#'.($outline['p']).'}';
21729 if ($templates['F'.$outline['l']]) {
21730 $pagenum = '{'.$pagenum.'}';
21731 }
21732 $maxpage = max($maxpage, $outline['p']);
21733 }
21734 // replace templates with current values
21735 $row = str_replace('#TOC_DESCRIPTION#', $outline['t'], $row);
21736 $row = str_replace('#TOC_PAGE_NUMBER#', $pagenum, $row);
21737 // add link to page
21738 $row = '<a href="#'.$outline['p'].','.$outline['y'].'">'.$row.'</a>';
21739 // write bookmark entry
21740 $this->writeHTML($row, false, false, true, false, '');
21741 }
21742 // restore link styles
21743 $this->htmlLinkColorArray = $prev_htmlLinkColorArray;
21744 $this->htmlLinkFontStyle = $prev_htmlLinkFontStyle;
21745 // move TOC page and replace numbers
21746 $page_last = $this->getPage();
21747 $numpages = ($page_last - $page_first + 1);
21748 // account for booklet mode
21749 if ($this->booklet) {
21750 // check if a blank page is required before TOC
21751 $page_fill_start = ((($page_first % 2) == 0) XOR (($page % 2) == 0));
21752 $page_fill_end = (!((($numpages % 2) == 0) XOR ($page_fill_start)));
21753 if ($page_fill_start) {
21754 // add a page at the end (to be moved before TOC)
21755 $this->addPage();
21756 ++$page_last;
21757 ++$numpages;
21758 }
21759 if ($page_fill_end) {
21760 // add a page at the end
21761 $this->addPage();
21762 ++$page_last;
21763 ++$numpages;
21764 }
21765 }
21766 $maxpage = max($maxpage, $page_last);
21767 if (!TCPDF_STATIC::empty_string($page)) {
21768 for ($p = $page_first; $p <= $page_last; ++$p) {
21769 // get page data
21770 $temppage = $this->getPageBuffer($p);
21771 for ($n = 1; $n <= $maxpage; ++$n) {
21772 // update page numbers
21773 $a = '{#'.$n.'}';
21774 // get page number aliases
21775 $pnalias = $this->getInternalPageNumberAliases($a);
21776 // calculate replacement number
21777 if ($n >= $page) {
21778 $np = $n + $numpages;
21779 } else {
21780 $np = $n;
21781 }
21782 $na = TCPDF_STATIC::formatTOCPageNumber(($this->starting_page_number + $np - 1));
21783 $nu = TCPDF_FONTS::UTF8ToUTF16BE($na, false, $this->isunicode, $this->CurrentFont);
21784 // replace aliases with numbers
21785 foreach ($pnalias['u'] as $u) {
21786 if ($correct_align) {
21787 $sfill = str_repeat($filler, (strlen($u) - strlen($nu.' ')));
21788 if ($this->rtl) {
21789 $nr = $nu.TCPDF_FONTS::UTF8ToUTF16BE(' '.$sfill, false, $this->isunicode, $this->CurrentFont);
21790 } else {
21791 $nr = TCPDF_FONTS::UTF8ToUTF16BE($sfill.' ', false, $this->isunicode, $this->CurrentFont).$nu;
21792 }
21793 } else {
21794 $nr = $nu;
21795 }
21796 $temppage = str_replace($u, $nr, $temppage);
21797 }
21798 foreach ($pnalias['a'] as $a) {
21799 if ($correct_align) {
21800 $sfill = str_repeat($filler, (strlen($a) - strlen($na.' ')));
21801 if ($this->rtl) {
21802 $nr = $na.' '.$sfill;
21803 } else {
21804 $nr = $sfill.' '.$na;
21805 }
21806 } else {
21807 $nr = $na;
21808 }
21809 $temppage = str_replace($a, $nr, $temppage);
21810 }
21811 }
21812 // save changes
21813 $this->setPageBuffer($p, $temppage);
21814 }
21815 // move pages
21816 $this->Bookmark($toc_name, 0, 0, $page_first, $style, $color);
21817 if ($page_fill_start) {
21818 $this->movePage($page_last, $page_first);
21819 }
21820 for ($i = 0; $i < $numpages; ++$i) {
21821 $this->movePage($page_last, $page);
21822 }
21823 }
21824 }
21825
21826 /**
21827 * Stores a copy of the current TCPDF object used for undo operation.
21828 * @public
21829 * @since 4.5.029 (2009-03-19)
21830 */
21831 public function startTransaction() {
21832 if (isset($this->objcopy)) {
21833 // remove previous copy
21834 $this->commitTransaction();
21835 }
21836 // record current page number and Y position
21837 $this->start_transaction_page = $this->page;
21838 $this->start_transaction_y = $this->y;
21839 // clone current object
21840 $this->objcopy = TCPDF_STATIC::objclone($this);
21841 }
21842
21843 /**
21844 * Delete the copy of the current TCPDF object used for undo operation.
21845 * @public
21846 * @since 4.5.029 (2009-03-19)
21847 */
21848 public function commitTransaction() {
21849 if (isset($this->objcopy)) {
21850 $this->objcopy->_destroy(true, true);
21851 unset($this->objcopy);
21852 }
21853 }
21854
21855 /**
21856 * This method allows to undo the latest transaction by returning the latest saved TCPDF object with startTransaction().
21857 * @param $self (boolean) if true restores current class object to previous state without the need of reassignment via the returned value.
21858 * @return TCPDF object.
21859 * @public
21860 * @since 4.5.029 (2009-03-19)
21861 */
21862 public function rollbackTransaction($self=false) {
21863 if (isset($this->objcopy)) {
21864 if (isset($this->objcopy->diskcache) AND $this->objcopy->diskcache) {
21865 // truncate files to previous values
21866 foreach ($this->objcopy->cache_file_length as $file => $length) {
21867 $file = substr($file, 1);
21868 $handle = fopen($file, 'r+');
21869 ftruncate($handle, $length);
21870 }
21871 }
21872 $this->_destroy(true, true);
21873 if ($self) {
21874 $objvars = get_object_vars($this->objcopy);
21875 foreach ($objvars as $key => $value) {
21876 $this->$key = $value;
21877 }
21878 }
21879 return $this->objcopy;
21880 }
21881 return $this;
21882 }
21883
21884 // --- MULTI COLUMNS METHODS -----------------------
21885
21886 /**
21887 * Set multiple columns of the same size
21888 * @param $numcols (int) number of columns (set to zero to disable columns mode)
21889 * @param $width (int) column width
21890 * @param $y (int) column starting Y position (leave empty for current Y position)
21891 * @public
21892 * @since 4.9.001 (2010-03-28)
21893 */
21894 public function setEqualColumns($numcols=0, $width=0, $y='') {
21895 $this->columns = array();
21896 if ($numcols < 2) {
21897 $numcols = 0;
21898 $this->columns = array();
21899 } else {
21900 // maximum column width
21901 $maxwidth = ($this->w - $this->original_lMargin - $this->original_rMargin) / $numcols;
21902 if (($width == 0) OR ($width > $maxwidth)) {
21903 $width = $maxwidth;
21904 }
21905 if (TCPDF_STATIC::empty_string($y)) {
21906 $y = $this->y;
21907 }
21908 // space between columns
21909 $space = (($this->w - $this->original_lMargin - $this->original_rMargin - ($numcols * $width)) / ($numcols - 1));
21910 // fill the columns array (with, space, starting Y position)
21911 for ($i = 0; $i < $numcols; ++$i) {
21912 $this->columns[$i] = array('w' => $width, 's' => $space, 'y' => $y);
21913 }
21914 }
21915 $this->num_columns = $numcols;
21916 $this->current_column = 0;
21917 $this->column_start_page = $this->page;
21918 $this->selectColumn(0);
21919 }
21920
21921 /**
21922 * Remove columns and reset page margins.
21923 * @public
21924 * @since 5.9.072 (2011-04-26)
21925 */
21926 public function resetColumns() {
21927 $this->lMargin = $this->original_lMargin;
21928 $this->rMargin = $this->original_rMargin;
21929 $this->setEqualColumns();
21930 }
21931
21932 /**
21933 * Set columns array.
21934 * Each column is represented by an array of arrays with the following keys: (w = width, s = space between columns, y = column top position).
21935 * @param $columns (array)
21936 * @public
21937 * @since 4.9.001 (2010-03-28)
21938 */
21939 public function setColumnsArray($columns) {
21940 $this->columns = $columns;
21941 $this->num_columns = count($columns);
21942 $this->current_column = 0;
21943 $this->column_start_page = $this->page;
21944 $this->selectColumn(0);
21945 }
21946
21947 /**
21948 * Set position at a given column
21949 * @param $col (int) column number (from 0 to getNumberOfColumns()-1); empty string = current column.
21950 * @public
21951 * @since 4.9.001 (2010-03-28)
21952 */
21953 public function selectColumn($col='') {
21954 if (is_string($col)) {
21955 $col = $this->current_column;
21956 } elseif ($col >= $this->num_columns) {
21957 $col = 0;
21958 }
21959 $xshift = array('x' => 0, 's' => array('H' => 0, 'V' => 0), 'p' => array('L' => 0, 'T' => 0, 'R' => 0, 'B' => 0));
21960 $enable_thead = false;
21961 if ($this->num_columns > 1) {
21962 if ($col != $this->current_column) {
21963 // move Y pointer at the top of the column
21964 if ($this->column_start_page == $this->page) {
21965 $this->y = $this->columns[$col]['y'];
21966 } else {
21967 $this->y = $this->tMargin;
21968 }
21969 // Avoid to write table headers more than once
21970 if (($this->page > $this->maxselcol['page']) OR (($this->page == $this->maxselcol['page']) AND ($col > $this->maxselcol['column']))) {
21971 $enable_thead = true;
21972 $this->maxselcol['page'] = $this->page;
21973 $this->maxselcol['column'] = $col;
21974 }
21975 }
21976 $xshift = $this->colxshift;
21977 // set X position of the current column by case
21978 $listindent = ($this->listindentlevel * $this->listindent);
21979 // calculate column X position
21980 $colpos = 0;
21981 for ($i = 0; $i < $col; ++$i) {
21982 $colpos += ($this->columns[$i]['w'] + $this->columns[$i]['s']);
21983 }
21984 if ($this->rtl) {
21985 $x = $this->w - $this->original_rMargin - $colpos;
21986 $this->rMargin = ($this->w - $x + $listindent);
21987 $this->lMargin = ($x - $this->columns[$col]['w']);
21988 $this->x = $x - $listindent;
21989 } else {
21990 $x = $this->original_lMargin + $colpos;
21991 $this->lMargin = ($x + $listindent);
21992 $this->rMargin = ($this->w - $x - $this->columns[$col]['w']);
21993 $this->x = $x + $listindent;
21994 }
21995 $this->columns[$col]['x'] = $x;
21996 }
21997 $this->current_column = $col;
21998 // fix for HTML mode
21999 $this->newline = true;
22000 // print HTML table header (if any)
22001 if ((!TCPDF_STATIC::empty_string($this->thead)) AND (!$this->inthead)) {
22002 if ($enable_thead) {
22003 // print table header
22004 $this->writeHTML($this->thead, false, false, false, false, '');
22005 $this->y += $xshift['s']['V'];
22006 // store end of header position
22007 if (!isset($this->columns[$col]['th'])) {
22008 $this->columns[$col]['th'] = array();
22009 }
22010 $this->columns[$col]['th']['\''.$this->page.'\''] = $this->y;
22011 $this->lasth = 0;
22012 } elseif (isset($this->columns[$col]['th']['\''.$this->page.'\''])) {
22013 $this->y = $this->columns[$col]['th']['\''.$this->page.'\''];
22014 }
22015 }
22016 // account for an html table cell over multiple columns
22017 if ($this->rtl) {
22018 $this->rMargin += $xshift['x'];
22019 $this->x -= ($xshift['x'] + $xshift['p']['R']);
22020 } else {
22021 $this->lMargin += $xshift['x'];
22022 $this->x += $xshift['x'] + $xshift['p']['L'];
22023 }
22024 }
22025
22026 /**
22027 * Return the current column number
22028 * @return int current column number
22029 * @public
22030 * @since 5.5.011 (2010-07-08)
22031 */
22032 public function getColumn() {
22033 return $this->current_column;
22034 }
22035
22036 /**
22037 * Return the current number of columns.
22038 * @return int number of columns
22039 * @public
22040 * @since 5.8.018 (2010-08-25)
22041 */
22042 public function getNumberOfColumns() {
22043 return $this->num_columns;
22044 }
22045
22046 /**
22047 * Set Text rendering mode.
22048 * @param $stroke (int) outline size in user units (0 = disable).
22049 * @param $fill (boolean) if true fills the text (default).
22050 * @param $clip (boolean) if true activate clipping mode
22051 * @public
22052 * @since 4.9.008 (2009-04-02)
22053 */
22054 public function setTextRenderingMode($stroke=0, $fill=true, $clip=false) {
22055 // Ref.: PDF 32000-1:2008 - 9.3.6 Text Rendering Mode
22056 // convert text rendering parameters
22057 if ($stroke < 0) {
22058 $stroke = 0;
22059 }
22060 if ($fill === true) {
22061 if ($stroke > 0) {
22062 if ($clip === true) {
22063 // Fill, then stroke text and add to path for clipping
22064 $textrendermode = 6;
22065 } else {
22066 // Fill, then stroke text
22067 $textrendermode = 2;
22068 }
22069 $textstrokewidth = $stroke;
22070 } else {
22071 if ($clip === true) {
22072 // Fill text and add to path for clipping
22073 $textrendermode = 4;
22074 } else {
22075 // Fill text
22076 $textrendermode = 0;
22077 }
22078 }
22079 } else {
22080 if ($stroke > 0) {
22081 if ($clip === true) {
22082 // Stroke text and add to path for clipping
22083 $textrendermode = 5;
22084 } else {
22085 // Stroke text
22086 $textrendermode = 1;
22087 }
22088 $textstrokewidth = $stroke;
22089 } else {
22090 if ($clip === true) {
22091 // Add text to path for clipping
22092 $textrendermode = 7;
22093 } else {
22094 // Neither fill nor stroke text (invisible)
22095 $textrendermode = 3;
22096 }
22097 }
22098 }
22099 $this->textrendermode = $textrendermode;
22100 $this->textstrokewidth = $stroke;
22101 }
22102
22103 /**
22104 * Set parameters for drop shadow effect for text.
22105 * @param $params (array) Array of parameters: enabled (boolean) set to true to enable shadow; depth_w (float) shadow width in user units; depth_h (float) shadow height in user units; color (array) shadow color or false to use the stroke color; opacity (float) Alpha value: real value from 0 (transparent) to 1 (opaque); blend_mode (string) blend mode, one of the following: Normal, Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, ColorBurn, HardLight, SoftLight, Difference, Exclusion, Hue, Saturation, Color, Luminosity.
22106 * @since 5.9.174 (2012-07-25)
22107 * @public
22108 */
22109 public function setTextShadow($params=array('enabled'=>false, 'depth_w'=>0, 'depth_h'=>0, 'color'=>false, 'opacity'=>1, 'blend_mode'=>'Normal')) {
22110 if (isset($params['enabled'])) {
22111 $this->txtshadow['enabled'] = $params['enabled']?true:false;
22112 } else {
22113 $this->txtshadow['enabled'] = false;
22114 }
22115 if (isset($params['depth_w'])) {
22116 $this->txtshadow['depth_w'] = floatval($params['depth_w']);
22117 } else {
22118 $this->txtshadow['depth_w'] = 0;
22119 }
22120 if (isset($params['depth_h'])) {
22121 $this->txtshadow['depth_h'] = floatval($params['depth_h']);
22122 } else {
22123 $this->txtshadow['depth_h'] = 0;
22124 }
22125 if (isset($params['color']) AND ($params['color'] !== false) AND is_array($params['color'])) {
22126 $this->txtshadow['color'] = $params['color'];
22127 } else {
22128 $this->txtshadow['color'] = $this->strokecolor;
22129 }
22130 if (isset($params['opacity'])) {
22131 $this->txtshadow['opacity'] = min(1, max(0, floatval($params['opacity'])));
22132 } else {
22133 $this->txtshadow['opacity'] = 1;
22134 }
22135 if (isset($params['blend_mode']) AND in_array($params['blend_mode'], array('Normal', 'Multiply', 'Screen', 'Overlay', 'Darken', 'Lighten', 'ColorDodge', 'ColorBurn', 'HardLight', 'SoftLight', 'Difference', 'Exclusion', 'Hue', 'Saturation', 'Color', 'Luminosity'))) {
22136 $this->txtshadow['blend_mode'] = $params['blend_mode'];
22137 } else {
22138 $this->txtshadow['blend_mode'] = 'Normal';
22139 }
22140 if ((($this->txtshadow['depth_w'] == 0) AND ($this->txtshadow['depth_h'] == 0)) OR ($this->txtshadow['opacity'] == 0)) {
22141 $this->txtshadow['enabled'] = false;
22142 }
22143 }
22144
22145 /**
22146 * Return the text shadow parameters array.
22147 * @return Array of parameters.
22148 * @since 5.9.174 (2012-07-25)
22149 * @public
22150 */
22151 public function getTextShadow() {
22152 return $this->txtshadow;
22153 }
22154
22155 /**
22156 * Returns an array of chars containing soft hyphens.
22157 * @param $word (array) array of chars
22158 * @param $patterns (array) Array of hypenation patterns.
22159 * @param $dictionary (array) Array of words to be returned without applying the hyphenation algoritm.
22160 * @param $leftmin (int) Minimum number of character to leave on the left of the word without applying the hyphens.
22161 * @param $rightmin (int) Minimum number of character to leave on the right of the word without applying the hyphens.
22162 * @param $charmin (int) Minimum word length to apply the hyphenation algoritm.
22163 * @param $charmax (int) Maximum length of broken piece of word.
22164 * @return array text with soft hyphens
22165 * @author Nicola Asuni
22166 * @since 4.9.012 (2010-04-12)
22167 * @protected
22168 */
22169 protected function hyphenateWord($word, $patterns, $dictionary=array(), $leftmin=1, $rightmin=2, $charmin=1, $charmax=8) {
22170 $hyphenword = array(); // hyphens positions
22171 $numchars = count($word);
22172 if ($numchars <= $charmin) {
22173 return $word;
22174 }
22175 $word_string = TCPDF_FONTS::UTF8ArrSubString($word, '', '', $this->isunicode);
22176 // some words will be returned as-is
22177 $pattern = '/^([a-zA-Z0-9_\.\-]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/';
22178 if (preg_match($pattern, $word_string) > 0) {
22179 // email
22180 return $word;
22181 }
22182 $pattern = '/(([a-zA-Z0-9\-]+\.)?)((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/';
22183 if (preg_match($pattern, $word_string) > 0) {
22184 // URL
22185 return $word;
22186 }
22187 if (isset($dictionary[$word_string])) {
22188 return TCPDF_FONTS::UTF8StringToArray($dictionary[$word_string], $this->isunicode, $this->CurrentFont);
22189 }
22190 // surround word with '_' characters
22191 $tmpword = array_merge(array(46), $word, array(46));
22192 $tmpnumchars = $numchars + 2;
22193 $maxpos = $tmpnumchars - $charmin;
22194 for ($pos = 0; $pos < $maxpos; ++$pos) {
22195 $imax = min(($tmpnumchars - $pos), $charmax);
22196 for ($i = $charmin; $i <= $imax; ++$i) {
22197 $subword = strtolower(TCPDF_FONTS::UTF8ArrSubString($tmpword, $pos, ($pos + $i), $this->isunicode));
22198 if (isset($patterns[$subword])) {
22199 $pattern = TCPDF_FONTS::UTF8StringToArray($patterns[$subword], $this->isunicode, $this->CurrentFont);
22200 $pattern_length = count($pattern);
22201 $digits = 1;
22202 for ($j = 0; $j < $pattern_length; ++$j) {
22203 // check if $pattern[$j] is a number = hyphenation level (only numbers from 1 to 5 are valid)
22204 if (($pattern[$j] >= 48) AND ($pattern[$j] <= 57)) {
22205 if ($j == 0) {
22206 $zero = $pos - 1;
22207 } else {
22208 $zero = $pos + $j - $digits;
22209 }
22210 // get hyphenation level
22211 $level = ($pattern[$j] - 48);
22212 // if two levels from two different patterns match at the same point, the higher one is selected.
22213 if (!isset($hyphenword[$zero]) OR ($hyphenword[$zero] < $level)) {
22214 $hyphenword[$zero] = $level;
22215 }
22216 ++$digits;
22217 }
22218 }
22219 }
22220 }
22221 }
22222 $inserted = 0;
22223 $maxpos = $numchars - $rightmin;
22224 for ($i = $leftmin; $i <= $maxpos; ++$i) {
22225 // only odd levels indicate allowed hyphenation points
22226 if (isset($hyphenword[$i]) AND (($hyphenword[$i] % 2) != 0)) {
22227 // 173 = soft hyphen character
22228 array_splice($word, $i + $inserted, 0, 173);
22229 ++$inserted;
22230 }
22231 }
22232 return $word;
22233 }
22234
22235 /**
22236 * Returns text with soft hyphens.
22237 * @param $text (string) text to process
22238 * @param $patterns (mixed) Array of hypenation patterns or a TEX file containing hypenation patterns. TEX patterns can be downloaded from http://www.ctan.org/tex-archive/language/hyph-utf8/tex/generic/hyph-utf8/patterns/
22239 * @param $dictionary (array) Array of words to be returned without applying the hyphenation algoritm.
22240 * @param $leftmin (int) Minimum number of character to leave on the left of the word without applying the hyphens.
22241 * @param $rightmin (int) Minimum number of character to leave on the right of the word without applying the hyphens.
22242 * @param $charmin (int) Minimum word length to apply the hyphenation algoritm.
22243 * @param $charmax (int) Maximum length of broken piece of word.
22244 * @return array text with soft hyphens
22245 * @author Nicola Asuni
22246 * @since 4.9.012 (2010-04-12)
22247 * @public
22248 */
22249 public function hyphenateText($text, $patterns, $dictionary=array(), $leftmin=1, $rightmin=2, $charmin=1, $charmax=8) {
22250 $text = $this->unhtmlentities($text);
22251 $word = array(); // last word
22252 $txtarr = array(); // text to be returned
22253 $intag = false; // true if we are inside an HTML tag
22254 $skip = false; // true to skip hyphenation
22255 if (!is_array($patterns)) {
22256 $patterns = TCPDF_STATIC::getHyphenPatternsFromTEX($patterns);
22257 }
22258 // get array of characters
22259 $unichars = TCPDF_FONTS::UTF8StringToArray($text, $this->isunicode, $this->CurrentFont);
22260 // for each char
22261 foreach ($unichars as $char) {
22262 if ((!$intag) AND (!$skip) AND TCPDF_FONT_DATA::$uni_type[$char] == 'L') {
22263 // letter character
22264 $word[] = $char;
22265 } else {
22266 // other type of character
22267 if (!TCPDF_STATIC::empty_string($word)) {
22268 // hypenate the word
22269 $txtarr = array_merge($txtarr, $this->hyphenateWord($word, $patterns, $dictionary, $leftmin, $rightmin, $charmin, $charmax));
22270 $word = array();
22271 }
22272 $txtarr[] = $char;
22273 if (chr($char) == '<') {
22274 // we are inside an HTML tag
22275 $intag = true;
22276 } elseif ($intag AND (chr($char) == '>')) {
22277 // end of HTML tag
22278 $intag = false;
22279 // check for style tag
22280 $expected = array(115, 116, 121, 108, 101); // = 'style'
22281 $current = array_slice($txtarr, -6, 5); // last 5 chars
22282 $compare = array_diff($expected, $current);
22283 if (empty($compare)) {
22284 // check if it is a closing tag
22285 $expected = array(47); // = '/'
22286 $current = array_slice($txtarr, -7, 1);
22287 $compare = array_diff($expected, $current);
22288 if (empty($compare)) {
22289 // closing style tag
22290 $skip = false;
22291 } else {
22292 // opening style tag
22293 $skip = true;
22294 }
22295 }
22296 }
22297 }
22298 }
22299 if (!TCPDF_STATIC::empty_string($word)) {
22300 // hypenate the word
22301 $txtarr = array_merge($txtarr, $this->hyphenateWord($word, $patterns, $dictionary, $leftmin, $rightmin, $charmin, $charmax));
22302 }
22303 // convert char array to string and return
22304 return TCPDF_FONTS::UTF8ArrSubString($txtarr, '', '', $this->isunicode);
22305 }
22306
22307 /**
22308 * Enable/disable rasterization of vector images using ImageMagick library.
22309 * @param $mode (boolean) if true enable rasterization, false otherwise.
22310 * @public
22311 * @since 5.0.000 (2010-04-27)
22312 */
22313 public function setRasterizeVectorImages($mode) {
22314 $this->rasterize_vector_images = $mode;
22315 }
22316
22317 /**
22318 * Enable or disable default option for font subsetting.
22319 * @param $enable (boolean) if true enable font subsetting by default.
22320 * @author Nicola Asuni
22321 * @public
22322 * @since 5.3.002 (2010-06-07)
22323 */
22324 public function setFontSubsetting($enable=true) {
22325 if ($this->pdfa_mode) {
22326 $this->font_subsetting = false;
22327 } else {
22328 $this->font_subsetting = $enable ? true : false;
22329 }
22330 }
22331
22332 /**
22333 * Return the default option for font subsetting.
22334 * @return boolean default font subsetting state.
22335 * @author Nicola Asuni
22336 * @public
22337 * @since 5.3.002 (2010-06-07)
22338 */
22339 public function getFontSubsetting() {
22340 return $this->font_subsetting;
22341 }
22342
22343 /**
22344 * Left trim the input string
22345 * @param $str (string) string to trim
22346 * @param $replace (string) string that replace spaces.
22347 * @return left trimmed string
22348 * @author Nicola Asuni
22349 * @public
22350 * @since 5.8.000 (2010-08-11)
22351 */
22352 public function stringLeftTrim($str, $replace='') {
22353 return preg_replace('/^'.$this->re_space['p'].'+/'.$this->re_space['m'], $replace, $str);
22354 }
22355
22356 /**
22357 * Right trim the input string
22358 * @param $str (string) string to trim
22359 * @param $replace (string) string that replace spaces.
22360 * @return right trimmed string
22361 * @author Nicola Asuni
22362 * @public
22363 * @since 5.8.000 (2010-08-11)
22364 */
22365 public function stringRightTrim($str, $replace='') {
22366 return preg_replace('/'.$this->re_space['p'].'+$/'.$this->re_space['m'], $replace, $str);
22367 }
22368
22369 /**
22370 * Trim the input string
22371 * @param $str (string) string to trim
22372 * @param $replace (string) string that replace spaces.
22373 * @return trimmed string
22374 * @author Nicola Asuni
22375 * @public
22376 * @since 5.8.000 (2010-08-11)
22377 */
22378 public function stringTrim($str, $replace='') {
22379 $str = $this->stringLeftTrim($str, $replace);
22380 $str = $this->stringRightTrim($str, $replace);
22381 return $str;
22382 }
22383
22384 /**
22385 * Return true if the current font is unicode type.
22386 * @return true for unicode font, false otherwise.
22387 * @author Nicola Asuni
22388 * @public
22389 * @since 5.8.002 (2010-08-14)
22390 */
22391 public function isUnicodeFont() {
22392 return (($this->CurrentFont['type'] == 'TrueTypeUnicode') OR ($this->CurrentFont['type'] == 'cidfont0'));
22393 }
22394
22395 /**
22396 * Return normalized font name
22397 * @param $fontfamily (string) property string containing font family names
22398 * @return string normalized font name
22399 * @author Nicola Asuni
22400 * @public
22401 * @since 5.8.004 (2010-08-17)
22402 */
22403 public function getFontFamilyName($fontfamily) {
22404 // remove spaces and symbols
22405 $fontfamily = preg_replace('/[^a-z0-9_\,]/', '', strtolower($fontfamily));
22406 // extract all font names
22407 $fontslist = preg_split('/[,]/', $fontfamily);
22408 // find first valid font name
22409 foreach ($fontslist as $font) {
22410 // replace font variations
22411 $font = preg_replace('/regular$/', '', $font);
22412 $font = preg_replace('/italic$/', 'I', $font);
22413 $font = preg_replace('/oblique$/', 'I', $font);
22414 $font = preg_replace('/bold([I]?)$/', 'B\\1', $font);
22415 // replace common family names and core fonts
22416 $pattern = array();
22417 $replacement = array();
22418 $pattern[] = '/^serif|^cursive|^fantasy|^timesnewroman/';
22419 $replacement[] = 'times';
22420 $pattern[] = '/^sansserif/';
22421 $replacement[] = 'helvetica';
22422 $pattern[] = '/^monospace/';
22423 $replacement[] = 'courier';
22424 $font = preg_replace($pattern, $replacement, $font);
22425 if (in_array(strtolower($font), $this->fontlist) OR in_array($font, $this->fontkeys)) {
22426 return $font;
22427 }
22428 }
22429 // return current font as default
22430 return $this->CurrentFont['fontkey'];
22431 }
22432
22433 /**
22434 * Start a new XObject Template.
22435 * An XObject Template is a PDF block that is a self-contained description of any sequence of graphics objects (including path objects, text objects, and sampled images).
22436 * An XObject Template may be painted multiple times, either on several pages or at several locations on the same page and produces the same results each time, subject only to the graphics state at the time it is invoked.
22437 * Note: X,Y coordinates will be reset to 0,0.
22438 * @param $w (int) Template width in user units (empty string or zero = page width less margins).
22439 * @param $h (int) Template height in user units (empty string or zero = page height less margins).
22440 * @param $group (mixed) Set transparency group. Can be a boolean value or an array specifying optional parameters: 'CS' (solour space name), 'I' (boolean flag to indicate isolated group) and 'K' (boolean flag to indicate knockout group).
22441 * @return int the XObject Template ID in case of success or false in case of error.
22442 * @author Nicola Asuni
22443 * @public
22444 * @since 5.8.017 (2010-08-24)
22445 * @see endTemplate(), printTemplate()
22446 */
22447 public function startTemplate($w=0, $h=0, $group=false) {
22448 if ($this->inxobj) {
22449 // we are already inside an XObject template
22450 return false;
22451 }
22452 $this->inxobj = true;
22453 ++$this->n;
22454 // XObject ID
22455 $this->xobjid = 'XT'.$this->n;
22456 // object ID
22457 $this->xobjects[$this->xobjid] = array('n' => $this->n);
22458 // store current graphic state
22459 $this->xobjects[$this->xobjid]['gvars'] = $this->getGraphicVars();
22460 // initialize data
22461 $this->xobjects[$this->xobjid]['intmrk'] = 0;
22462 $this->xobjects[$this->xobjid]['transfmrk'] = array();
22463 $this->xobjects[$this->xobjid]['outdata'] = '';
22464 $this->xobjects[$this->xobjid]['xobjects'] = array();
22465 $this->xobjects[$this->xobjid]['images'] = array();
22466 $this->xobjects[$this->xobjid]['fonts'] = array();
22467 $this->xobjects[$this->xobjid]['annotations'] = array();
22468 $this->xobjects[$this->xobjid]['extgstates'] = array();
22469 $this->xobjects[$this->xobjid]['gradients'] = array();
22470 $this->xobjects[$this->xobjid]['spot_colors'] = array();
22471 // set new environment
22472 $this->num_columns = 1;
22473 $this->current_column = 0;
22474 $this->SetAutoPageBreak(false);
22475 if (($w === '') OR ($w <= 0)) {
22476 $w = $this->w - $this->lMargin - $this->rMargin;
22477 }
22478 if (($h === '') OR ($h <= 0)) {
22479 $h = $this->h - $this->tMargin - $this->bMargin;
22480 }
22481 $this->xobjects[$this->xobjid]['x'] = 0;
22482 $this->xobjects[$this->xobjid]['y'] = 0;
22483 $this->xobjects[$this->xobjid]['w'] = $w;
22484 $this->xobjects[$this->xobjid]['h'] = $h;
22485 $this->w = $w;
22486 $this->h = $h;
22487 $this->wPt = $this->w * $this->k;
22488 $this->hPt = $this->h * $this->k;
22489 $this->fwPt = $this->wPt;
22490 $this->fhPt = $this->hPt;
22491 $this->x = 0;
22492 $this->y = 0;
22493 $this->lMargin = 0;
22494 $this->rMargin = 0;
22495 $this->tMargin = 0;
22496 $this->bMargin = 0;
22497 // set group mode
22498 $this->xobjects[$this->xobjid]['group'] = $group;
22499 return $this->xobjid;
22500 }
22501
22502 /**
22503 * End the current XObject Template started with startTemplate() and restore the previous graphic state.
22504 * An XObject Template is a PDF block that is a self-contained description of any sequence of graphics objects (including path objects, text objects, and sampled images).
22505 * An XObject Template may be painted multiple times, either on several pages or at several locations on the same page and produces the same results each time, subject only to the graphics state at the time it is invoked.
22506 * @return int the XObject Template ID in case of success or false in case of error.
22507 * @author Nicola Asuni
22508 * @public
22509 * @since 5.8.017 (2010-08-24)
22510 * @see startTemplate(), printTemplate()
22511 */
22512 public function endTemplate() {
22513 if (!$this->inxobj) {
22514 // we are not inside a template
22515 return false;
22516 }
22517 $this->inxobj = false;
22518 // restore previous graphic state
22519 $this->setGraphicVars($this->xobjects[$this->xobjid]['gvars'], true);
22520 return $this->xobjid;
22521 }
22522
22523 /**
22524 * Print an XObject Template.
22525 * You can print an XObject Template inside the currently opened Template.
22526 * An XObject Template is a PDF block that is a self-contained description of any sequence of graphics objects (including path objects, text objects, and sampled images).
22527 * An XObject Template may be painted multiple times, either on several pages or at several locations on the same page and produces the same results each time, subject only to the graphics state at the time it is invoked.
22528 * @param $id (string) The ID of XObject Template to print.
22529 * @param $x (int) X position in user units (empty string = current x position)
22530 * @param $y (int) Y position in user units (empty string = current y position)
22531 * @param $w (int) Width in user units (zero = remaining page width)
22532 * @param $h (int) Height in user units (zero = remaining page height)
22533 * @param $align (string) Indicates the alignment of the pointer next to template insertion relative to template height. The value can be:<ul><li>T: top-right for LTR or top-left for RTL</li><li>M: middle-right for LTR or middle-left for RTL</li><li>B: bottom-right for LTR or bottom-left for RTL</li><li>N: next line</li></ul>
22534 * @param $palign (string) Allows to center or align the template on the current line. Possible values are:<ul><li>L : left align</li><li>C : center</li><li>R : right align</li><li>'' : empty string : left for LTR or right for RTL</li></ul>
22535 * @param $fitonpage (boolean) If true the template is resized to not exceed page dimensions.
22536 * @author Nicola Asuni
22537 * @public
22538 * @since 5.8.017 (2010-08-24)
22539 * @see startTemplate(), endTemplate()
22540 */
22541 public function printTemplate($id, $x='', $y='', $w=0, $h=0, $align='', $palign='', $fitonpage=false) {
22542 if ($this->state != 2) {
22543 return;
22544 }
22545 if (!isset($this->xobjects[$id])) {
22546 $this->Error('The XObject Template \''.$id.'\' doesn\'t exist!');
22547 }
22548 if ($this->inxobj) {
22549 if ($id == $this->xobjid) {
22550 // close current template
22551 $this->endTemplate();
22552 } else {
22553 // use the template as resource for the template currently opened
22554 $this->xobjects[$this->xobjid]['xobjects'][$id] = $this->xobjects[$id];
22555 }
22556 }
22557 // set default values
22558 if ($x === '') {
22559 $x = $this->x;
22560 }
22561 if ($y === '') {
22562 $y = $this->y;
22563 }
22564 // check page for no-write regions and adapt page margins if necessary
22565 list($x, $y) = $this->checkPageRegions($h, $x, $y);
22566 $ow = $this->xobjects[$id]['w'];
22567 if ($ow <= 0) {
22568 $ow = 1;
22569 }
22570 $oh = $this->xobjects[$id]['h'];
22571 if ($oh <= 0) {
22572 $oh = 1;
22573 }
22574 // calculate template width and height on document
22575 if (($w <= 0) AND ($h <= 0)) {
22576 $w = $ow;
22577 $h = $oh;
22578 } elseif ($w <= 0) {
22579 $w = $h * $ow / $oh;
22580 } elseif ($h <= 0) {
22581 $h = $w * $oh / $ow;
22582 }
22583 // fit the template on available space
22584 list($w, $h, $x, $y) = $this->fitBlock($w, $h, $x, $y, $fitonpage);
22585 // set page alignment
22586 $rb_y = $y + $h;
22587 // set alignment
22588 if ($this->rtl) {
22589 if ($palign == 'L') {
22590 $xt = $this->lMargin;
22591 } elseif ($palign == 'C') {
22592 $xt = ($this->w + $this->lMargin - $this->rMargin - $w) / 2;
22593 } elseif ($palign == 'R') {
22594 $xt = $this->w - $this->rMargin - $w;
22595 } else {
22596 $xt = $x - $w;
22597 }
22598 $rb_x = $xt;
22599 } else {
22600 if ($palign == 'L') {
22601 $xt = $this->lMargin;
22602 } elseif ($palign == 'C') {
22603 $xt = ($this->w + $this->lMargin - $this->rMargin - $w) / 2;
22604 } elseif ($palign == 'R') {
22605 $xt = $this->w - $this->rMargin - $w;
22606 } else {
22607 $xt = $x;
22608 }
22609 $rb_x = $xt + $w;
22610 }
22611 // print XObject Template + Transformation matrix
22612 $this->StartTransform();
22613 // translate and scale
22614 $sx = ($w / $ow);
22615 $sy = ($h / $oh);
22616 $tm = array();
22617 $tm[0] = $sx;
22618 $tm[1] = 0;
22619 $tm[2] = 0;
22620 $tm[3] = $sy;
22621 $tm[4] = $xt * $this->k;
22622 $tm[5] = ($this->h - $h - $y) * $this->k;
22623 $this->Transform($tm);
22624 // set object
22625 $this->_out('/'.$id.' Do');
22626 $this->StopTransform();
22627 // add annotations
22628 if (!empty($this->xobjects[$id]['annotations'])) {
22629 foreach ($this->xobjects[$id]['annotations'] as $annot) {
22630 // transform original coordinates
22631 $coordlt = TCPDF_STATIC::getTransformationMatrixProduct($tm, array(1, 0, 0, 1, ($annot['x'] * $this->k), (-$annot['y'] * $this->k)));
22632 $ax = ($coordlt[4] / $this->k);
22633 $ay = ($this->h - $h - ($coordlt[5] / $this->k));
22634 $coordrb = TCPDF_STATIC::getTransformationMatrixProduct($tm, array(1, 0, 0, 1, (($annot['x'] + $annot['w']) * $this->k), ((-$annot['y'] - $annot['h']) * $this->k)));
22635 $aw = ($coordrb[4] / $this->k) - $ax;
22636 $ah = ($this->h - $h - ($coordrb[5] / $this->k)) - $ay;
22637 $this->Annotation($ax, $ay, $aw, $ah, $annot['text'], $annot['opt'], $annot['spaces']);
22638 }
22639 }
22640 // set pointer to align the next text/objects
22641 switch($align) {
22642 case 'T': {
22643 $this->y = $y;
22644 $this->x = $rb_x;
22645 break;
22646 }
22647 case 'M': {
22648 $this->y = $y + round($h/2);
22649 $this->x = $rb_x;
22650 break;
22651 }
22652 case 'B': {
22653 $this->y = $rb_y;
22654 $this->x = $rb_x;
22655 break;
22656 }
22657 case 'N': {
22658 $this->SetY($rb_y);
22659 break;
22660 }
22661 default:{
22662 break;
22663 }
22664 }
22665 }
22666
22667 /**
22668 * Set the percentage of character stretching.
22669 * @param $perc (int) percentage of stretching (100 = no stretching)
22670 * @author Nicola Asuni
22671 * @public
22672 * @since 5.9.000 (2010-09-29)
22673 */
22674 public function setFontStretching($perc=100) {
22675 $this->font_stretching = $perc;
22676 }
22677
22678 /**
22679 * Get the percentage of character stretching.
22680 * @return float stretching value
22681 * @author Nicola Asuni
22682 * @public
22683 * @since 5.9.000 (2010-09-29)
22684 */
22685 public function getFontStretching() {
22686 return $this->font_stretching;
22687 }
22688
22689 /**
22690 * Set the amount to increase or decrease the space between characters in a text.
22691 * @param $spacing (float) amount to increase or decrease the space between characters in a text (0 = default spacing)
22692 * @author Nicola Asuni
22693 * @public
22694 * @since 5.9.000 (2010-09-29)
22695 */
22696 public function setFontSpacing($spacing=0) {
22697 $this->font_spacing = $spacing;
22698 }
22699
22700 /**
22701 * Get the amount to increase or decrease the space between characters in a text.
22702 * @return int font spacing (tracking) value
22703 * @author Nicola Asuni
22704 * @public
22705 * @since 5.9.000 (2010-09-29)
22706 */
22707 public function getFontSpacing() {
22708 return $this->font_spacing;
22709 }
22710
22711 /**
22712 * Return an array of no-write page regions
22713 * @return array of no-write page regions
22714 * @author Nicola Asuni
22715 * @public
22716 * @since 5.9.003 (2010-10-13)
22717 * @see setPageRegions(), addPageRegion()
22718 */
22719 public function getPageRegions() {
22720 return $this->page_regions;
22721 }
22722
22723 /**
22724 * Set no-write regions on page.
22725 * A no-write region is a portion of the page with a rectangular or trapezium shape that will not be covered when writing text or html code.
22726 * A region is always aligned on the left or right side of the page ad is defined using a vertical segment.
22727 * You can set multiple regions for the same page.
22728 * @param $regions (array) array of no-write regions. For each region you can define an array as follow: ('page' => page number or empy for current page, 'xt' => X top, 'yt' => Y top, 'xb' => X bottom, 'yb' => Y bottom, 'side' => page side 'L' = left or 'R' = right). Omit this parameter to remove all regions.
22729 * @author Nicola Asuni
22730 * @public
22731 * @since 5.9.003 (2010-10-13)
22732 * @see addPageRegion(), getPageRegions()
22733 */
22734 public function setPageRegions($regions=array()) {
22735 // empty current regions array
22736 $this->page_regions = array();
22737 // add regions
22738 foreach ($regions as $data) {
22739 $this->addPageRegion($data);
22740 }
22741 }
22742
22743 /**
22744 * Add a single no-write region on selected page.
22745 * A no-write region is a portion of the page with a rectangular or trapezium shape that will not be covered when writing text or html code.
22746 * A region is always aligned on the left or right side of the page ad is defined using a vertical segment.
22747 * You can set multiple regions for the same page.
22748 * @param $region (array) array of a single no-write region array: ('page' => page number or empy for current page, 'xt' => X top, 'yt' => Y top, 'xb' => X bottom, 'yb' => Y bottom, 'side' => page side 'L' = left or 'R' = right).
22749 * @author Nicola Asuni
22750 * @public
22751 * @since 5.9.003 (2010-10-13)
22752 * @see setPageRegions(), getPageRegions()
22753 */
22754 public function addPageRegion($region) {
22755 if (!isset($region['page']) OR empty($region['page'])) {
22756 $region['page'] = $this->page;
22757 }
22758 if (isset($region['xt']) AND isset($region['xb']) AND ($region['xt'] > 0) AND ($region['xb'] > 0)
22759 AND isset($region['yt']) AND isset($region['yb']) AND ($region['yt'] >= 0) AND ($region['yt'] < $region['yb'])
22760 AND isset($region['side']) AND (($region['side'] == 'L') OR ($region['side'] == 'R'))) {
22761 $this->page_regions[] = $region;
22762 }
22763 }
22764
22765 /**
22766 * Remove a single no-write region.
22767 * @param $key (int) region key
22768 * @author Nicola Asuni
22769 * @public
22770 * @since 5.9.003 (2010-10-13)
22771 * @see setPageRegions(), getPageRegions()
22772 */
22773 public function removePageRegion($key) {
22774 if (isset($this->page_regions[$key])) {
22775 unset($this->page_regions[$key]);
22776 }
22777 }
22778
22779 /**
22780 * Check page for no-write regions and adapt current coordinates and page margins if necessary.
22781 * A no-write region is a portion of the page with a rectangular or trapezium shape that will not be covered when writing text or html code.
22782 * A region is always aligned on the left or right side of the page ad is defined using a vertical segment.
22783 * @param $h (float) height of the text/image/object to print in user units
22784 * @param $x (float) current X coordinate in user units
22785 * @param $y (float) current Y coordinate in user units
22786 * @return array($x, $y)
22787 * @author Nicola Asuni
22788 * @protected
22789 * @since 5.9.003 (2010-10-13)
22790 */
22791 protected function checkPageRegions($h, $x, $y) {
22792 // set default values
22793 if ($x === '') {
22794 $x = $this->x;
22795 }
22796 if ($y === '') {
22797 $y = $this->y;
22798 }
22799 if (!$this->check_page_regions OR empty($this->page_regions)) {
22800 // no page regions defined
22801 return array($x, $y);
22802 }
22803 if (empty($h)) {
22804 $h = $this->getCellHeight($this->FontSize);
22805 }
22806 // check for page break
22807 if ($this->checkPageBreak($h, $y)) {
22808 // the content will be printed on a new page
22809 $x = $this->x;
22810 $y = $this->y;
22811 }
22812 if ($this->num_columns > 1) {
22813 if ($this->rtl) {
22814 $this->lMargin = ($this->columns[$this->current_column]['x'] - $this->columns[$this->current_column]['w']);
22815 } else {
22816 $this->rMargin = ($this->w - $this->columns[$this->current_column]['x'] - $this->columns[$this->current_column]['w']);
22817 }
22818 } else {
22819 if ($this->rtl) {
22820 $this->lMargin = max($this->clMargin, $this->original_lMargin);
22821 } else {
22822 $this->rMargin = max($this->crMargin, $this->original_rMargin);
22823 }
22824 }
22825 // adjust coordinates and page margins
22826 foreach ($this->page_regions as $regid => $regdata) {
22827 if ($regdata['page'] == $this->page) {
22828 // check region boundaries
22829 if (($y > ($regdata['yt'] - $h)) AND ($y <= $regdata['yb'])) {
22830 // Y is inside the region
22831 $minv = ($regdata['xb'] - $regdata['xt']) / ($regdata['yb'] - $regdata['yt']); // inverse of angular coefficient
22832 $yt = max($y, $regdata['yt']);
22833 $yb = min(($yt + $h), $regdata['yb']);
22834 $xt = (($yt - $regdata['yt']) * $minv) + $regdata['xt'];
22835 $xb = (($yb - $regdata['yt']) * $minv) + $regdata['xt'];
22836 if ($regdata['side'] == 'L') { // left side
22837 $new_margin = max($xt, $xb);
22838 if ($this->lMargin < $new_margin) {
22839 if ($this->rtl) {
22840 // adjust left page margin
22841 $this->lMargin = max(0, $new_margin);
22842 }
22843 if ($x < $new_margin) {
22844 // adjust x position
22845 $x = $new_margin;
22846 if ($new_margin > ($this->w - $this->rMargin)) {
22847 // adjust y position
22848 $y = $regdata['yb'] - $h;
22849 }
22850 }
22851 }
22852 } elseif ($regdata['side'] == 'R') { // right side
22853 $new_margin = min($xt, $xb);
22854 if (($this->w - $this->rMargin) > $new_margin) {
22855 if (!$this->rtl) {
22856 // adjust right page margin
22857 $this->rMargin = max(0, ($this->w - $new_margin));
22858 }
22859 if ($x > $new_margin) {
22860 // adjust x position
22861 $x = $new_margin;
22862 if ($new_margin > $this->lMargin) {
22863 // adjust y position
22864 $y = $regdata['yb'] - $h;
22865 }
22866 }
22867 }
22868 }
22869 }
22870 }
22871 }
22872 return array($x, $y);
22873 }
22874
22875 // --- SVG METHODS ---------------------------------------------------------
22876
22877 /**
22878 * Embedd a Scalable Vector Graphics (SVG) image.
22879 * NOTE: SVG standard is not yet fully implemented, use the setRasterizeVectorImages() method to enable/disable rasterization of vector images using ImageMagick library.
22880 * @param $file (string) Name of the SVG file or a '@' character followed by the SVG data string.
22881 * @param $x (float) Abscissa of the upper-left corner.
22882 * @param $y (float) Ordinate of the upper-left corner.
22883 * @param $w (float) Width of the image in the page. If not specified or equal to zero, it is automatically calculated.
22884 * @param $h (float) Height of the image in the page. If not specified or equal to zero, it is automatically calculated.
22885 * @param $link (mixed) URL or identifier returned by AddLink().
22886 * @param $align (string) Indicates the alignment of the pointer next to image insertion relative to image height. The value can be:<ul><li>T: top-right for LTR or top-left for RTL</li><li>M: middle-right for LTR or middle-left for RTL</li><li>B: bottom-right for LTR or bottom-left for RTL</li><li>N: next line</li></ul> If the alignment is an empty string, then the pointer will be restored on the starting SVG position.
22887 * @param $palign (string) Allows to center or align the image on the current line. Possible values are:<ul><li>L : left align</li><li>C : center</li><li>R : right align</li><li>'' : empty string : left for LTR or right for RTL</li></ul>
22888 * @param $border (mixed) Indicates if borders must be drawn around the cell. 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 - for example: array('LTRB' => array('width' => 2, 'cap' => 'butt', 'join' => 'miter', 'dash' => 0, 'color' => array(0, 0, 0)))
22889 * @param $fitonpage (boolean) if true the image is resized to not exceed page dimensions.
22890 * @author Nicola Asuni
22891 * @since 5.0.000 (2010-05-02)
22892 * @public
22893 */
22894 public function ImageSVG($file, $x='', $y='', $w=0, $h=0, $link='', $align='', $palign='', $border=0, $fitonpage=false) {
22895 if ($this->state != 2) {
22896 return;
22897 }
22898 // reseet SVG vars
22899 $this->svggradients = array();
22900 $this->svggradientid = 0;
22901 $this->svgdefsmode = false;
22902 $this->svgdefs = array();
22903 $this->svgclipmode = false;
22904 $this->svgclippaths = array();
22905 $this->svgcliptm = array();
22906 $this->svgclipid = 0;
22907 $this->svgtext = '';
22908 $this->svgtextmode = array();
22909 if ($this->rasterize_vector_images AND ($w > 0) AND ($h > 0)) {
22910 // convert SVG to raster image using GD or ImageMagick libraries
22911 return $this->Image($file, $x, $y, $w, $h, 'SVG', $link, $align, true, 300, $palign, false, false, $border, false, false, false);
22912 }
22913 if ($file[0] === '@') { // image from string
22914 $this->svgdir = '';
22915 $svgdata = substr($file, 1);
22916 } else { // SVG file
22917 $this->svgdir = dirname($file);
22918 $svgdata = TCPDF_STATIC::fileGetContents($file);
22919 }
22920 if ($svgdata === FALSE) {
22921 $this->Error('SVG file not found: '.$file);
22922 }
22923 if ($x === '') {
22924 $x = $this->x;
22925 }
22926 if ($y === '') {
22927 $y = $this->y;
22928 }
22929 // check page for no-write regions and adapt page margins if necessary
22930 list($x, $y) = $this->checkPageRegions($h, $x, $y);
22931 $k = $this->k;
22932 $ox = 0;
22933 $oy = 0;
22934 $ow = $w;
22935 $oh = $h;
22936 $aspect_ratio_align = 'xMidYMid';
22937 $aspect_ratio_ms = 'meet';
22938 $regs = array();
22939 // get original image width and height
22940 preg_match('/<svg([^\>]*)>/si', $svgdata, $regs);
22941 if (isset($regs[1]) AND !empty($regs[1])) {
22942 $tmp = array();
22943 if (preg_match('/[\s]+x[\s]*=[\s]*"([^"]*)"/si', $regs[1], $tmp)) {
22944 $ox = $this->getHTMLUnitToUnits($tmp[1], 0, $this->svgunit, false);
22945 }
22946 $tmp = array();
22947 if (preg_match('/[\s]+y[\s]*=[\s]*"([^"]*)"/si', $regs[1], $tmp)) {
22948 $oy = $this->getHTMLUnitToUnits($tmp[1], 0, $this->svgunit, false);
22949 }
22950 $tmp = array();
22951 if (preg_match('/[\s]+width[\s]*=[\s]*"([^"]*)"/si', $regs[1], $tmp)) {
22952 $ow = $this->getHTMLUnitToUnits($tmp[1], 1, $this->svgunit, false);
22953 }
22954 $tmp = array();
22955 if (preg_match('/[\s]+height[\s]*=[\s]*"([^"]*)"/si', $regs[1], $tmp)) {
22956 $oh = $this->getHTMLUnitToUnits($tmp[1], 1, $this->svgunit, false);
22957 }
22958 $tmp = array();
22959 $view_box = array();
22960 if (preg_match('/[\s]+viewBox[\s]*=[\s]*"[\s]*([0-9\.\-]+)[\s]+([0-9\.\-]+)[\s]+([0-9\.]+)[\s]+([0-9\.]+)[\s]*"/si', $regs[1], $tmp)) {
22961 if (count($tmp) == 5) {
22962 array_shift($tmp);
22963 foreach ($tmp as $key => $val) {
22964 $view_box[$key] = $this->getHTMLUnitToUnits($val, 0, $this->svgunit, false);
22965 }
22966 $ox = $view_box[0];
22967 $oy = $view_box[1];
22968 }
22969 // get aspect ratio
22970 $tmp = array();
22971 if (preg_match('/[\s]+preserveAspectRatio[\s]*=[\s]*"([^"]*)"/si', $regs[1], $tmp)) {
22972 $aspect_ratio = preg_split('/[\s]+/si', $tmp[1]);
22973 switch (count($aspect_ratio)) {
22974 case 3: {
22975 $aspect_ratio_align = $aspect_ratio[1];
22976 $aspect_ratio_ms = $aspect_ratio[2];
22977 break;
22978 }
22979 case 2: {
22980 $aspect_ratio_align = $aspect_ratio[0];
22981 $aspect_ratio_ms = $aspect_ratio[1];
22982 break;
22983 }
22984 case 1: {
22985 $aspect_ratio_align = $aspect_ratio[0];
22986 $aspect_ratio_ms = 'meet';
22987 break;
22988 }
22989 }
22990 }
22991 }
22992 }
22993 if ($ow <= 0) {
22994 $ow = 1;
22995 }
22996 if ($oh <= 0) {
22997 $oh = 1;
22998 }
22999 // calculate image width and height on document
23000 if (($w <= 0) AND ($h <= 0)) {
23001 // convert image size to document unit
23002 $w = $ow;
23003 $h = $oh;
23004 } elseif ($w <= 0) {
23005 $w = $h * $ow / $oh;
23006 } elseif ($h <= 0) {
23007 $h = $w * $oh / $ow;
23008 }
23009 // fit the image on available space
23010 list($w, $h, $x, $y) = $this->fitBlock($w, $h, $x, $y, $fitonpage);
23011 if ($this->rasterize_vector_images) {
23012 // convert SVG to raster image using GD or ImageMagick libraries
23013 return $this->Image($file, $x, $y, $w, $h, 'SVG', $link, $align, true, 300, $palign, false, false, $border, false, false, false);
23014 }
23015 // set alignment
23016 $this->img_rb_y = $y + $h;
23017 // set alignment
23018 if ($this->rtl) {
23019 if ($palign == 'L') {
23020 $ximg = $this->lMargin;
23021 } elseif ($palign == 'C') {
23022 $ximg = ($this->w + $this->lMargin - $this->rMargin - $w) / 2;
23023 } elseif ($palign == 'R') {
23024 $ximg = $this->w - $this->rMargin - $w;
23025 } else {
23026 $ximg = $x - $w;
23027 }
23028 $this->img_rb_x = $ximg;
23029 } else {
23030 if ($palign == 'L') {
23031 $ximg = $this->lMargin;
23032 } elseif ($palign == 'C') {
23033 $ximg = ($this->w + $this->lMargin - $this->rMargin - $w) / 2;
23034 } elseif ($palign == 'R') {
23035 $ximg = $this->w - $this->rMargin - $w;
23036 } else {
23037 $ximg = $x;
23038 }
23039 $this->img_rb_x = $ximg + $w;
23040 }
23041 // store current graphic vars
23042 $gvars = $this->getGraphicVars();
23043 // store SVG position and scale factors
23044 $svgoffset_x = ($ximg - $ox) * $this->k;
23045 $svgoffset_y = -($y - $oy) * $this->k;
23046 if (isset($view_box[2]) AND ($view_box[2] > 0) AND ($view_box[3] > 0)) {
23047 $ow = $view_box[2];
23048 $oh = $view_box[3];
23049 } else {
23050 if ($ow <= 0) {
23051 $ow = $w;
23052 }
23053 if ($oh <= 0) {
23054 $oh = $h;
23055 }
23056 }
23057 $svgscale_x = $w / $ow;
23058 $svgscale_y = $h / $oh;
23059 // scaling and alignment
23060 if ($aspect_ratio_align != 'none') {
23061 // store current scaling values
23062 $svgscale_old_x = $svgscale_x;
23063 $svgscale_old_y = $svgscale_y;
23064 // force uniform scaling
23065 if ($aspect_ratio_ms == 'slice') {
23066 // the entire viewport is covered by the viewBox
23067 if ($svgscale_x > $svgscale_y) {
23068 $svgscale_y = $svgscale_x;
23069 } elseif ($svgscale_x < $svgscale_y) {
23070 $svgscale_x = $svgscale_y;
23071 }
23072 } else { // meet
23073 // the entire viewBox is visible within the viewport
23074 if ($svgscale_x < $svgscale_y) {
23075 $svgscale_y = $svgscale_x;
23076 } elseif ($svgscale_x > $svgscale_y) {
23077 $svgscale_x = $svgscale_y;
23078 }
23079 }
23080 // correct X alignment
23081 switch (substr($aspect_ratio_align, 1, 3)) {
23082 case 'Min': {
23083 // do nothing
23084 break;
23085 }
23086 case 'Max': {
23087 $svgoffset_x += (($w * $this->k) - ($ow * $this->k * $svgscale_x));
23088 break;
23089 }
23090 default:
23091 case 'Mid': {
23092 $svgoffset_x += ((($w * $this->k) - ($ow * $this->k * $svgscale_x)) / 2);
23093 break;
23094 }
23095 }
23096 // correct Y alignment
23097 switch (substr($aspect_ratio_align, 5)) {
23098 case 'Min': {
23099 // do nothing
23100 break;
23101 }
23102 case 'Max': {
23103 $svgoffset_y -= (($h * $this->k) - ($oh * $this->k * $svgscale_y));
23104 break;
23105 }
23106 default:
23107 case 'Mid': {
23108 $svgoffset_y -= ((($h * $this->k) - ($oh * $this->k * $svgscale_y)) / 2);
23109 break;
23110 }
23111 }
23112 }
23113 // store current page break mode
23114 $page_break_mode = $this->AutoPageBreak;
23115 $page_break_margin = $this->getBreakMargin();
23116 $cell_padding = $this->cell_padding;
23117 $this->SetCellPadding(0);
23118 $this->SetAutoPageBreak(false);
23119 // save the current graphic state
23120 $this->_out('q'.$this->epsmarker);
23121 // set initial clipping mask
23122 $this->Rect($ximg, $y, $w, $h, 'CNZ', array(), array());
23123 // scale and translate
23124 $e = $ox * $this->k * (1 - $svgscale_x);
23125 $f = ($this->h - $oy) * $this->k * (1 - $svgscale_y);
23126 $this->_out(sprintf('%F %F %F %F %F %F cm', $svgscale_x, 0, 0, $svgscale_y, ($e + $svgoffset_x), ($f + $svgoffset_y)));
23127 // creates a new XML parser to be used by the other XML functions
23128 $this->parser = xml_parser_create('UTF-8');
23129 // the following function allows to use parser inside object
23130 xml_set_object($this->parser, $this);
23131 // disable case-folding for this XML parser
23132 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
23133 // sets the element handler functions for the XML parser
23134 xml_set_element_handler($this->parser, 'startSVGElementHandler', 'endSVGElementHandler');
23135 // sets the character data handler function for the XML parser
23136 xml_set_character_data_handler($this->parser, 'segSVGContentHandler');
23137 // start parsing an XML document
23138 if (!xml_parse($this->parser, $svgdata)) {
23139 $error_message = sprintf('SVG Error: %s at line %d', xml_error_string(xml_get_error_code($this->parser)), xml_get_current_line_number($this->parser));
23140 $this->Error($error_message);
23141 }
23142 // free this XML parser
23143 xml_parser_free($this->parser);
23144 // restore previous graphic state
23145 $this->_out($this->epsmarker.'Q');
23146 // restore graphic vars
23147 $this->setGraphicVars($gvars);
23148 $this->lasth = $gvars['lasth'];
23149 if (!empty($border)) {
23150 $bx = $this->x;
23151 $by = $this->y;
23152 $this->x = $ximg;
23153 if ($this->rtl) {
23154 $this->x += $w;
23155 }
23156 $this->y = $y;
23157 $this->Cell($w, $h, '', $border, 0, '', 0, '', 0, true);
23158 $this->x = $bx;
23159 $this->y = $by;
23160 }
23161 if ($link) {
23162 $this->Link($ximg, $y, $w, $h, $link, 0);
23163 }
23164 // set pointer to align the next text/objects
23165 switch($align) {
23166 case 'T':{
23167 $this->y = $y;
23168 $this->x = $this->img_rb_x;
23169 break;
23170 }
23171 case 'M':{
23172 $this->y = $y + round($h/2);
23173 $this->x = $this->img_rb_x;
23174 break;
23175 }
23176 case 'B':{
23177 $this->y = $this->img_rb_y;
23178 $this->x = $this->img_rb_x;
23179 break;
23180 }
23181 case 'N':{
23182 $this->SetY($this->img_rb_y);
23183 break;
23184 }
23185 default:{
23186 // restore pointer to starting position
23187 $this->x = $gvars['x'];
23188 $this->y = $gvars['y'];
23189 $this->page = $gvars['page'];
23190 $this->current_column = $gvars['current_column'];
23191 $this->tMargin = $gvars['tMargin'];
23192 $this->bMargin = $gvars['bMargin'];
23193 $this->w = $gvars['w'];
23194 $this->h = $gvars['h'];
23195 $this->wPt = $gvars['wPt'];
23196 $this->hPt = $gvars['hPt'];
23197 $this->fwPt = $gvars['fwPt'];
23198 $this->fhPt = $gvars['fhPt'];
23199 break;
23200 }
23201 }
23202 $this->endlinex = $this->img_rb_x;
23203 // restore page break
23204 $this->SetAutoPageBreak($page_break_mode, $page_break_margin);
23205 $this->cell_padding = $cell_padding;
23206 }
23207
23208 /**
23209 * Convert SVG transformation matrix to PDF.
23210 * @param $tm (array) original SVG transformation matrix
23211 * @return array transformation matrix
23212 * @protected
23213 * @since 5.0.000 (2010-05-02)
23214 */
23215 protected function convertSVGtMatrix($tm) {
23216 $a = $tm[0];
23217 $b = -$tm[1];
23218 $c = -$tm[2];
23219 $d = $tm[3];
23220 $e = $this->getHTMLUnitToUnits($tm[4], 1, $this->svgunit, false) * $this->k;
23221 $f = -$this->getHTMLUnitToUnits($tm[5], 1, $this->svgunit, false) * $this->k;
23222 $x = 0;
23223 $y = $this->h * $this->k;
23224 $e = ($x * (1 - $a)) - ($y * $c) + $e;
23225 $f = ($y * (1 - $d)) - ($x * $b) + $f;
23226 return array($a, $b, $c, $d, $e, $f);
23227 }
23228
23229 /**
23230 * Apply SVG graphic transformation matrix.
23231 * @param $tm (array) original SVG transformation matrix
23232 * @protected
23233 * @since 5.0.000 (2010-05-02)
23234 */
23235 protected function SVGTransform($tm) {
23236 $this->Transform($this->convertSVGtMatrix($tm));
23237 }
23238
23239 /**
23240 * Apply the requested SVG styles (*** TO BE COMPLETED ***)
23241 * @param $svgstyle (array) array of SVG styles to apply
23242 * @param $prevsvgstyle (array) array of previous SVG style
23243 * @param $x (int) X origin of the bounding box
23244 * @param $y (int) Y origin of the bounding box
23245 * @param $w (int) width of the bounding box
23246 * @param $h (int) height of the bounding box
23247 * @param $clip_function (string) clip function
23248 * @param $clip_params (array) array of parameters for clipping function
23249 * @return object style
23250 * @author Nicola Asuni
23251 * @since 5.0.000 (2010-05-02)
23252 * @protected
23253 */
23254 protected function setSVGStyles($svgstyle, $prevsvgstyle, $x=0, $y=0, $w=1, $h=1, $clip_function='', $clip_params=array()) {
23255 if ($this->state != 2) {
23256 return;
23257 }
23258 $objstyle = '';
23259 $minlen = (0.01 / $this->k); // minimum acceptable length
23260 if (!isset($svgstyle['opacity'])) {
23261 return $objstyle;
23262 }
23263 // clip-path
23264 $regs = array();
23265 if (preg_match('/url\([\s]*\#([^\)]*)\)/si', $svgstyle['clip-path'], $regs)) {
23266 $clip_path = $this->svgclippaths[$regs[1]];
23267 foreach ($clip_path as $cp) {
23268 $this->startSVGElementHandler('clip-path', $cp['name'], $cp['attribs'], $cp['tm']);
23269 }
23270 }
23271 // opacity
23272 if ($svgstyle['opacity'] != 1) {
23273 $this->setAlpha($svgstyle['opacity'], 'Normal', $svgstyle['opacity'], false);
23274 }
23275 // color
23276 $fill_color = TCPDF_COLORS::convertHTMLColorToDec($svgstyle['color'], $this->spot_colors);
23277 $this->SetFillColorArray($fill_color);
23278 // text color
23279 $text_color = TCPDF_COLORS::convertHTMLColorToDec($svgstyle['text-color'], $this->spot_colors);
23280 $this->SetTextColorArray($text_color);
23281 // clip
23282 if (preg_match('/rect\(([a-z0-9\-\.]*)[\s]*([a-z0-9\-\.]*)[\s]*([a-z0-9\-\.]*)[\s]*([a-z0-9\-\.]*)\)/si', $svgstyle['clip'], $regs)) {
23283 $top = (isset($regs[1])?$this->getHTMLUnitToUnits($regs[1], 0, $this->svgunit, false):0);
23284 $right = (isset($regs[2])?$this->getHTMLUnitToUnits($regs[2], 0, $this->svgunit, false):0);
23285 $bottom = (isset($regs[3])?$this->getHTMLUnitToUnits($regs[3], 0, $this->svgunit, false):0);
23286 $left = (isset($regs[4])?$this->getHTMLUnitToUnits($regs[4], 0, $this->svgunit, false):0);
23287 $cx = $x + $left;
23288 $cy = $y + $top;
23289 $cw = $w - $left - $right;
23290 $ch = $h - $top - $bottom;
23291 if ($svgstyle['clip-rule'] == 'evenodd') {
23292 $clip_rule = 'CNZ';
23293 } else {
23294 $clip_rule = 'CEO';
23295 }
23296 $this->Rect($cx, $cy, $cw, $ch, $clip_rule, array(), array());
23297 }
23298 // fill
23299 $regs = array();
23300 if (preg_match('/url\([\s]*\#([^\)]*)\)/si', $svgstyle['fill'], $regs)) {
23301 // gradient
23302 $gradient = $this->svggradients[$regs[1]];
23303 if (isset($gradient['xref'])) {
23304 // reference to another gradient definition
23305 $newgradient = $this->svggradients[$gradient['xref']];
23306 $newgradient['coords'] = $gradient['coords'];
23307 $newgradient['mode'] = $gradient['mode'];
23308 $newgradient['type'] = $gradient['type'];
23309 $newgradient['gradientUnits'] = $gradient['gradientUnits'];
23310 if (isset($gradient['gradientTransform'])) {
23311 $newgradient['gradientTransform'] = $gradient['gradientTransform'];
23312 }
23313 $gradient = $newgradient;
23314 }
23315 //save current Graphic State
23316 $this->_outSaveGraphicsState();
23317 //set clipping area
23318 if (!empty($clip_function) AND method_exists($this, $clip_function)) {
23319 $bbox = call_user_func_array(array($this, $clip_function), $clip_params);
23320 if ((!isset($gradient['type']) OR ($gradient['type'] != 3)) AND is_array($bbox) AND (count($bbox) == 4)) {
23321 list($x, $y, $w, $h) = $bbox;
23322 }
23323 }
23324 if ($gradient['mode'] == 'measure') {
23325 if (!isset($gradient['coords'][4])) {
23326 $gradient['coords'][4] = 0.5;
23327 }
23328 if (isset($gradient['gradientTransform']) AND !empty($gradient['gradientTransform'])) {
23329 $gtm = $gradient['gradientTransform'];
23330 // apply transformation matrix
23331 $xa = ($gtm[0] * $gradient['coords'][0]) + ($gtm[2] * $gradient['coords'][1]) + $gtm[4];
23332 $ya = ($gtm[1] * $gradient['coords'][0]) + ($gtm[3] * $gradient['coords'][1]) + $gtm[5];
23333 $xb = ($gtm[0] * $gradient['coords'][2]) + ($gtm[2] * $gradient['coords'][3]) + $gtm[4];
23334 $yb = ($gtm[1] * $gradient['coords'][2]) + ($gtm[3] * $gradient['coords'][3]) + $gtm[5];
23335 $r = sqrt(pow(($gtm[0] * $gradient['coords'][4]), 2) + pow(($gtm[1] * $gradient['coords'][4]), 2));
23336 $gradient['coords'][0] = $xa;
23337 $gradient['coords'][1] = $ya;
23338 $gradient['coords'][2] = $xb;
23339 $gradient['coords'][3] = $yb;
23340 $gradient['coords'][4] = $r;
23341 }
23342 // convert SVG coordinates to user units
23343 $gradient['coords'][0] = $this->getHTMLUnitToUnits($gradient['coords'][0], 0, $this->svgunit, false);
23344 $gradient['coords'][1] = $this->getHTMLUnitToUnits($gradient['coords'][1], 0, $this->svgunit, false);
23345 $gradient['coords'][2] = $this->getHTMLUnitToUnits($gradient['coords'][2], 0, $this->svgunit, false);
23346 $gradient['coords'][3] = $this->getHTMLUnitToUnits($gradient['coords'][3], 0, $this->svgunit, false);
23347 $gradient['coords'][4] = $this->getHTMLUnitToUnits($gradient['coords'][4], 0, $this->svgunit, false);
23348 if ($w <= $minlen) {
23349 $w = $minlen;
23350 }
23351 if ($h <= $minlen) {
23352 $h = $minlen;
23353 }
23354 // shift units
23355 if ($gradient['gradientUnits'] == 'objectBoundingBox') {
23356 // convert to SVG coordinate system
23357 $gradient['coords'][0] += $x;
23358 $gradient['coords'][1] += $y;
23359 $gradient['coords'][2] += $x;
23360 $gradient['coords'][3] += $y;
23361 }
23362 // calculate percentages
23363 $gradient['coords'][0] = (($gradient['coords'][0] - $x) / $w);
23364 $gradient['coords'][1] = (($gradient['coords'][1] - $y) / $h);
23365 $gradient['coords'][2] = (($gradient['coords'][2] - $x) / $w);
23366 $gradient['coords'][3] = (($gradient['coords'][3] - $y) / $h);
23367 $gradient['coords'][4] /= $w;
23368 } elseif ($gradient['mode'] == 'percentage') {
23369 foreach($gradient['coords'] as $key => $val) {
23370 $gradient['coords'][$key] = (intval($val) / 100);
23371 if ($val < 0) {
23372 $gradient['coords'][$key] = 0;
23373 } elseif ($val > 1) {
23374 $gradient['coords'][$key] = 1;
23375 }
23376 }
23377 }
23378 if (($gradient['type'] == 2) AND ($gradient['coords'][0] == $gradient['coords'][2]) AND ($gradient['coords'][1] == $gradient['coords'][3])) {
23379 // single color (no shading)
23380 $gradient['coords'][0] = 1;
23381 $gradient['coords'][1] = 0;
23382 $gradient['coords'][2] = 0.999;
23383 $gradient['coords'][3] = 0;
23384 }
23385 // swap Y coordinates
23386 $tmp = $gradient['coords'][1];
23387 $gradient['coords'][1] = $gradient['coords'][3];
23388 $gradient['coords'][3] = $tmp;
23389 // set transformation map for gradient
23390 $cy = ($this->h - $y);
23391 if ($gradient['type'] == 3) {
23392 // circular gradient
23393 $cy -= ($gradient['coords'][1] * ($w + $h));
23394 } else {
23395 $cy -= $h;
23396 }
23397 $this->_out(sprintf('%F 0 0 %F %F %F cm', ($w * $this->k), ($h * $this->k), ($x * $this->k), ($cy * $this->k)));
23398 if (count($gradient['stops']) > 1) {
23399 $this->Gradient($gradient['type'], $gradient['coords'], $gradient['stops'], array(), false);
23400 }
23401 } elseif ($svgstyle['fill'] != 'none') {
23402 $fill_color = TCPDF_COLORS::convertHTMLColorToDec($svgstyle['fill'], $this->spot_colors);
23403 if ($svgstyle['fill-opacity'] != 1) {
23404 $this->setAlpha($this->alpha['CA'], 'Normal', $svgstyle['fill-opacity'], false);
23405 }
23406 $this->SetFillColorArray($fill_color);
23407 if ($svgstyle['fill-rule'] == 'evenodd') {
23408 $objstyle .= 'F*';
23409 } else {
23410 $objstyle .= 'F';
23411 }
23412 }
23413 // stroke
23414 if ($svgstyle['stroke'] != 'none') {
23415 if ($svgstyle['stroke-opacity'] != 1) {
23416 $this->setAlpha($svgstyle['stroke-opacity'], 'Normal', $this->alpha['ca'], false);
23417 } elseif (preg_match('/rgba\(\d+%?,\s*\d+%?,\s*\d+%?,\s*(\d+(?:\.\d+)?)\)/i', $svgstyle['stroke'], $rgba_matches)) {
23418 $this->setAlpha($rgba_matches[1], 'Normal', $this->alpha['ca'], false);
23419 }
23420 $stroke_style = array(
23421 'color' => TCPDF_COLORS::convertHTMLColorToDec($svgstyle['stroke'], $this->spot_colors),
23422 'width' => $this->getHTMLUnitToUnits($svgstyle['stroke-width'], 0, $this->svgunit, false),
23423 'cap' => $svgstyle['stroke-linecap'],
23424 'join' => $svgstyle['stroke-linejoin']
23425 );
23426 if (isset($svgstyle['stroke-dasharray']) AND !empty($svgstyle['stroke-dasharray']) AND ($svgstyle['stroke-dasharray'] != 'none')) {
23427 $stroke_style['dash'] = $svgstyle['stroke-dasharray'];
23428 }
23429 $this->SetLineStyle($stroke_style);
23430 $objstyle .= 'D';
23431 }
23432 // font
23433 $regs = array();
23434 if (!empty($svgstyle['font'])) {
23435 if (preg_match('/font-family[\s]*:[\s]*([^\;\"]*)/si', $svgstyle['font'], $regs)) {
23436 $font_family = $this->getFontFamilyName($regs[1]);
23437 } else {
23438 $font_family = $svgstyle['font-family'];
23439 }
23440 if (preg_match('/font-size[\s]*:[\s]*([^\s\;\"]*)/si', $svgstyle['font'], $regs)) {
23441 $font_size = trim($regs[1]);
23442 } else {
23443 $font_size = $svgstyle['font-size'];
23444 }
23445 if (preg_match('/font-style[\s]*:[\s]*([^\s\;\"]*)/si', $svgstyle['font'], $regs)) {
23446 $font_style = trim($regs[1]);
23447 } else {
23448 $font_style = $svgstyle['font-style'];
23449 }
23450 if (preg_match('/font-weight[\s]*:[\s]*([^\s\;\"]*)/si', $svgstyle['font'], $regs)) {
23451 $font_weight = trim($regs[1]);
23452 } else {
23453 $font_weight = $svgstyle['font-weight'];
23454 }
23455 if (preg_match('/font-stretch[\s]*:[\s]*([^\s\;\"]*)/si', $svgstyle['font'], $regs)) {
23456 $font_stretch = trim($regs[1]);
23457 } else {
23458 $font_stretch = $svgstyle['font-stretch'];
23459 }
23460 if (preg_match('/letter-spacing[\s]*:[\s]*([^\s\;\"]*)/si', $svgstyle['font'], $regs)) {
23461 $font_spacing = trim($regs[1]);
23462 } else {
23463 $font_spacing = $svgstyle['letter-spacing'];
23464 }
23465 } else {
23466 $font_family = $this->getFontFamilyName($svgstyle['font-family']);
23467 $font_size = $svgstyle['font-size'];
23468 $font_style = $svgstyle['font-style'];
23469 $font_weight = $svgstyle['font-weight'];
23470 $font_stretch = $svgstyle['font-stretch'];
23471 $font_spacing = $svgstyle['letter-spacing'];
23472 }
23473 $font_size = $this->getHTMLFontUnits($font_size, $this->svgstyles[0]['font-size'], $prevsvgstyle['font-size'], $this->svgunit);
23474 $font_stretch = $this->getCSSFontStretching($font_stretch, $svgstyle['font-stretch']);
23475 $font_spacing = $this->getCSSFontSpacing($font_spacing, $svgstyle['letter-spacing']);
23476 switch ($font_style) {
23477 case 'italic': {
23478 $font_style = 'I';
23479 break;
23480 }
23481 case 'oblique': {
23482 $font_style = 'I';
23483 break;
23484 }
23485 default:
23486 case 'normal': {
23487 $font_style = '';
23488 break;
23489 }
23490 }
23491 switch ($font_weight) {
23492 case 'bold':
23493 case 'bolder': {
23494 $font_style .= 'B';
23495 break;
23496 }
23497 }
23498 switch ($svgstyle['text-decoration']) {
23499 case 'underline': {
23500 $font_style .= 'U';
23501 break;
23502 }
23503 case 'overline': {
23504 $font_style .= 'O';
23505 break;
23506 }
23507 case 'line-through': {
23508 $font_style .= 'D';
23509 break;
23510 }
23511 default:
23512 case 'none': {
23513 break;
23514 }
23515 }
23516 $this->SetFont($font_family, $font_style, $font_size);
23517 $this->setFontStretching($font_stretch);
23518 $this->setFontSpacing($font_spacing);
23519 return $objstyle;
23520 }
23521
23522 /**
23523 * Draws an SVG path
23524 * @param $d (string) attribute d of the path SVG element
23525 * @param $style (string) Style of rendering. Possible values are:
23526 * <ul>
23527 * <li>D or empty string: Draw (default).</li>
23528 * <li>F: Fill.</li>
23529 * <li>F*: Fill using the even-odd rule to determine which regions lie inside the clipping path.</li>
23530 * <li>DF or FD: Draw and fill.</li>
23531 * <li>DF* or FD*: Draw and fill using the even-odd rule to determine which regions lie inside the clipping path.</li>
23532 * <li>CNZ: Clipping mode (using the even-odd rule to determine which regions lie inside the clipping path).</li>
23533 * <li>CEO: Clipping mode (using the nonzero winding number rule to determine which regions lie inside the clipping path).</li>
23534 * </ul>
23535 * @return array of container box measures (x, y, w, h)
23536 * @author Nicola Asuni
23537 * @since 5.0.000 (2010-05-02)
23538 * @protected
23539 */
23540 protected function SVGPath($d, $style='') {
23541 if ($this->state != 2) {
23542 return;
23543 }
23544 // set fill/stroke style
23545 $op = TCPDF_STATIC::getPathPaintOperator($style, '');
23546 if (empty($op)) {
23547 return;
23548 }
23549 $paths = array();
23550 $d = preg_replace('/([0-9ACHLMQSTVZ])([\-\+])/si', '\\1 \\2', $d);
23551 preg_match_all('/([ACHLMQSTVZ])[\s]*([^ACHLMQSTVZ\"]*)/si', $d, $paths, PREG_SET_ORDER);
23552 $x = 0;
23553 $y = 0;
23554 $x1 = 0;
23555 $y1 = 0;
23556 $x2 = 0;
23557 $y2 = 0;
23558 $xmin = 2147483647;
23559 $xmax = 0;
23560 $ymin = 2147483647;
23561 $ymax = 0;
23562 $relcoord = false;
23563 $minlen = (0.01 / $this->k); // minimum acceptable length (3 point)
23564 $firstcmd = true; // used to print first point
23565 // draw curve pieces
23566 foreach ($paths as $key => $val) {
23567 // get curve type
23568 $cmd = trim($val[1]);
23569 if (strtolower($cmd) == $cmd) {
23570 // use relative coordinated instead of absolute
23571 $relcoord = true;
23572 $xoffset = $x;
23573 $yoffset = $y;
23574 } else {
23575 $relcoord = false;
23576 $xoffset = 0;
23577 $yoffset = 0;
23578 }
23579 $params = array();
23580 if (isset($val[2])) {
23581 // get curve parameters
23582 $rawparams = preg_split('/([\,\s]+)/si', trim($val[2]));
23583 $params = array();
23584 foreach ($rawparams as $ck => $cp) {
23585 $params[$ck] = $this->getHTMLUnitToUnits($cp, 0, $this->svgunit, false);
23586 if (abs($params[$ck]) < $minlen) {
23587 // aproximate little values to zero
23588 $params[$ck] = 0;
23589 }
23590 }
23591 }
23592 // store current origin point
23593 $x0 = $x;
23594 $y0 = $y;
23595 switch (strtoupper($cmd)) {
23596 case 'M': { // moveto
23597 foreach ($params as $ck => $cp) {
23598 if (($ck % 2) == 0) {
23599 $x = $cp + $xoffset;
23600 } else {
23601 $y = $cp + $yoffset;
23602 if ($firstcmd OR (abs($x0 - $x) >= $minlen) OR (abs($y0 - $y) >= $minlen)) {
23603 if ($ck == 1) {
23604 $this->_outPoint($x, $y);
23605 $firstcmd = false;
23606 } else {
23607 $this->_outLine($x, $y);
23608 }
23609 $x0 = $x;
23610 $y0 = $y;
23611 }
23612 $xmin = min($xmin, $x);
23613 $ymin = min($ymin, $y);
23614 $xmax = max($xmax, $x);
23615 $ymax = max($ymax, $y);
23616 if ($relcoord) {
23617 $xoffset = $x;
23618 $yoffset = $y;
23619 }
23620 }
23621 }
23622 break;
23623 }
23624 case 'L': { // lineto
23625 foreach ($params as $ck => $cp) {
23626 if (($ck % 2) == 0) {
23627 $x = $cp + $xoffset;
23628 } else {
23629 $y = $cp + $yoffset;
23630 if ((abs($x0 - $x) >= $minlen) OR (abs($y0 - $y) >= $minlen)) {
23631 $this->_outLine($x, $y);
23632 $x0 = $x;
23633 $y0 = $y;
23634 }
23635 $xmin = min($xmin, $x);
23636 $ymin = min($ymin, $y);
23637 $xmax = max($xmax, $x);
23638 $ymax = max($ymax, $y);
23639 if ($relcoord) {
23640 $xoffset = $x;
23641 $yoffset = $y;
23642 }
23643 }
23644 }
23645 break;
23646 }
23647 case 'H': { // horizontal lineto
23648 foreach ($params as $ck => $cp) {
23649 $x = $cp + $xoffset;
23650 if ((abs($x0 - $x) >= $minlen) OR (abs($y0 - $y) >= $minlen)) {
23651 $this->_outLine($x, $y);
23652 $x0 = $x;
23653 $y0 = $y;
23654 }
23655 $xmin = min($xmin, $x);
23656 $xmax = max($xmax, $x);
23657 if ($relcoord) {
23658 $xoffset = $x;
23659 }
23660 }
23661 break;
23662 }
23663 case 'V': { // vertical lineto
23664 foreach ($params as $ck => $cp) {
23665 $y = $cp + $yoffset;
23666 if ((abs($x0 - $x) >= $minlen) OR (abs($y0 - $y) >= $minlen)) {
23667 $this->_outLine($x, $y);
23668 $x0 = $x;
23669 $y0 = $y;
23670 }
23671 $ymin = min($ymin, $y);
23672 $ymax = max($ymax, $y);
23673 if ($relcoord) {
23674 $yoffset = $y;
23675 }
23676 }
23677 break;
23678 }
23679 case 'C': { // curveto
23680 foreach ($params as $ck => $cp) {
23681 $params[$ck] = $cp;
23682 if ((($ck + 1) % 6) == 0) {
23683 $x1 = $params[($ck - 5)] + $xoffset;
23684 $y1 = $params[($ck - 4)] + $yoffset;
23685 $x2 = $params[($ck - 3)] + $xoffset;
23686 $y2 = $params[($ck - 2)] + $yoffset;
23687 $x = $params[($ck - 1)] + $xoffset;
23688 $y = $params[($ck)] + $yoffset;
23689 $this->_outCurve($x1, $y1, $x2, $y2, $x, $y);
23690 $xmin = min($xmin, $x, $x1, $x2);
23691 $ymin = min($ymin, $y, $y1, $y2);
23692 $xmax = max($xmax, $x, $x1, $x2);
23693 $ymax = max($ymax, $y, $y1, $y2);
23694 if ($relcoord) {
23695 $xoffset = $x;
23696 $yoffset = $y;
23697 }
23698 }
23699 }
23700 break;
23701 }
23702 case 'S': { // shorthand/smooth curveto
23703 foreach ($params as $ck => $cp) {
23704 $params[$ck] = $cp;
23705 if ((($ck + 1) % 4) == 0) {
23706 if (($key > 0) AND ((strtoupper($paths[($key - 1)][1]) == 'C') OR (strtoupper($paths[($key - 1)][1]) == 'S'))) {
23707 $x1 = (2 * $x) - $x2;
23708 $y1 = (2 * $y) - $y2;
23709 } else {
23710 $x1 = $x;
23711 $y1 = $y;
23712 }
23713 $x2 = $params[($ck - 3)] + $xoffset;
23714 $y2 = $params[($ck - 2)] + $yoffset;
23715 $x = $params[($ck - 1)] + $xoffset;
23716 $y = $params[($ck)] + $yoffset;
23717 $this->_outCurve($x1, $y1, $x2, $y2, $x, $y);
23718 $xmin = min($xmin, $x, $x1, $x2);
23719 $ymin = min($ymin, $y, $y1, $y2);
23720 $xmax = max($xmax, $x, $x1, $x2);
23721 $ymax = max($ymax, $y, $y1, $y2);
23722 if ($relcoord) {
23723 $xoffset = $x;
23724 $yoffset = $y;
23725 }
23726 }
23727 }
23728 break;
23729 }
23730 case 'Q': { // quadratic Bezier curveto
23731 foreach ($params as $ck => $cp) {
23732 $params[$ck] = $cp;
23733 if ((($ck + 1) % 4) == 0) {
23734 // convert quadratic points to cubic points
23735 $x1 = $params[($ck - 3)] + $xoffset;
23736 $y1 = $params[($ck - 2)] + $yoffset;
23737 $xa = ($x + (2 * $x1)) / 3;
23738 $ya = ($y + (2 * $y1)) / 3;
23739 $x = $params[($ck - 1)] + $xoffset;
23740 $y = $params[($ck)] + $yoffset;
23741 $xb = ($x + (2 * $x1)) / 3;
23742 $yb = ($y + (2 * $y1)) / 3;
23743 $this->_outCurve($xa, $ya, $xb, $yb, $x, $y);
23744 $xmin = min($xmin, $x, $xa, $xb);
23745 $ymin = min($ymin, $y, $ya, $yb);
23746 $xmax = max($xmax, $x, $xa, $xb);
23747 $ymax = max($ymax, $y, $ya, $yb);
23748 if ($relcoord) {
23749 $xoffset = $x;
23750 $yoffset = $y;
23751 }
23752 }
23753 }
23754 break;
23755 }
23756 case 'T': { // shorthand/smooth quadratic Bezier curveto
23757 foreach ($params as $ck => $cp) {
23758 $params[$ck] = $cp;
23759 if (($ck % 2) != 0) {
23760 if (($key > 0) AND ((strtoupper($paths[($key - 1)][1]) == 'Q') OR (strtoupper($paths[($key - 1)][1]) == 'T'))) {
23761 $x1 = (2 * $x) - $x1;
23762 $y1 = (2 * $y) - $y1;
23763 } else {
23764 $x1 = $x;
23765 $y1 = $y;
23766 }
23767 // convert quadratic points to cubic points
23768 $xa = ($x + (2 * $x1)) / 3;
23769 $ya = ($y + (2 * $y1)) / 3;
23770 $x = $params[($ck - 1)] + $xoffset;
23771 $y = $params[($ck)] + $yoffset;
23772 $xb = ($x + (2 * $x1)) / 3;
23773 $yb = ($y + (2 * $y1)) / 3;
23774 $this->_outCurve($xa, $ya, $xb, $yb, $x, $y);
23775 $xmin = min($xmin, $x, $xa, $xb);
23776 $ymin = min($ymin, $y, $ya, $yb);
23777 $xmax = max($xmax, $x, $xa, $xb);
23778 $ymax = max($ymax, $y, $ya, $yb);
23779 if ($relcoord) {
23780 $xoffset = $x;
23781 $yoffset = $y;
23782 }
23783 }
23784 }
23785 break;
23786 }
23787 case 'A': { // elliptical arc
23788 foreach ($params as $ck => $cp) {
23789 $params[$ck] = $cp;
23790 if ((($ck + 1) % 7) == 0) {
23791 $x0 = $x;
23792 $y0 = $y;
23793 $rx = abs($params[($ck - 6)]);
23794 $ry = abs($params[($ck - 5)]);
23795 $ang = -$rawparams[($ck - 4)];
23796 $angle = deg2rad($ang);
23797 $fa = $rawparams[($ck - 3)]; // large-arc-flag
23798 $fs = $rawparams[($ck - 2)]; // sweep-flag
23799 $x = $params[($ck - 1)] + $xoffset;
23800 $y = $params[$ck] + $yoffset;
23801 if ((abs($x0 - $x) < $minlen) AND (abs($y0 - $y) < $minlen)) {
23802 // endpoints are almost identical
23803 $xmin = min($xmin, $x);
23804 $ymin = min($ymin, $y);
23805 $xmax = max($xmax, $x);
23806 $ymax = max($ymax, $y);
23807 } else {
23808 $cos_ang = cos($angle);
23809 $sin_ang = sin($angle);
23810 $a = (($x0 - $x) / 2);
23811 $b = (($y0 - $y) / 2);
23812 $xa = ($a * $cos_ang) - ($b * $sin_ang);
23813 $ya = ($a * $sin_ang) + ($b * $cos_ang);
23814 $rx2 = $rx * $rx;
23815 $ry2 = $ry * $ry;
23816 $xa2 = $xa * $xa;
23817 $ya2 = $ya * $ya;
23818 $delta = ($xa2 / $rx2) + ($ya2 / $ry2);
23819 if ($delta > 1) {
23820 $rx *= sqrt($delta);
23821 $ry *= sqrt($delta);
23822 $rx2 = $rx * $rx;
23823 $ry2 = $ry * $ry;
23824 }
23825 $numerator = (($rx2 * $ry2) - ($rx2 * $ya2) - ($ry2 * $xa2));
23826 if ($numerator < 0) {
23827 $root = 0;
23828 } else {
23829 $root = sqrt($numerator / (($rx2 * $ya2) + ($ry2 * $xa2)));
23830 }
23831 if ($fa == $fs){
23832 $root *= -1;
23833 }
23834 $cax = $root * (($rx * $ya) / $ry);
23835 $cay = -$root * (($ry * $xa) / $rx);
23836 // coordinates of ellipse center
23837 $cx = ($cax * $cos_ang) - ($cay * $sin_ang) + (($x0 + $x) / 2);
23838 $cy = ($cax * $sin_ang) + ($cay * $cos_ang) + (($y0 + $y) / 2);
23839 // get angles
23840 $angs = TCPDF_STATIC::getVectorsAngle(1, 0, (($xa - $cax) / $rx), (($cay - $ya) / $ry));
23841 $dang = TCPDF_STATIC::getVectorsAngle((($xa - $cax) / $rx), (($ya - $cay) / $ry), ((-$xa - $cax) / $rx), ((-$ya - $cay) / $ry));
23842 if (($fs == 0) AND ($dang > 0)) {
23843 $dang -= (2 * M_PI);
23844 } elseif (($fs == 1) AND ($dang < 0)) {
23845 $dang += (2 * M_PI);
23846 }
23847 $angf = $angs - $dang;
23848 if ((($fs == 0) AND ($angs > $angf)) OR (($fs == 1) AND ($angs < $angf))) {
23849 // reverse angles
23850 $tmp = $angs;
23851 $angs = $angf;
23852 $angf = $tmp;
23853 }
23854 $angs = round(rad2deg($angs), 6);
23855 $angf = round(rad2deg($angf), 6);
23856 // covent angles to positive values
23857 if (($angs < 0) AND ($angf < 0)) {
23858 $angs += 360;
23859 $angf += 360;
23860 }
23861 $pie = false;
23862 if (($key == 0) AND (isset($paths[($key + 1)][1])) AND (trim($paths[($key + 1)][1]) == 'z')) {
23863 $pie = true;
23864 }
23865 list($axmin, $aymin, $axmax, $aymax) = $this->_outellipticalarc($cx, $cy, $rx, $ry, $ang, $angs, $angf, $pie, 2, false, ($fs == 0), true);
23866 $xmin = min($xmin, $x, $axmin);
23867 $ymin = min($ymin, $y, $aymin);
23868 $xmax = max($xmax, $x, $axmax);
23869 $ymax = max($ymax, $y, $aymax);
23870 }
23871 if ($relcoord) {
23872 $xoffset = $x;
23873 $yoffset = $y;
23874 }
23875 }
23876 }
23877 break;
23878 }
23879 case 'Z': {
23880 $this->_out('h');
23881 break;
23882 }
23883 }
23884 $firstcmd = false;
23885 } // end foreach
23886 if (!empty($op)) {
23887 $this->_out($op);
23888 }
23889 return array($xmin, $ymin, ($xmax - $xmin), ($ymax - $ymin));
23890 }
23891
23892 /**
23893 * Sets the opening SVG element handler function for the XML parser. (*** TO BE COMPLETED ***)
23894 * @param $parser (resource) The first parameter, parser, is a reference to the XML parser calling the handler.
23895 * @param $name (string) The second parameter, name, contains the name of the element for which this handler is called. If case-folding is in effect for this parser, the element name will be in uppercase letters.
23896 * @param $attribs (array) The third parameter, attribs, contains an associative array with the element's attributes (if any). The keys of this array are the attribute names, the values are the attribute values. Attribute names are case-folded on the same criteria as element names. Attribute values are not case-folded. The original order of the attributes can be retrieved by walking through attribs the normal way, using each(). The first key in the array was the first attribute, and so on.
23897 * @param $ctm (array) tranformation matrix for clipping mode (starting transformation matrix).
23898 * @author Nicola Asuni
23899 * @since 5.0.000 (2010-05-02)
23900 * @protected
23901 */
23902 protected function startSVGElementHandler($parser, $name, $attribs, $ctm=array()) {
23903 // check if we are in clip mode
23904 if ($this->svgclipmode) {
23905 $this->svgclippaths[$this->svgclipid][] = array('name' => $name, 'attribs' => $attribs, 'tm' => $this->svgcliptm[$this->svgclipid]);
23906 return;
23907 }
23908 if ($this->svgdefsmode AND !in_array($name, array('clipPath', 'linearGradient', 'radialGradient', 'stop'))) {
23909 if (isset($attribs['id'])) {
23910 $attribs['child_elements'] = array();
23911 $this->svgdefs[$attribs['id']] = array('name' => $name, 'attribs' => $attribs);
23912 return;
23913 }
23914 if (end($this->svgdefs) !== FALSE) {
23915 $last_svgdefs_id = key($this->svgdefs);
23916 if (isset($this->svgdefs[$last_svgdefs_id]['attribs']['child_elements'])) {
23917 $attribs['id'] = 'DF_'.(count($this->svgdefs[$last_svgdefs_id]['attribs']['child_elements']) + 1);
23918 $this->svgdefs[$last_svgdefs_id]['attribs']['child_elements'][$attribs['id']] = array('name' => $name, 'attribs' => $attribs);
23919 return;
23920 }
23921 }
23922 return;
23923 }
23924 $clipping = false;
23925 if ($parser == 'clip-path') {
23926 // set clipping mode
23927 $clipping = true;
23928 }
23929 // get styling properties
23930 $prev_svgstyle = $this->svgstyles[max(0,(count($this->svgstyles) - 1))]; // previous style
23931 $svgstyle = $this->svgstyles[0]; // set default style
23932 if ($clipping AND !isset($attribs['fill']) AND (!isset($attribs['style']) OR (!preg_match('/[;\"\s]{1}fill[\s]*:[\s]*([^;\"]*)/si', $attribs['style'], $attrval)))) {
23933 // default fill attribute for clipping
23934 $attribs['fill'] = 'none';
23935 }
23936 if (isset($attribs['style']) AND !TCPDF_STATIC::empty_string($attribs['style']) AND ($attribs['style'][0] != ';')) {
23937 // fix style for regular expression
23938 $attribs['style'] = ';'.$attribs['style'];
23939 }
23940 foreach ($prev_svgstyle as $key => $val) {
23941 if (in_array($key, TCPDF_IMAGES::$svginheritprop)) {
23942 // inherit previous value
23943 $svgstyle[$key] = $val;
23944 }
23945 if (isset($attribs[$key]) AND !TCPDF_STATIC::empty_string($attribs[$key])) {
23946 // specific attribute settings
23947 if ($attribs[$key] == 'inherit') {
23948 $svgstyle[$key] = $val;
23949 } else {
23950 $svgstyle[$key] = $attribs[$key];
23951 }
23952 } elseif (isset($attribs['style']) AND !TCPDF_STATIC::empty_string($attribs['style'])) {
23953 // CSS style syntax
23954 $attrval = array();
23955 if (preg_match('/[;\"\s]{1}'.$key.'[\s]*:[\s]*([^;\"]*)/si', $attribs['style'], $attrval) AND isset($attrval[1])) {
23956 if ($attrval[1] == 'inherit') {
23957 $svgstyle[$key] = $val;
23958 } else {
23959 $svgstyle[$key] = $attrval[1];
23960 }
23961 }
23962 }
23963 }
23964 // transformation matrix
23965 if (!empty($ctm)) {
23966 $tm = $ctm;
23967 } else {
23968 $tm = array(1,0,0,1,0,0);
23969 }
23970 if (isset($attribs['transform']) AND !empty($attribs['transform'])) {
23971 $tm = TCPDF_STATIC::getTransformationMatrixProduct($tm, TCPDF_STATIC::getSVGTransformMatrix($attribs['transform']));
23972 }
23973 $svgstyle['transfmatrix'] = $tm;
23974 $invisible = false;
23975 if (($svgstyle['visibility'] == 'hidden') OR ($svgstyle['visibility'] == 'collapse') OR ($svgstyle['display'] == 'none')) {
23976 // the current graphics element is invisible (nothing is painted)
23977 $invisible = true;
23978 }
23979 // process tag
23980 switch($name) {
23981 case 'defs': {
23982 $this->svgdefsmode = true;
23983 break;
23984 }
23985 // clipPath
23986 case 'clipPath': {
23987 if ($invisible) {
23988 break;
23989 }
23990 $this->svgclipmode = true;
23991 if (!isset($attribs['id'])) {
23992 $attribs['id'] = 'CP_'.(count($this->svgcliptm) + 1);
23993 }
23994 $this->svgclipid = $attribs['id'];
23995 $this->svgclippaths[$this->svgclipid] = array();
23996 $this->svgcliptm[$this->svgclipid] = $tm;
23997 break;
23998 }
23999 case 'svg': {
24000 // start of SVG object
24001 break;
24002 }
24003 case 'g': {
24004 // group together related graphics elements
24005 array_push($this->svgstyles, $svgstyle);
24006 $this->StartTransform();
24007 $x = (isset($attribs['x'])?$attribs['x']:0);
24008 $y = (isset($attribs['y'])?$attribs['y']:0);
24009 $w = 1;//(isset($attribs['width'])?$attribs['width']:1);
24010 $h = 1;//(isset($attribs['height'])?$attribs['height']:1);
24011 $tm = TCPDF_STATIC::getTransformationMatrixProduct($tm, array($w, 0, 0, $h, $x, $y));
24012 $this->SVGTransform($tm);
24013 $this->setSVGStyles($svgstyle, $prev_svgstyle);
24014 break;
24015 }
24016 case 'linearGradient': {
24017 if ($this->pdfa_mode) {
24018 break;
24019 }
24020 if (!isset($attribs['id'])) {
24021 $attribs['id'] = 'GR_'.(count($this->svggradients) + 1);
24022 }
24023 $this->svggradientid = $attribs['id'];
24024 $this->svggradients[$this->svggradientid] = array();
24025 $this->svggradients[$this->svggradientid]['type'] = 2;
24026 $this->svggradients[$this->svggradientid]['stops'] = array();
24027 if (isset($attribs['gradientUnits'])) {
24028 $this->svggradients[$this->svggradientid]['gradientUnits'] = $attribs['gradientUnits'];
24029 } else {
24030 $this->svggradients[$this->svggradientid]['gradientUnits'] = 'objectBoundingBox';
24031 }
24032 //$attribs['spreadMethod']
24033 if (((!isset($attribs['x1'])) AND (!isset($attribs['y1'])) AND (!isset($attribs['x2'])) AND (!isset($attribs['y2'])))
24034 OR ((isset($attribs['x1']) AND (substr($attribs['x1'], -1) == '%'))
24035 OR (isset($attribs['y1']) AND (substr($attribs['y1'], -1) == '%'))
24036 OR (isset($attribs['x2']) AND (substr($attribs['x2'], -1) == '%'))
24037 OR (isset($attribs['y2']) AND (substr($attribs['y2'], -1) == '%')))) {
24038 $this->svggradients[$this->svggradientid]['mode'] = 'percentage';
24039 } else {
24040 $this->svggradients[$this->svggradientid]['mode'] = 'measure';
24041 }
24042 $x1 = (isset($attribs['x1'])?$attribs['x1']:'0');
24043 $y1 = (isset($attribs['y1'])?$attribs['y1']:'0');
24044 $x2 = (isset($attribs['x2'])?$attribs['x2']:'100');
24045 $y2 = (isset($attribs['y2'])?$attribs['y2']:'0');
24046 if (isset($attribs['gradientTransform'])) {
24047 $this->svggradients[$this->svggradientid]['gradientTransform'] = TCPDF_STATIC::getSVGTransformMatrix($attribs['gradientTransform']);
24048 }
24049 $this->svggradients[$this->svggradientid]['coords'] = array($x1, $y1, $x2, $y2);
24050 if (isset($attribs['xlink:href']) AND !empty($attribs['xlink:href'])) {
24051 // gradient is defined on another place
24052 $this->svggradients[$this->svggradientid]['xref'] = substr($attribs['xlink:href'], 1);
24053 }
24054 break;
24055 }
24056 case 'radialGradient': {
24057 if ($this->pdfa_mode) {
24058 break;
24059 }
24060 if (!isset($attribs['id'])) {
24061 $attribs['id'] = 'GR_'.(count($this->svggradients) + 1);
24062 }
24063 $this->svggradientid = $attribs['id'];
24064 $this->svggradients[$this->svggradientid] = array();
24065 $this->svggradients[$this->svggradientid]['type'] = 3;
24066 $this->svggradients[$this->svggradientid]['stops'] = array();
24067 if (isset($attribs['gradientUnits'])) {
24068 $this->svggradients[$this->svggradientid]['gradientUnits'] = $attribs['gradientUnits'];
24069 } else {
24070 $this->svggradients[$this->svggradientid]['gradientUnits'] = 'objectBoundingBox';
24071 }
24072 //$attribs['spreadMethod']
24073 if (((!isset($attribs['cx'])) AND (!isset($attribs['cy'])))
24074 OR ((isset($attribs['cx']) AND (substr($attribs['cx'], -1) == '%'))
24075 OR (isset($attribs['cy']) AND (substr($attribs['cy'], -1) == '%')))) {
24076 $this->svggradients[$this->svggradientid]['mode'] = 'percentage';
24077 } elseif (isset($attribs['r']) AND is_numeric($attribs['r']) AND ($attribs['r']) <= 1) {
24078 $this->svggradients[$this->svggradientid]['mode'] = 'ratio';
24079 } else {
24080 $this->svggradients[$this->svggradientid]['mode'] = 'measure';
24081 }
24082 $cx = (isset($attribs['cx']) ? $attribs['cx'] : 0.5);
24083 $cy = (isset($attribs['cy']) ? $attribs['cy'] : 0.5);
24084 $fx = (isset($attribs['fx']) ? $attribs['fx'] : $cx);
24085 $fy = (isset($attribs['fy']) ? $attribs['fy'] : $cy);
24086 $r = (isset($attribs['r']) ? $attribs['r'] : 0.5);
24087 if (isset($attribs['gradientTransform'])) {
24088 $this->svggradients[$this->svggradientid]['gradientTransform'] = TCPDF_STATIC::getSVGTransformMatrix($attribs['gradientTransform']);
24089 }
24090 $this->svggradients[$this->svggradientid]['coords'] = array($cx, $cy, $fx, $fy, $r);
24091 if (isset($attribs['xlink:href']) AND !empty($attribs['xlink:href'])) {
24092 // gradient is defined on another place
24093 $this->svggradients[$this->svggradientid]['xref'] = substr($attribs['xlink:href'], 1);
24094 }
24095 break;
24096 }
24097 case 'stop': {
24098 // gradient stops
24099 if (substr($attribs['offset'], -1) == '%') {
24100 $offset = floatval(substr($attribs['offset'], -1)) / 100;
24101 } else {
24102 $offset = floatval($attribs['offset']);
24103 if ($offset > 1) {
24104 $offset /= 100;
24105 }
24106 }
24107 $stop_color = isset($svgstyle['stop-color'])?TCPDF_COLORS::convertHTMLColorToDec($svgstyle['stop-color'], $this->spot_colors):'black';
24108 $opacity = isset($svgstyle['stop-opacity'])?$svgstyle['stop-opacity']:1;
24109 $this->svggradients[$this->svggradientid]['stops'][] = array('offset' => $offset, 'color' => $stop_color, 'opacity' => $opacity);
24110 break;
24111 }
24112 // paths
24113 case 'path': {
24114 if ($invisible) {
24115 break;
24116 }
24117 if (isset($attribs['d'])) {
24118 $d = trim($attribs['d']);
24119 if (!empty($d)) {
24120 $x = (isset($attribs['x'])?$attribs['x']:0);
24121 $y = (isset($attribs['y'])?$attribs['y']:0);
24122 $w = (isset($attribs['width'])?$attribs['width']:1);
24123 $h = (isset($attribs['height'])?$attribs['height']:1);
24124 $tm = TCPDF_STATIC::getTransformationMatrixProduct($tm, array($w, 0, 0, $h, $x, $y));
24125 if ($clipping) {
24126 $this->SVGTransform($tm);
24127 $this->SVGPath($d, 'CNZ');
24128 } else {
24129 $this->StartTransform();
24130 $this->SVGTransform($tm);
24131 $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'SVGPath', array($d, 'CNZ'));
24132 if (!empty($obstyle)) {
24133 $this->SVGPath($d, $obstyle);
24134 }
24135 $this->StopTransform();
24136 }
24137 }
24138 }
24139 break;
24140 }
24141 // shapes
24142 case 'rect': {
24143 if ($invisible) {
24144 break;
24145 }
24146 $x = (isset($attribs['x'])?$this->getHTMLUnitToUnits($attribs['x'], 0, $this->svgunit, false):0);
24147 $y = (isset($attribs['y'])?$this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false):0);
24148 $w = (isset($attribs['width'])?$this->getHTMLUnitToUnits($attribs['width'], 0, $this->svgunit, false):0);
24149 $h = (isset($attribs['height'])?$this->getHTMLUnitToUnits($attribs['height'], 0, $this->svgunit, false):0);
24150 $rx = (isset($attribs['rx'])?$this->getHTMLUnitToUnits($attribs['rx'], 0, $this->svgunit, false):0);
24151 $ry = (isset($attribs['ry'])?$this->getHTMLUnitToUnits($attribs['ry'], 0, $this->svgunit, false):$rx);
24152 if ($clipping) {
24153 $this->SVGTransform($tm);
24154 $this->RoundedRectXY($x, $y, $w, $h, $rx, $ry, '1111', 'CNZ', array(), array());
24155 } else {
24156 $this->StartTransform();
24157 $this->SVGTransform($tm);
24158 $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'RoundedRectXY', array($x, $y, $w, $h, $rx, $ry, '1111', 'CNZ'));
24159 if (!empty($obstyle)) {
24160 $this->RoundedRectXY($x, $y, $w, $h, $rx, $ry, '1111', $obstyle, array(), array());
24161 }
24162 $this->StopTransform();
24163 }
24164 break;
24165 }
24166 case 'circle': {
24167 if ($invisible) {
24168 break;
24169 }
24170 $r = (isset($attribs['r']) ? $this->getHTMLUnitToUnits($attribs['r'], 0, $this->svgunit, false) : 0);
24171 $cx = (isset($attribs['cx']) ? $this->getHTMLUnitToUnits($attribs['cx'], 0, $this->svgunit, false) : (isset($attribs['x']) ? $this->getHTMLUnitToUnits($attribs['x'], 0, $this->svgunit, false) : 0));
24172 $cy = (isset($attribs['cy']) ? $this->getHTMLUnitToUnits($attribs['cy'], 0, $this->svgunit, false) : (isset($attribs['y']) ? $this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false) : 0));
24173 $x = ($cx - $r);
24174 $y = ($cy - $r);
24175 $w = (2 * $r);
24176 $h = $w;
24177 if ($clipping) {
24178 $this->SVGTransform($tm);
24179 $this->Circle($cx, $cy, $r, 0, 360, 'CNZ', array(), array(), 8);
24180 } else {
24181 $this->StartTransform();
24182 $this->SVGTransform($tm);
24183 $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'Circle', array($cx, $cy, $r, 0, 360, 'CNZ'));
24184 if (!empty($obstyle)) {
24185 $this->Circle($cx, $cy, $r, 0, 360, $obstyle, array(), array(), 8);
24186 }
24187 $this->StopTransform();
24188 }
24189 break;
24190 }
24191 case 'ellipse': {
24192 if ($invisible) {
24193 break;
24194 }
24195 $rx = (isset($attribs['rx']) ? $this->getHTMLUnitToUnits($attribs['rx'], 0, $this->svgunit, false) : 0);
24196 $ry = (isset($attribs['ry']) ? $this->getHTMLUnitToUnits($attribs['ry'], 0, $this->svgunit, false) : 0);
24197 $cx = (isset($attribs['cx']) ? $this->getHTMLUnitToUnits($attribs['cx'], 0, $this->svgunit, false) : (isset($attribs['x']) ? $this->getHTMLUnitToUnits($attribs['x'], 0, $this->svgunit, false) : 0));
24198 $cy = (isset($attribs['cy']) ? $this->getHTMLUnitToUnits($attribs['cy'], 0, $this->svgunit, false) : (isset($attribs['y']) ? $this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false) : 0));
24199 $x = ($cx - $rx);
24200 $y = ($cy - $ry);
24201 $w = (2 * $rx);
24202 $h = (2 * $ry);
24203 if ($clipping) {
24204 $this->SVGTransform($tm);
24205 $this->Ellipse($cx, $cy, $rx, $ry, 0, 0, 360, 'CNZ', array(), array(), 8);
24206 } else {
24207 $this->StartTransform();
24208 $this->SVGTransform($tm);
24209 $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'Ellipse', array($cx, $cy, $rx, $ry, 0, 0, 360, 'CNZ'));
24210 if (!empty($obstyle)) {
24211 $this->Ellipse($cx, $cy, $rx, $ry, 0, 0, 360, $obstyle, array(), array(), 8);
24212 }
24213 $this->StopTransform();
24214 }
24215 break;
24216 }
24217 case 'line': {
24218 if ($invisible) {
24219 break;
24220 }
24221 $x1 = (isset($attribs['x1'])?$this->getHTMLUnitToUnits($attribs['x1'], 0, $this->svgunit, false):0);
24222 $y1 = (isset($attribs['y1'])?$this->getHTMLUnitToUnits($attribs['y1'], 0, $this->svgunit, false):0);
24223 $x2 = (isset($attribs['x2'])?$this->getHTMLUnitToUnits($attribs['x2'], 0, $this->svgunit, false):0);
24224 $y2 = (isset($attribs['y2'])?$this->getHTMLUnitToUnits($attribs['y2'], 0, $this->svgunit, false):0);
24225 $x = $x1;
24226 $y = $y1;
24227 $w = abs($x2 - $x1);
24228 $h = abs($y2 - $y1);
24229 if (!$clipping) {
24230 $this->StartTransform();
24231 $this->SVGTransform($tm);
24232 $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'Line', array($x1, $y1, $x2, $y2));
24233 $this->Line($x1, $y1, $x2, $y2);
24234 $this->StopTransform();
24235 }
24236 break;
24237 }
24238 case 'polyline':
24239 case 'polygon': {
24240 if ($invisible) {
24241 break;
24242 }
24243 $points = (isset($attribs['points'])?$attribs['points']:'0 0');
24244 $points = trim($points);
24245 // note that point may use a complex syntax not covered here
24246 $points = preg_split('/[\,\s]+/si', $points);
24247 if (count($points) < 4) {
24248 break;
24249 }
24250 $p = array();
24251 $xmin = 2147483647;
24252 $xmax = 0;
24253 $ymin = 2147483647;
24254 $ymax = 0;
24255 foreach ($points as $key => $val) {
24256 $p[$key] = $this->getHTMLUnitToUnits($val, 0, $this->svgunit, false);
24257 if (($key % 2) == 0) {
24258 // X coordinate
24259 $xmin = min($xmin, $p[$key]);
24260 $xmax = max($xmax, $p[$key]);
24261 } else {
24262 // Y coordinate
24263 $ymin = min($ymin, $p[$key]);
24264 $ymax = max($ymax, $p[$key]);
24265 }
24266 }
24267 $x = $xmin;
24268 $y = $ymin;
24269 $w = ($xmax - $xmin);
24270 $h = ($ymax - $ymin);
24271 if ($name == 'polyline') {
24272 $this->StartTransform();
24273 $this->SVGTransform($tm);
24274 $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'PolyLine', array($p, 'CNZ'));
24275 if (!empty($obstyle)) {
24276 $this->PolyLine($p, $obstyle, array(), array());
24277 }
24278 $this->StopTransform();
24279 } else { // polygon
24280 if ($clipping) {
24281 $this->SVGTransform($tm);
24282 $this->Polygon($p, 'CNZ', array(), array(), true);
24283 } else {
24284 $this->StartTransform();
24285 $this->SVGTransform($tm);
24286 $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h, 'Polygon', array($p, 'CNZ'));
24287 if (!empty($obstyle)) {
24288 $this->Polygon($p, $obstyle, array(), array(), true);
24289 }
24290 $this->StopTransform();
24291 }
24292 }
24293 break;
24294 }
24295 // image
24296 case 'image': {
24297 if ($invisible) {
24298 break;
24299 }
24300 if (!isset($attribs['xlink:href']) OR empty($attribs['xlink:href'])) {
24301 break;
24302 }
24303 $x = (isset($attribs['x'])?$this->getHTMLUnitToUnits($attribs['x'], 0, $this->svgunit, false):0);
24304 $y = (isset($attribs['y'])?$this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false):0);
24305 $w = (isset($attribs['width'])?$this->getHTMLUnitToUnits($attribs['width'], 0, $this->svgunit, false):0);
24306 $h = (isset($attribs['height'])?$this->getHTMLUnitToUnits($attribs['height'], 0, $this->svgunit, false):0);
24307 $img = $attribs['xlink:href'];
24308 if (!$clipping) {
24309 $this->StartTransform();
24310 $this->SVGTransform($tm);
24311 $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, $w, $h);
24312 if (preg_match('/^data:image\/[^;]+;base64,/', $img, $m) > 0) {
24313 // embedded image encoded as base64
24314 $img = '@'.base64_decode(substr($img, strlen($m[0])));
24315 } else {
24316 // fix image path
24317 if (!TCPDF_STATIC::empty_string($this->svgdir) AND (($img[0] == '.') OR (basename($img) == $img))) {
24318 // replace relative path with full server path
24319 $img = $this->svgdir.'/'.$img;
24320 }
24321 if (($img[0] == '/') AND !empty($_SERVER['DOCUMENT_ROOT']) AND ($_SERVER['DOCUMENT_ROOT'] != '/')) {
24322 $findroot = strpos($img, $_SERVER['DOCUMENT_ROOT']);
24323 if (($findroot === false) OR ($findroot > 1)) {
24324 if (substr($_SERVER['DOCUMENT_ROOT'], -1) == '/') {
24325 $img = substr($_SERVER['DOCUMENT_ROOT'], 0, -1).$img;
24326 } else {
24327 $img = $_SERVER['DOCUMENT_ROOT'].$img;
24328 }
24329 }
24330 }
24331 $img = urldecode($img);
24332 $testscrtype = @parse_url($img);
24333 if (!isset($testscrtype['query']) OR empty($testscrtype['query'])) {
24334 // convert URL to server path
24335 $img = str_replace(K_PATH_URL, K_PATH_MAIN, $img);
24336 }
24337 }
24338 // get image type
24339 $imgtype = TCPDF_IMAGES::getImageFileType($img);
24340 if (($imgtype == 'eps') OR ($imgtype == 'ai')) {
24341 $this->ImageEps($img, $x, $y, $w, $h);
24342 } elseif ($imgtype == 'svg') {
24343 $this->ImageSVG($img, $x, $y, $w, $h);
24344 } else {
24345 $this->Image($img, $x, $y, $w, $h);
24346 }
24347 $this->StopTransform();
24348 }
24349 break;
24350 }
24351 // text
24352 case 'text':
24353 case 'tspan': {
24354 // only basic support - advanced features must be implemented
24355 $this->svgtextmode['invisible'] = $invisible;
24356 if ($invisible) {
24357 break;
24358 }
24359 array_push($this->svgstyles, $svgstyle);
24360 if (isset($attribs['x'])) {
24361 $x = $this->getHTMLUnitToUnits($attribs['x'], 0, $this->svgunit, false);
24362 } elseif ($name == 'tspan') {
24363 $x = $this->x;
24364 } else {
24365 $x = 0;
24366 }
24367 if (isset($attribs['dx'])) {
24368 $x += $this->getHTMLUnitToUnits($attribs['dx'], 0, $this->svgunit, false);
24369 }
24370 if (isset($attribs['y'])) {
24371 $y = $this->getHTMLUnitToUnits($attribs['y'], 0, $this->svgunit, false);
24372 } elseif ($name == 'tspan') {
24373 $y = $this->y;
24374 } else {
24375 $y = 0;
24376 }
24377 if (isset($attribs['dy'])) {
24378 $y += $this->getHTMLUnitToUnits($attribs['dy'], 0, $this->svgunit, false);
24379 }
24380 $svgstyle['text-color'] = $svgstyle['fill'];
24381 $this->svgtext = '';
24382 if (isset($svgstyle['text-anchor'])) {
24383 $this->svgtextmode['text-anchor'] = $svgstyle['text-anchor'];
24384 } else {
24385 $this->svgtextmode['text-anchor'] = 'start';
24386 }
24387 if (isset($svgstyle['direction'])) {
24388 if ($svgstyle['direction'] == 'rtl') {
24389 $this->svgtextmode['rtl'] = true;
24390 } else {
24391 $this->svgtextmode['rtl'] = false;
24392 }
24393 } else {
24394 $this->svgtextmode['rtl'] = false;
24395 }
24396 if (isset($svgstyle['stroke']) AND ($svgstyle['stroke'] != 'none') AND isset($svgstyle['stroke-width']) AND ($svgstyle['stroke-width'] > 0)) {
24397 $this->svgtextmode['stroke'] = $this->getHTMLUnitToUnits($svgstyle['stroke-width'], 0, $this->svgunit, false);
24398 } else {
24399 $this->svgtextmode['stroke'] = false;
24400 }
24401 $this->StartTransform();
24402 $this->SVGTransform($tm);
24403 $obstyle = $this->setSVGStyles($svgstyle, $prev_svgstyle, $x, $y, 1, 1);
24404 $this->x = $x;
24405 $this->y = $y;
24406 break;
24407 }
24408 // use
24409 case 'use': {
24410 if (isset($attribs['xlink:href']) AND !empty($attribs['xlink:href'])) {
24411 $svgdefid = substr($attribs['xlink:href'], 1);
24412 if (isset($this->svgdefs[$svgdefid])) {
24413 $use = $this->svgdefs[$svgdefid];
24414 if (isset($attribs['xlink:href'])) {
24415 unset($attribs['xlink:href']);
24416 }
24417 if (isset($attribs['id'])) {
24418 unset($attribs['id']);
24419 }
24420 if (isset($use['attribs']['x']) AND isset($attribs['x'])) {
24421 $attribs['x'] += $use['attribs']['x'];
24422 }
24423 if (isset($use['attribs']['y']) AND isset($attribs['y'])) {
24424 $attribs['y'] += $use['attribs']['y'];
24425 }
24426 if (empty($attribs['style'])) {
24427 $attribs['style'] = '';
24428 }
24429 if (!empty($use['attribs']['style'])) {
24430 // merge styles
24431 $attribs['style'] = str_replace(';;',';',';'.$use['attribs']['style'].$attribs['style']);
24432 }
24433 $attribs = array_merge($use['attribs'], $attribs);
24434 $this->startSVGElementHandler($parser, $use['name'], $attribs);
24435 return;
24436 }
24437 }
24438 break;
24439 }
24440 default: {
24441 break;
24442 }
24443 } // end of switch
24444 // process child elements
24445 if (!empty($attribs['child_elements'])) {
24446 $child_elements = $attribs['child_elements'];
24447 unset($attribs['child_elements']);
24448 foreach($child_elements as $child_element) {
24449 if (empty($child_element['attribs']['closing_tag'])) {
24450 $this->startSVGElementHandler('child-tag', $child_element['name'], $child_element['attribs']);
24451 } else {
24452 if (isset($child_element['attribs']['content'])) {
24453 $this->svgtext = $child_element['attribs']['content'];
24454 }
24455 $this->endSVGElementHandler('child-tag', $child_element['name']);
24456 }
24457 }
24458 }
24459 }
24460
24461 /**
24462 * Sets the closing SVG element handler function for the XML parser.
24463 * @param $parser (resource) The first parameter, parser, is a reference to the XML parser calling the handler.
24464 * @param $name (string) The second parameter, name, contains the name of the element for which this handler is called. If case-folding is in effect for this parser, the element name will be in uppercase letters.
24465 * @author Nicola Asuni
24466 * @since 5.0.000 (2010-05-02)
24467 * @protected
24468 */
24469 protected function endSVGElementHandler($parser, $name) {
24470 if ($this->svgdefsmode AND !in_array($name, array('defs', 'clipPath', 'linearGradient', 'radialGradient', 'stop'))) {;
24471 if (end($this->svgdefs) !== FALSE) {
24472 $last_svgdefs_id = key($this->svgdefs);
24473 if (isset($this->svgdefs[$last_svgdefs_id]['attribs']['child_elements'])) {
24474 foreach($this->svgdefs[$last_svgdefs_id]['attribs']['child_elements'] as $child_element) {
24475 if (isset($child_element['attribs']['id']) AND ($child_element['name'] == $name)) {
24476 $this->svgdefs[$last_svgdefs_id]['attribs']['child_elements'][$child_element['attribs']['id'].'_CLOSE'] = array('name' => $name, 'attribs' => array('closing_tag' => TRUE, 'content' => $this->svgtext));
24477 return;
24478 }
24479 }
24480 if ($this->svgdefs[$last_svgdefs_id]['name'] == $name) {
24481 $this->svgdefs[$last_svgdefs_id]['attribs']['child_elements'][$last_svgdefs_id.'_CLOSE'] = array('name' => $name, 'attribs' => array('closing_tag' => TRUE, 'content' => $this->svgtext));
24482 return;
24483 }
24484 }
24485 }
24486 return;
24487 }
24488 switch($name) {
24489 case 'defs': {
24490 $this->svgdefsmode = false;
24491 break;
24492 }
24493 // clipPath
24494 case 'clipPath': {
24495 $this->svgclipmode = false;
24496 break;
24497 }
24498 case 'g': {
24499 // ungroup: remove last style from array
24500 array_pop($this->svgstyles);
24501 $this->StopTransform();
24502 break;
24503 }
24504 case 'text':
24505 case 'tspan': {
24506 if ($this->svgtextmode['invisible']) {
24507 // This implementation must be fixed to following the rule:
24508 // If the 'visibility' property is set to hidden on a 'tspan', 'tref' or 'altGlyph' element, then the text is invisible but still takes up space in text layout calculations.
24509 break;
24510 }
24511 // print text
24512 $text = $this->svgtext;
24513 //$text = $this->stringTrim($text);
24514 $textlen = $this->GetStringWidth($text);
24515 if ($this->svgtextmode['text-anchor'] != 'start') {
24516 // check if string is RTL text
24517 if ($this->svgtextmode['text-anchor'] == 'end') {
24518 if ($this->svgtextmode['rtl']) {
24519 $this->x += $textlen;
24520 } else {
24521 $this->x -= $textlen;
24522 }
24523 } elseif ($this->svgtextmode['text-anchor'] == 'middle') {
24524 if ($this->svgtextmode['rtl']) {
24525 $this->x += ($textlen / 2);
24526 } else {
24527 $this->x -= ($textlen / 2);
24528 }
24529 }
24530 }
24531 $textrendermode = $this->textrendermode;
24532 $textstrokewidth = $this->textstrokewidth;
24533 $this->setTextRenderingMode($this->svgtextmode['stroke'], true, false);
24534 if ($name == 'text') {
24535 // store current coordinates
24536 $tmpx = $this->x;
24537 $tmpy = $this->y;
24538 }
24539 $this->Cell($textlen, 0, $text, 0, 0, '', false, '', 0, false, 'L', 'T');
24540 if ($name == 'text') {
24541 // restore coordinates
24542 $this->x = $tmpx;
24543 $this->y = $tmpy;
24544 }
24545 // restore previous rendering mode
24546 $this->textrendermode = $textrendermode;
24547 $this->textstrokewidth = $textstrokewidth;
24548 $this->svgtext = '';
24549 $this->StopTransform();
24550 if (!$this->svgdefsmode) {
24551 array_pop($this->svgstyles);
24552 }
24553 break;
24554 }
24555 default: {
24556 break;
24557 }
24558 }
24559 }
24560
24561 /**
24562 * Sets the character data handler function for the XML parser.
24563 * @param $parser (resource) The first parameter, parser, is a reference to the XML parser calling the handler.
24564 * @param $data (string) The second parameter, data, contains the character data as a string.
24565 * @author Nicola Asuni
24566 * @since 5.0.000 (2010-05-02)
24567 * @protected
24568 */
24569 protected function segSVGContentHandler($parser, $data) {
24570 $this->svgtext .= $data;
24571 }
24572
24573 // --- END SVG METHODS -----------------------------------------------------
24574
24575} // END OF TCPDF CLASS
24576
24577//============================================================+
24578// END OF FILE
24579//============================================================+
diff --git a/inc/3rdparty/libraries/tcpdf/tcpdf_autoconfig.php b/inc/3rdparty/libraries/tcpdf/tcpdf_autoconfig.php
new file mode 100644
index 00000000..951c0b0f
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/tcpdf_autoconfig.php
@@ -0,0 +1,242 @@
1<?php
2//============================================================+
3// File name : tcpdf_autoconfig.php
4// Version : 1.0.000
5// Begin : 2013-05-16
6// Last Update : 2014-09-02
7// Authors : 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) 2011-2014 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 : Try to automatically configure some TCPDF
32// constants if not defined.
33//
34//============================================================+
35
36/**
37 * @file
38 * Try to automatically configure some TCPDF constants if not defined.
39 * @package com.tecnick.tcpdf
40 * @version 1.0.000
41 */
42
43// DOCUMENT_ROOT fix for IIS Webserver
44if ((!isset($_SERVER['DOCUMENT_ROOT'])) OR (empty($_SERVER['DOCUMENT_ROOT']))) {
45 if(isset($_SERVER['SCRIPT_FILENAME'])) {
46 $_SERVER['DOCUMENT_ROOT'] = str_replace( '\\', '/', substr($_SERVER['SCRIPT_FILENAME'], 0, 0-strlen($_SERVER['PHP_SELF'])));
47 } elseif(isset($_SERVER['PATH_TRANSLATED'])) {
48 $_SERVER['DOCUMENT_ROOT'] = str_replace( '\\', '/', substr(str_replace('\\\\', '\\', $_SERVER['PATH_TRANSLATED']), 0, 0-strlen($_SERVER['PHP_SELF'])));
49 } else {
50 // define here your DOCUMENT_ROOT path if the previous fails (e.g. '/var/www')
51 $_SERVER['DOCUMENT_ROOT'] = '/';
52 }
53}
54$_SERVER['DOCUMENT_ROOT'] = str_replace('//', '/', $_SERVER['DOCUMENT_ROOT']);
55if (substr($_SERVER['DOCUMENT_ROOT'], -1) != '/') {
56 $_SERVER['DOCUMENT_ROOT'] .= '/';
57}
58
59// Load main configuration file only if the K_TCPDF_EXTERNAL_CONFIG constant is set to false.
60if (!defined('K_TCPDF_EXTERNAL_CONFIG') OR !K_TCPDF_EXTERNAL_CONFIG) {
61 // define a list of default config files in order of priority
62 $tcpdf_config_files = array(dirname(__FILE__).'/config/tcpdf_config.php', '/etc/php-tcpdf/tcpdf_config.php', '/etc/tcpdf/tcpdf_config.php', '/etc/tcpdf_config.php');
63 foreach ($tcpdf_config_files as $tcpdf_config) {
64 if (@file_exists($tcpdf_config) AND is_readable($tcpdf_config)) {
65 require_once($tcpdf_config);
66 break;
67 }
68 }
69}
70
71if (!defined('K_PATH_MAIN')) {
72 define ('K_PATH_MAIN', dirname(__FILE__).'/');
73}
74
75if (!defined('K_PATH_FONTS')) {
76 define ('K_PATH_FONTS', K_PATH_MAIN.'fonts/');
77}
78
79if (!defined('K_PATH_URL')) {
80 $k_path_url = K_PATH_MAIN; // default value for console mode
81 if (isset($_SERVER['HTTP_HOST']) AND (!empty($_SERVER['HTTP_HOST']))) {
82 if(isset($_SERVER['HTTPS']) AND (!empty($_SERVER['HTTPS'])) AND (strtolower($_SERVER['HTTPS']) != 'off')) {
83 $k_path_url = 'https://';
84 } else {
85 $k_path_url = 'http://';
86 }
87 $k_path_url .= $_SERVER['HTTP_HOST'];
88 $k_path_url .= str_replace( '\\', '/', substr(K_PATH_MAIN, (strlen($_SERVER['DOCUMENT_ROOT']) - 1)));
89 }
90 define ('K_PATH_URL', $k_path_url);
91}
92
93if (!defined('K_PATH_IMAGES')) {
94 $tcpdf_images_dirs = array(K_PATH_MAIN.'examples/images/', K_PATH_MAIN.'images/', '/usr/share/doc/php-tcpdf/examples/images/', '/usr/share/doc/tcpdf/examples/images/', '/usr/share/doc/php/tcpdf/examples/images/', '/var/www/tcpdf/images/', '/var/www/html/tcpdf/images/', '/usr/local/apache2/htdocs/tcpdf/images/', K_PATH_MAIN);
95 foreach ($tcpdf_images_dirs as $tcpdf_images_path) {
96 if (@file_exists($tcpdf_images_path)) {
97 break;
98 }
99 }
100 define ('K_PATH_IMAGES', $tcpdf_images_path);
101}
102
103if (!defined('PDF_HEADER_LOGO')) {
104 $tcpdf_header_logo = '';
105 if (@file_exists(K_PATH_IMAGES.'tcpdf_logo.jpg')) {
106 $tcpdf_header_logo = 'tcpdf_logo.jpg';
107 }
108 define ('PDF_HEADER_LOGO', $tcpdf_header_logo);
109}
110
111if (!defined('PDF_HEADER_LOGO_WIDTH')) {
112 if (!empty($tcpdf_header_logo)) {
113 define ('PDF_HEADER_LOGO_WIDTH', 30);
114 } else {
115 define ('PDF_HEADER_LOGO_WIDTH', 0);
116 }
117}
118
119if (!defined('K_PATH_CACHE')) {
120 $K_PATH_CACHE = ini_get('upload_tmp_dir') ? ini_get('upload_tmp_dir') : sys_get_temp_dir();
121 if (substr($K_PATH_CACHE, -1) != '/') {
122 $K_PATH_CACHE .= '/';
123 }
124 define ('K_PATH_CACHE', $K_PATH_CACHE);
125}
126
127if (!defined('K_BLANK_IMAGE')) {
128 define ('K_BLANK_IMAGE', '_blank.png');
129}
130
131if (!defined('PDF_PAGE_FORMAT')) {
132 define ('PDF_PAGE_FORMAT', 'A4');
133}
134
135if (!defined('PDF_PAGE_ORIENTATION')) {
136 define ('PDF_PAGE_ORIENTATION', 'P');
137}
138
139if (!defined('PDF_CREATOR')) {
140 define ('PDF_CREATOR', 'TCPDF');
141}
142
143if (!defined('PDF_AUTHOR')) {
144 define ('PDF_AUTHOR', 'TCPDF');
145}
146
147if (!defined('PDF_HEADER_TITLE')) {
148 define ('PDF_HEADER_TITLE', 'TCPDF Example');
149}
150
151if (!defined('PDF_HEADER_STRING')) {
152 define ('PDF_HEADER_STRING', "by Nicola Asuni - Tecnick.com\nwww.tcpdf.org");
153}
154
155if (!defined('PDF_UNIT')) {
156 define ('PDF_UNIT', 'mm');
157}
158
159if (!defined('PDF_MARGIN_HEADER')) {
160 define ('PDF_MARGIN_HEADER', 5);
161}
162
163if (!defined('PDF_MARGIN_FOOTER')) {
164 define ('PDF_MARGIN_FOOTER', 10);
165}
166
167if (!defined('PDF_MARGIN_TOP')) {
168 define ('PDF_MARGIN_TOP', 27);
169}
170
171if (!defined('PDF_MARGIN_BOTTOM')) {
172 define ('PDF_MARGIN_BOTTOM', 25);
173}
174
175if (!defined('PDF_MARGIN_LEFT')) {
176 define ('PDF_MARGIN_LEFT', 15);
177}
178
179if (!defined('PDF_MARGIN_RIGHT')) {
180 define ('PDF_MARGIN_RIGHT', 15);
181}
182
183if (!defined('PDF_FONT_NAME_MAIN')) {
184 define ('PDF_FONT_NAME_MAIN', 'helvetica');
185}
186
187if (!defined('PDF_FONT_SIZE_MAIN')) {
188 define ('PDF_FONT_SIZE_MAIN', 10);
189}
190
191if (!defined('PDF_FONT_NAME_DATA')) {
192 define ('PDF_FONT_NAME_DATA', 'helvetica');
193}
194
195if (!defined('PDF_FONT_SIZE_DATA')) {
196 define ('PDF_FONT_SIZE_DATA', 8);
197}
198
199if (!defined('PDF_FONT_MONOSPACED')) {
200 define ('PDF_FONT_MONOSPACED', 'courier');
201}
202
203if (!defined('PDF_IMAGE_SCALE_RATIO')) {
204 define ('PDF_IMAGE_SCALE_RATIO', 1.25);
205}
206
207if (!defined('HEAD_MAGNIFICATION')) {
208 define('HEAD_MAGNIFICATION', 1.1);
209}
210
211if (!defined('K_CELL_HEIGHT_RATIO')) {
212 define('K_CELL_HEIGHT_RATIO', 1.25);
213}
214
215if (!defined('K_TITLE_MAGNIFICATION')) {
216 define('K_TITLE_MAGNIFICATION', 1.3);
217}
218
219if (!defined('K_SMALL_RATIO')) {
220 define('K_SMALL_RATIO', 2/3);
221}
222
223if (!defined('K_THAI_TOPCHARS')) {
224 define('K_THAI_TOPCHARS', true);
225}
226
227if (!defined('K_TCPDF_CALLS_IN_HTML')) {
228 define('K_TCPDF_CALLS_IN_HTML', true);
229}
230
231if (!defined('K_TCPDF_THROW_EXCEPTION_ERROR')) {
232 define('K_TCPDF_THROW_EXCEPTION_ERROR', false);
233}
234
235if (!defined('K_TIMEZONE')) {
236 define('K_TIMEZONE', @date_default_timezone_get());
237}
238date_default_timezone_set(K_TIMEZONE);
239
240//============================================================+
241// END OF FILE
242//============================================================+
diff --git a/inc/3rdparty/libraries/tcpdf/tcpdf_barcodes_1d.php b/inc/3rdparty/libraries/tcpdf/tcpdf_barcodes_1d.php
new file mode 100644
index 00000000..09dfaf4d
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/tcpdf_barcodes_1d.php
@@ -0,0 +1,2303 @@
1<?php
2//============================================================+
3// File name : tcpdf_barcodes_1d.php
4// Version : 1.0.026
5// Begin : 2008-06-09
6// Last Update : 2014-05-20
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) 2008-2014 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 GNU Lesser General Public License
25// along with TCPDF. If not, see <http://www.gnu.org/licenses/>.
26//
27// See LICENSE.TXT file for more information.
28// -------------------------------------------------------------------
29//
30// Description : PHP class to creates array representations for
31// common 1D barcodes to be used with TCPDF.
32//
33//============================================================+
34
35/**
36 * @file
37 * PHP class to creates array representations for common 1D barcodes to be used with TCPDF.
38 * @package com.tecnick.tcpdf
39 * @author Nicola Asuni
40 * @version 1.0.026
41 */
42
43/**
44 * @class TCPDFBarcode
45 * PHP class to creates array representations for common 1D barcodes to be used with TCPDF (http://www.tcpdf.org).<br>
46 * @package com.tecnick.tcpdf
47 * @version 1.0.026
48 * @author Nicola Asuni
49 */
50class TCPDFBarcode {
51
52 /**
53 * Array representation of barcode.
54 * @protected
55 */
56 protected $barcode_array;
57
58 /**
59 * This is the class constructor.
60 * Return an array representations for common 1D barcodes:<ul>
61 * <li>$arrcode['code'] code to be printed on text label</li>
62 * <li>$arrcode['maxh'] max barcode height</li>
63 * <li>$arrcode['maxw'] max barcode width</li>
64 * <li>$arrcode['bcode'][$k] single bar or space in $k position</li>
65 * <li>$arrcode['bcode'][$k]['t'] bar type: true = bar, false = space.</li>
66 * <li>$arrcode['bcode'][$k]['w'] bar width in units.</li>
67 * <li>$arrcode['bcode'][$k]['h'] bar height in units.</li>
68 * <li>$arrcode['bcode'][$k]['p'] bar top position (0 = top, 1 = middle)</li></ul>
69 * @param $code (string) code to print
70 * @param $type (string) type of barcode: <ul><li>C39 : CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.</li><li>C39+ : CODE 39 with checksum</li><li>C39E : CODE 39 EXTENDED</li><li>C39E+ : CODE 39 EXTENDED + CHECKSUM</li><li>C93 : CODE 93 - USS-93</li><li>S25 : Standard 2 of 5</li><li>S25+ : Standard 2 of 5 + CHECKSUM</li><li>I25 : Interleaved 2 of 5</li><li>I25+ : Interleaved 2 of 5 + CHECKSUM</li><li>C128 : CODE 128</li><li>C128A : CODE 128 A</li><li>C128B : CODE 128 B</li><li>C128C : CODE 128 C</li><li>EAN2 : 2-Digits UPC-Based Extention</li><li>EAN5 : 5-Digits UPC-Based Extention</li><li>EAN8 : EAN 8</li><li>EAN13 : EAN 13</li><li>UPCA : UPC-A</li><li>UPCE : UPC-E</li><li>MSI : MSI (Variation of Plessey code)</li><li>MSI+ : MSI + CHECKSUM (modulo 11)</li><li>POSTNET : POSTNET</li><li>PLANET : PLANET</li><li>RMS4CC : RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)</li><li>KIX : KIX (Klant index - Customer index)</li><li>IMB: Intelligent Mail Barcode - Onecode - USPS-B-3200</li><li>CODABAR : CODABAR</li><li>CODE11 : CODE 11</li><li>PHARMA : PHARMACODE</li><li>PHARMA2T : PHARMACODE TWO-TRACKS</li></ul>
71 * @public
72 */
73 public function __construct($code, $type) {
74 $this->setBarcode($code, $type);
75 }
76
77 /**
78 * Return an array representations of barcode.
79 * @return array
80 * @public
81 */
82 public function getBarcodeArray() {
83 return $this->barcode_array;
84 }
85
86 /**
87 * Send barcode as SVG image object to the standard output.
88 * @param $w (int) Minimum width of a single bar in user units.
89 * @param $h (int) Height of barcode in user units.
90 * @param $color (string) Foreground color (in SVG format) for bar elements (background is transparent).
91 * @public
92 */
93 public function getBarcodeSVG($w=2, $h=30, $color='black') {
94 // send headers
95 $code = $this->getBarcodeSVGcode($w, $h, $color);
96 header('Content-Type: application/svg+xml');
97 header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1
98 header('Pragma: public');
99 header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past
100 header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
101 header('Content-Disposition: inline; filename="'.md5($code).'.svg";');
102 //header('Content-Length: '.strlen($code));
103 echo $code;
104 }
105
106 /**
107 * Return a SVG string representation of barcode.
108 * @param $w (int) Minimum width of a single bar in user units.
109 * @param $h (int) Height of barcode in user units.
110 * @param $color (string) Foreground color (in SVG format) for bar elements (background is transparent).
111 * @return string SVG code.
112 * @public
113 */
114 public function getBarcodeSVGcode($w=2, $h=30, $color='black') {
115 // replace table for special characters
116 $repstr = array("\0" => '', '&' => '&amp;', '<' => '&lt;', '>' => '&gt;');
117 $svg = '<'.'?'.'xml version="1.0" standalone="no"'.'?'.'>'."\n";
118 $svg .= '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'."\n";
119 $svg .= '<svg width="'.round(($this->barcode_array['maxw'] * $w), 3).'" height="'.$h.'" version="1.1" xmlns="http://www.w3.org/2000/svg">'."\n";
120 $svg .= "\t".'<desc>'.strtr($this->barcode_array['code'], $repstr).'</desc>'."\n";
121 $svg .= "\t".'<g id="bars" fill="'.$color.'" stroke="none">'."\n";
122 // print bars
123 $x = 0;
124 foreach ($this->barcode_array['bcode'] as $k => $v) {
125 $bw = round(($v['w'] * $w), 3);
126 $bh = round(($v['h'] * $h / $this->barcode_array['maxh']), 3);
127 if ($v['t']) {
128 $y = round(($v['p'] * $h / $this->barcode_array['maxh']), 3);
129 // draw a vertical bar
130 $svg .= "\t\t".'<rect x="'.$x.'" y="'.$y.'" width="'.$bw.'" height="'.$bh.'" />'."\n";
131 }
132 $x += $bw;
133 }
134 $svg .= "\t".'</g>'."\n";
135 $svg .= '</svg>'."\n";
136 return $svg;
137 }
138
139 /**
140 * Return an HTML representation of barcode.
141 * @param $w (int) Width of a single bar element in pixels.
142 * @param $h (int) Height of a single bar element in pixels.
143 * @param $color (string) Foreground color for bar elements (background is transparent).
144 * @return string HTML code.
145 * @public
146 */
147 public function getBarcodeHTML($w=2, $h=30, $color='black') {
148 $html = '<div style="font-size:0;position:relative;width:'.($this->barcode_array['maxw'] * $w).'px;height:'.($h).'px;">'."\n";
149 // print bars
150 $x = 0;
151 foreach ($this->barcode_array['bcode'] as $k => $v) {
152 $bw = round(($v['w'] * $w), 3);
153 $bh = round(($v['h'] * $h / $this->barcode_array['maxh']), 3);
154 if ($v['t']) {
155 $y = round(($v['p'] * $h / $this->barcode_array['maxh']), 3);
156 // draw a vertical bar
157 $html .= '<div style="background-color:'.$color.';width:'.$bw.'px;height:'.$bh.'px;position:absolute;left:'.$x.'px;top:'.$y.'px;">&nbsp;</div>'."\n";
158 }
159 $x += $bw;
160 }
161 $html .= '</div>'."\n";
162 return $html;
163 }
164
165 /**
166 * Send a PNG image representation of barcode (requires GD or Imagick library).
167 * @param $w (int) Width of a single bar element in pixels.
168 * @param $h (int) Height of a single bar element in pixels.
169 * @param $color (array) RGB (0-255) foreground color for bar elements (background is transparent).
170 * @public
171 */
172 public function getBarcodePNG($w=2, $h=30, $color=array(0,0,0)) {
173 $data = $this->getBarcodePngData($w, $h, $color);
174 // send headers
175 header('Content-Type: image/png');
176 header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1
177 header('Pragma: public');
178 header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past
179 header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
180 //header('Content-Length: '.strlen($data));
181 echo $data;
182 }
183
184 /**
185 * Return a PNG image representation of barcode (requires GD or Imagick library).
186 * @param $w (int) Width of a single bar element in pixels.
187 * @param $h (int) Height of a single bar element in pixels.
188 * @param $color (array) RGB (0-255) foreground color for bar elements (background is transparent).
189 * @return image or false in case of error.
190 * @public
191 */
192 public function getBarcodePngData($w=2, $h=30, $color=array(0,0,0)) {
193 // calculate image size
194 $width = ($this->barcode_array['maxw'] * $w);
195 $height = $h;
196 if (function_exists('imagecreate')) {
197 // GD library
198 $imagick = false;
199 $png = imagecreate($width, $height);
200 $bgcol = imagecolorallocate($png, 255, 255, 255);
201 imagecolortransparent($png, $bgcol);
202 $fgcol = imagecolorallocate($png, $color[0], $color[1], $color[2]);
203 } elseif (extension_loaded('imagick')) {
204 $imagick = true;
205 $bgcol = new imagickpixel('rgb(255,255,255');
206 $fgcol = new imagickpixel('rgb('.$color[0].','.$color[1].','.$color[2].')');
207 $png = new Imagick();
208 $png->newImage($width, $height, 'none', 'png');
209 $bar = new imagickdraw();
210 $bar->setfillcolor($fgcol);
211 } else {
212 return false;
213 }
214 // print bars
215 $x = 0;
216 foreach ($this->barcode_array['bcode'] as $k => $v) {
217 $bw = round(($v['w'] * $w), 3);
218 $bh = round(($v['h'] * $h / $this->barcode_array['maxh']), 3);
219 if ($v['t']) {
220 $y = round(($v['p'] * $h / $this->barcode_array['maxh']), 3);
221 // draw a vertical bar
222 if ($imagick) {
223 $bar->rectangle($x, $y, ($x + $bw - 1), ($y + $bh - 1));
224 } else {
225 imagefilledrectangle($png, $x, $y, ($x + $bw - 1), ($y + $bh - 1), $fgcol);
226 }
227 }
228 $x += $bw;
229 }
230 if ($imagick) {
231 $png->drawimage($bar);
232 return $png;
233 } else {
234 ob_start();
235 imagepng($png);
236 $imagedata = ob_get_clean();
237 imagedestroy($png);
238 return $imagedata;
239 }
240 }
241
242 /**
243 * Set the barcode.
244 * @param $code (string) code to print
245 * @param $type (string) type of barcode: <ul><li>C39 : CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.</li><li>C39+ : CODE 39 with checksum</li><li>C39E : CODE 39 EXTENDED</li><li>C39E+ : CODE 39 EXTENDED + CHECKSUM</li><li>C93 : CODE 93 - USS-93</li><li>S25 : Standard 2 of 5</li><li>S25+ : Standard 2 of 5 + CHECKSUM</li><li>I25 : Interleaved 2 of 5</li><li>I25+ : Interleaved 2 of 5 + CHECKSUM</li><li>C128 : CODE 128</li><li>C128A : CODE 128 A</li><li>C128B : CODE 128 B</li><li>C128C : CODE 128 C</li><li>EAN2 : 2-Digits UPC-Based Extention</li><li>EAN5 : 5-Digits UPC-Based Extention</li><li>EAN8 : EAN 8</li><li>EAN13 : EAN 13</li><li>UPCA : UPC-A</li><li>UPCE : UPC-E</li><li>MSI : MSI (Variation of Plessey code)</li><li>MSI+ : MSI + CHECKSUM (modulo 11)</li><li>POSTNET : POSTNET</li><li>PLANET : PLANET</li><li>RMS4CC : RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)</li><li>KIX : KIX (Klant index - Customer index)</li><li>IMB: Intelligent Mail Barcode - Onecode - USPS-B-3200</li><li>CODABAR : CODABAR</li><li>CODE11 : CODE 11</li><li>PHARMA : PHARMACODE</li><li>PHARMA2T : PHARMACODE TWO-TRACKS</li></ul>
246 * @return array barcode array
247 * @public
248 */
249 public function setBarcode($code, $type) {
250 switch (strtoupper($type)) {
251 case 'C39': { // CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
252 $arrcode = $this->barcode_code39($code, false, false);
253 break;
254 }
255 case 'C39+': { // CODE 39 with checksum
256 $arrcode = $this->barcode_code39($code, false, true);
257 break;
258 }
259 case 'C39E': { // CODE 39 EXTENDED
260 $arrcode = $this->barcode_code39($code, true, false);
261 break;
262 }
263 case 'C39E+': { // CODE 39 EXTENDED + CHECKSUM
264 $arrcode = $this->barcode_code39($code, true, true);
265 break;
266 }
267 case 'C93': { // CODE 93 - USS-93
268 $arrcode = $this->barcode_code93($code);
269 break;
270 }
271 case 'S25': { // Standard 2 of 5
272 $arrcode = $this->barcode_s25($code, false);
273 break;
274 }
275 case 'S25+': { // Standard 2 of 5 + CHECKSUM
276 $arrcode = $this->barcode_s25($code, true);
277 break;
278 }
279 case 'I25': { // Interleaved 2 of 5
280 $arrcode = $this->barcode_i25($code, false);
281 break;
282 }
283 case 'I25+': { // Interleaved 2 of 5 + CHECKSUM
284 $arrcode = $this->barcode_i25($code, true);
285 break;
286 }
287 case 'C128': { // CODE 128
288 $arrcode = $this->barcode_c128($code, '');
289 break;
290 }
291 case 'C128A': { // CODE 128 A
292 $arrcode = $this->barcode_c128($code, 'A');
293 break;
294 }
295 case 'C128B': { // CODE 128 B
296 $arrcode = $this->barcode_c128($code, 'B');
297 break;
298 }
299 case 'C128C': { // CODE 128 C
300 $arrcode = $this->barcode_c128($code, 'C');
301 break;
302 }
303 case 'EAN2': { // 2-Digits UPC-Based Extention
304 $arrcode = $this->barcode_eanext($code, 2);
305 break;
306 }
307 case 'EAN5': { // 5-Digits UPC-Based Extention
308 $arrcode = $this->barcode_eanext($code, 5);
309 break;
310 }
311 case 'EAN8': { // EAN 8
312 $arrcode = $this->barcode_eanupc($code, 8);
313 break;
314 }
315 case 'EAN13': { // EAN 13
316 $arrcode = $this->barcode_eanupc($code, 13);
317 break;
318 }
319 case 'UPCA': { // UPC-A
320 $arrcode = $this->barcode_eanupc($code, 12);
321 break;
322 }
323 case 'UPCE': { // UPC-E
324 $arrcode = $this->barcode_eanupc($code, 6);
325 break;
326 }
327 case 'MSI': { // MSI (Variation of Plessey code)
328 $arrcode = $this->barcode_msi($code, false);
329 break;
330 }
331 case 'MSI+': { // MSI + CHECKSUM (modulo 11)
332 $arrcode = $this->barcode_msi($code, true);
333 break;
334 }
335 case 'POSTNET': { // POSTNET
336 $arrcode = $this->barcode_postnet($code, false);
337 break;
338 }
339 case 'PLANET': { // PLANET
340 $arrcode = $this->barcode_postnet($code, true);
341 break;
342 }
343 case 'RMS4CC': { // RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code)
344 $arrcode = $this->barcode_rms4cc($code, false);
345 break;
346 }
347 case 'KIX': { // KIX (Klant index - Customer index)
348 $arrcode = $this->barcode_rms4cc($code, true);
349 break;
350 }
351 case 'IMB': { // IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200
352 $arrcode = $this->barcode_imb($code);
353 break;
354 }
355 case 'CODABAR': { // CODABAR
356 $arrcode = $this->barcode_codabar($code);
357 break;
358 }
359 case 'CODE11': { // CODE 11
360 $arrcode = $this->barcode_code11($code);
361 break;
362 }
363 case 'PHARMA': { // PHARMACODE
364 $arrcode = $this->barcode_pharmacode($code);
365 break;
366 }
367 case 'PHARMA2T': { // PHARMACODE TWO-TRACKS
368 $arrcode = $this->barcode_pharmacode2t($code);
369 break;
370 }
371 default: {
372 $this->barcode_array = false;
373 $arrcode = false;
374 break;
375 }
376 }
377 $this->barcode_array = $arrcode;
378 }
379
380 /**
381 * CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9.
382 * General-purpose code in very wide use world-wide
383 * @param $code (string) code to represent.
384 * @param $extended (boolean) if true uses the extended mode.
385 * @param $checksum (boolean) if true add a checksum to the code.
386 * @return array barcode representation.
387 * @protected
388 */
389 protected function barcode_code39($code, $extended=false, $checksum=false) {
390 $chr['0'] = '111331311';
391 $chr['1'] = '311311113';
392 $chr['2'] = '113311113';
393 $chr['3'] = '313311111';
394 $chr['4'] = '111331113';
395 $chr['5'] = '311331111';
396 $chr['6'] = '113331111';
397 $chr['7'] = '111311313';
398 $chr['8'] = '311311311';
399 $chr['9'] = '113311311';
400 $chr['A'] = '311113113';
401 $chr['B'] = '113113113';
402 $chr['C'] = '313113111';
403 $chr['D'] = '111133113';
404 $chr['E'] = '311133111';
405 $chr['F'] = '113133111';
406 $chr['G'] = '111113313';
407 $chr['H'] = '311113311';
408 $chr['I'] = '113113311';
409 $chr['J'] = '111133311';
410 $chr['K'] = '311111133';
411 $chr['L'] = '113111133';
412 $chr['M'] = '313111131';
413 $chr['N'] = '111131133';
414 $chr['O'] = '311131131';
415 $chr['P'] = '113131131';
416 $chr['Q'] = '111111333';
417 $chr['R'] = '311111331';
418 $chr['S'] = '113111331';
419 $chr['T'] = '111131331';
420 $chr['U'] = '331111113';
421 $chr['V'] = '133111113';
422 $chr['W'] = '333111111';
423 $chr['X'] = '131131113';
424 $chr['Y'] = '331131111';
425 $chr['Z'] = '133131111';
426 $chr['-'] = '131111313';
427 $chr['.'] = '331111311';
428 $chr[' '] = '133111311';
429 $chr['$'] = '131313111';
430 $chr['/'] = '131311131';
431 $chr['+'] = '131113131';
432 $chr['%'] = '111313131';
433 $chr['*'] = '131131311';
434 $code = strtoupper($code);
435 if ($extended) {
436 // extended mode
437 $code = $this->encode_code39_ext($code);
438 }
439 if ($code === false) {
440 return false;
441 }
442 if ($checksum) {
443 // checksum
444 $code .= $this->checksum_code39($code);
445 }
446 // add start and stop codes
447 $code = '*'.$code.'*';
448 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
449 $k = 0;
450 $clen = strlen($code);
451 for ($i = 0; $i < $clen; ++$i) {
452 $char = $code{$i};
453 if(!isset($chr[$char])) {
454 // invalid character
455 return false;
456 }
457 for ($j = 0; $j < 9; ++$j) {
458 if (($j % 2) == 0) {
459 $t = true; // bar
460 } else {
461 $t = false; // space
462 }
463 $w = $chr[$char]{$j};
464 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
465 $bararray['maxw'] += $w;
466 ++$k;
467 }
468 // intercharacter gap
469 $bararray['bcode'][$k] = array('t' => false, 'w' => 1, 'h' => 1, 'p' => 0);
470 $bararray['maxw'] += 1;
471 ++$k;
472 }
473 return $bararray;
474 }
475
476 /**
477 * Encode a string to be used for CODE 39 Extended mode.
478 * @param $code (string) code to represent.
479 * @return encoded string.
480 * @protected
481 */
482 protected function encode_code39_ext($code) {
483 $encode = array(
484 chr(0) => '%U', chr(1) => '$A', chr(2) => '$B', chr(3) => '$C',
485 chr(4) => '$D', chr(5) => '$E', chr(6) => '$F', chr(7) => '$G',
486 chr(8) => '$H', chr(9) => '$I', chr(10) => '$J', chr(11) => '£K',
487 chr(12) => '$L', chr(13) => '$M', chr(14) => '$N', chr(15) => '$O',
488 chr(16) => '$P', chr(17) => '$Q', chr(18) => '$R', chr(19) => '$S',
489 chr(20) => '$T', chr(21) => '$U', chr(22) => '$V', chr(23) => '$W',
490 chr(24) => '$X', chr(25) => '$Y', chr(26) => '$Z', chr(27) => '%A',
491 chr(28) => '%B', chr(29) => '%C', chr(30) => '%D', chr(31) => '%E',
492 chr(32) => ' ', chr(33) => '/A', chr(34) => '/B', chr(35) => '/C',
493 chr(36) => '/D', chr(37) => '/E', chr(38) => '/F', chr(39) => '/G',
494 chr(40) => '/H', chr(41) => '/I', chr(42) => '/J', chr(43) => '/K',
495 chr(44) => '/L', chr(45) => '-', chr(46) => '.', chr(47) => '/O',
496 chr(48) => '0', chr(49) => '1', chr(50) => '2', chr(51) => '3',
497 chr(52) => '4', chr(53) => '5', chr(54) => '6', chr(55) => '7',
498 chr(56) => '8', chr(57) => '9', chr(58) => '/Z', chr(59) => '%F',
499 chr(60) => '%G', chr(61) => '%H', chr(62) => '%I', chr(63) => '%J',
500 chr(64) => '%V', chr(65) => 'A', chr(66) => 'B', chr(67) => 'C',
501 chr(68) => 'D', chr(69) => 'E', chr(70) => 'F', chr(71) => 'G',
502 chr(72) => 'H', chr(73) => 'I', chr(74) => 'J', chr(75) => 'K',
503 chr(76) => 'L', chr(77) => 'M', chr(78) => 'N', chr(79) => 'O',
504 chr(80) => 'P', chr(81) => 'Q', chr(82) => 'R', chr(83) => 'S',
505 chr(84) => 'T', chr(85) => 'U', chr(86) => 'V', chr(87) => 'W',
506 chr(88) => 'X', chr(89) => 'Y', chr(90) => 'Z', chr(91) => '%K',
507 chr(92) => '%L', chr(93) => '%M', chr(94) => '%N', chr(95) => '%O',
508 chr(96) => '%W', chr(97) => '+A', chr(98) => '+B', chr(99) => '+C',
509 chr(100) => '+D', chr(101) => '+E', chr(102) => '+F', chr(103) => '+G',
510 chr(104) => '+H', chr(105) => '+I', chr(106) => '+J', chr(107) => '+K',
511 chr(108) => '+L', chr(109) => '+M', chr(110) => '+N', chr(111) => '+O',
512 chr(112) => '+P', chr(113) => '+Q', chr(114) => '+R', chr(115) => '+S',
513 chr(116) => '+T', chr(117) => '+U', chr(118) => '+V', chr(119) => '+W',
514 chr(120) => '+X', chr(121) => '+Y', chr(122) => '+Z', chr(123) => '%P',
515 chr(124) => '%Q', chr(125) => '%R', chr(126) => '%S', chr(127) => '%T');
516 $code_ext = '';
517 $clen = strlen($code);
518 for ($i = 0 ; $i < $clen; ++$i) {
519 if (ord($code{$i}) > 127) {
520 return false;
521 }
522 $code_ext .= $encode[$code{$i}];
523 }
524 return $code_ext;
525 }
526
527 /**
528 * Calculate CODE 39 checksum (modulo 43).
529 * @param $code (string) code to represent.
530 * @return char checksum.
531 * @protected
532 */
533 protected function checksum_code39($code) {
534 $chars = array(
535 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
536 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
537 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
538 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%');
539 $sum = 0;
540 $clen = strlen($code);
541 for ($i = 0 ; $i < $clen; ++$i) {
542 $k = array_keys($chars, $code{$i});
543 $sum += $k[0];
544 }
545 $j = ($sum % 43);
546 return $chars[$j];
547 }
548
549 /**
550 * CODE 93 - USS-93
551 * Compact code similar to Code 39
552 * @param $code (string) code to represent.
553 * @return array barcode representation.
554 * @protected
555 */
556 protected function barcode_code93($code) {
557 $chr[48] = '131112'; // 0
558 $chr[49] = '111213'; // 1
559 $chr[50] = '111312'; // 2
560 $chr[51] = '111411'; // 3
561 $chr[52] = '121113'; // 4
562 $chr[53] = '121212'; // 5
563 $chr[54] = '121311'; // 6
564 $chr[55] = '111114'; // 7
565 $chr[56] = '131211'; // 8
566 $chr[57] = '141111'; // 9
567 $chr[65] = '211113'; // A
568 $chr[66] = '211212'; // B
569 $chr[67] = '211311'; // C
570 $chr[68] = '221112'; // D
571 $chr[69] = '221211'; // E
572 $chr[70] = '231111'; // F
573 $chr[71] = '112113'; // G
574 $chr[72] = '112212'; // H
575 $chr[73] = '112311'; // I
576 $chr[74] = '122112'; // J
577 $chr[75] = '132111'; // K
578 $chr[76] = '111123'; // L
579 $chr[77] = '111222'; // M
580 $chr[78] = '111321'; // N
581 $chr[79] = '121122'; // O
582 $chr[80] = '131121'; // P
583 $chr[81] = '212112'; // Q
584 $chr[82] = '212211'; // R
585 $chr[83] = '211122'; // S
586 $chr[84] = '211221'; // T
587 $chr[85] = '221121'; // U
588 $chr[86] = '222111'; // V
589 $chr[87] = '112122'; // W
590 $chr[88] = '112221'; // X
591 $chr[89] = '122121'; // Y
592 $chr[90] = '123111'; // Z
593 $chr[45] = '121131'; // -
594 $chr[46] = '311112'; // .
595 $chr[32] = '311211'; //
596 $chr[36] = '321111'; // $
597 $chr[47] = '112131'; // /
598 $chr[43] = '113121'; // +
599 $chr[37] = '211131'; // %
600 $chr[128] = '121221'; // ($)
601 $chr[129] = '311121'; // (/)
602 $chr[130] = '122211'; // (+)
603 $chr[131] = '312111'; // (%)
604 $chr[42] = '111141'; // start-stop
605 $code = strtoupper($code);
606 $encode = array(
607 chr(0) => chr(131).'U', chr(1) => chr(128).'A', chr(2) => chr(128).'B', chr(3) => chr(128).'C',
608 chr(4) => chr(128).'D', chr(5) => chr(128).'E', chr(6) => chr(128).'F', chr(7) => chr(128).'G',
609 chr(8) => chr(128).'H', chr(9) => chr(128).'I', chr(10) => chr(128).'J', chr(11) => '£K',
610 chr(12) => chr(128).'L', chr(13) => chr(128).'M', chr(14) => chr(128).'N', chr(15) => chr(128).'O',
611 chr(16) => chr(128).'P', chr(17) => chr(128).'Q', chr(18) => chr(128).'R', chr(19) => chr(128).'S',
612 chr(20) => chr(128).'T', chr(21) => chr(128).'U', chr(22) => chr(128).'V', chr(23) => chr(128).'W',
613 chr(24) => chr(128).'X', chr(25) => chr(128).'Y', chr(26) => chr(128).'Z', chr(27) => chr(131).'A',
614 chr(28) => chr(131).'B', chr(29) => chr(131).'C', chr(30) => chr(131).'D', chr(31) => chr(131).'E',
615 chr(32) => ' ', chr(33) => chr(129).'A', chr(34) => chr(129).'B', chr(35) => chr(129).'C',
616 chr(36) => chr(129).'D', chr(37) => chr(129).'E', chr(38) => chr(129).'F', chr(39) => chr(129).'G',
617 chr(40) => chr(129).'H', chr(41) => chr(129).'I', chr(42) => chr(129).'J', chr(43) => chr(129).'K',
618 chr(44) => chr(129).'L', chr(45) => '-', chr(46) => '.', chr(47) => chr(129).'O',
619 chr(48) => '0', chr(49) => '1', chr(50) => '2', chr(51) => '3',
620 chr(52) => '4', chr(53) => '5', chr(54) => '6', chr(55) => '7',
621 chr(56) => '8', chr(57) => '9', chr(58) => chr(129).'Z', chr(59) => chr(131).'F',
622 chr(60) => chr(131).'G', chr(61) => chr(131).'H', chr(62) => chr(131).'I', chr(63) => chr(131).'J',
623 chr(64) => chr(131).'V', chr(65) => 'A', chr(66) => 'B', chr(67) => 'C',
624 chr(68) => 'D', chr(69) => 'E', chr(70) => 'F', chr(71) => 'G',
625 chr(72) => 'H', chr(73) => 'I', chr(74) => 'J', chr(75) => 'K',
626 chr(76) => 'L', chr(77) => 'M', chr(78) => 'N', chr(79) => 'O',
627 chr(80) => 'P', chr(81) => 'Q', chr(82) => 'R', chr(83) => 'S',
628 chr(84) => 'T', chr(85) => 'U', chr(86) => 'V', chr(87) => 'W',
629 chr(88) => 'X', chr(89) => 'Y', chr(90) => 'Z', chr(91) => chr(131).'K',
630 chr(92) => chr(131).'L', chr(93) => chr(131).'M', chr(94) => chr(131).'N', chr(95) => chr(131).'O',
631 chr(96) => chr(131).'W', chr(97) => chr(130).'A', chr(98) => chr(130).'B', chr(99) => chr(130).'C',
632 chr(100) => chr(130).'D', chr(101) => chr(130).'E', chr(102) => chr(130).'F', chr(103) => chr(130).'G',
633 chr(104) => chr(130).'H', chr(105) => chr(130).'I', chr(106) => chr(130).'J', chr(107) => chr(130).'K',
634 chr(108) => chr(130).'L', chr(109) => chr(130).'M', chr(110) => chr(130).'N', chr(111) => chr(130).'O',
635 chr(112) => chr(130).'P', chr(113) => chr(130).'Q', chr(114) => chr(130).'R', chr(115) => chr(130).'S',
636 chr(116) => chr(130).'T', chr(117) => chr(130).'U', chr(118) => chr(130).'V', chr(119) => chr(130).'W',
637 chr(120) => chr(130).'X', chr(121) => chr(130).'Y', chr(122) => chr(130).'Z', chr(123) => chr(131).'P',
638 chr(124) => chr(131).'Q', chr(125) => chr(131).'R', chr(126) => chr(131).'S', chr(127) => chr(131).'T');
639 $code_ext = '';
640 $clen = strlen($code);
641 for ($i = 0 ; $i < $clen; ++$i) {
642 if (ord($code{$i}) > 127) {
643 return false;
644 }
645 $code_ext .= $encode[$code{$i}];
646 }
647 // checksum
648 $code_ext .= $this->checksum_code93($code_ext);
649 // add start and stop codes
650 $code = '*'.$code_ext.'*';
651 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
652 $k = 0;
653 $clen = strlen($code);
654 for ($i = 0; $i < $clen; ++$i) {
655 $char = ord($code{$i});
656 if(!isset($chr[$char])) {
657 // invalid character
658 return false;
659 }
660 for ($j = 0; $j < 6; ++$j) {
661 if (($j % 2) == 0) {
662 $t = true; // bar
663 } else {
664 $t = false; // space
665 }
666 $w = $chr[$char]{$j};
667 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
668 $bararray['maxw'] += $w;
669 ++$k;
670 }
671 }
672 $bararray['bcode'][$k] = array('t' => true, 'w' => 1, 'h' => 1, 'p' => 0);
673 $bararray['maxw'] += 1;
674 ++$k;
675 return $bararray;
676 }
677
678 /**
679 * Calculate CODE 93 checksum (modulo 47).
680 * @param $code (string) code to represent.
681 * @return string checksum code.
682 * @protected
683 */
684 protected function checksum_code93($code) {
685 $chars = array(
686 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
687 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
688 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
689 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%',
690 '<', '=', '>', '?');
691 // translate special characters
692 $code = strtr($code, chr(128).chr(131).chr(129).chr(130), '<=>?');
693 $len = strlen($code);
694 // calculate check digit C
695 $p = 1;
696 $check = 0;
697 for ($i = ($len - 1); $i >= 0; --$i) {
698 $k = array_keys($chars, $code{$i});
699 $check += ($k[0] * $p);
700 ++$p;
701 if ($p > 20) {
702 $p = 1;
703 }
704 }
705 $check %= 47;
706 $c = $chars[$check];
707 $code .= $c;
708 // calculate check digit K
709 $p = 1;
710 $check = 0;
711 for ($i = $len; $i >= 0; --$i) {
712 $k = array_keys($chars, $code{$i});
713 $check += ($k[0] * $p);
714 ++$p;
715 if ($p > 15) {
716 $p = 1;
717 }
718 }
719 $check %= 47;
720 $k = $chars[$check];
721 $checksum = $c.$k;
722 // resto respecial characters
723 $checksum = strtr($checksum, '<=>?', chr(128).chr(131).chr(129).chr(130));
724 return $checksum;
725 }
726
727 /**
728 * Checksum for standard 2 of 5 barcodes.
729 * @param $code (string) code to process.
730 * @return int checksum.
731 * @protected
732 */
733 protected function checksum_s25($code) {
734 $len = strlen($code);
735 $sum = 0;
736 for ($i = 0; $i < $len; $i+=2) {
737 $sum += $code{$i};
738 }
739 $sum *= 3;
740 for ($i = 1; $i < $len; $i+=2) {
741 $sum += ($code{$i});
742 }
743 $r = $sum % 10;
744 if($r > 0) {
745 $r = (10 - $r);
746 }
747 return $r;
748 }
749
750 /**
751 * MSI.
752 * Variation of Plessey code, with similar applications
753 * Contains digits (0 to 9) and encodes the data only in the width of bars.
754 * @param $code (string) code to represent.
755 * @param $checksum (boolean) if true add a checksum to the code (modulo 11)
756 * @return array barcode representation.
757 * @protected
758 */
759 protected function barcode_msi($code, $checksum=false) {
760 $chr['0'] = '100100100100';
761 $chr['1'] = '100100100110';
762 $chr['2'] = '100100110100';
763 $chr['3'] = '100100110110';
764 $chr['4'] = '100110100100';
765 $chr['5'] = '100110100110';
766 $chr['6'] = '100110110100';
767 $chr['7'] = '100110110110';
768 $chr['8'] = '110100100100';
769 $chr['9'] = '110100100110';
770 $chr['A'] = '110100110100';
771 $chr['B'] = '110100110110';
772 $chr['C'] = '110110100100';
773 $chr['D'] = '110110100110';
774 $chr['E'] = '110110110100';
775 $chr['F'] = '110110110110';
776 if ($checksum) {
777 // add checksum
778 $clen = strlen($code);
779 $p = 2;
780 $check = 0;
781 for ($i = ($clen - 1); $i >= 0; --$i) {
782 $check += (hexdec($code{$i}) * $p);
783 ++$p;
784 if ($p > 7) {
785 $p = 2;
786 }
787 }
788 $check %= 11;
789 if ($check > 0) {
790 $check = 11 - $check;
791 }
792 $code .= $check;
793 }
794 $seq = '110'; // left guard
795 $clen = strlen($code);
796 for ($i = 0; $i < $clen; ++$i) {
797 $digit = $code{$i};
798 if (!isset($chr[$digit])) {
799 // invalid character
800 return false;
801 }
802 $seq .= $chr[$digit];
803 }
804 $seq .= '1001'; // right guard
805 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
806 return $this->binseq_to_array($seq, $bararray);
807 }
808
809 /**
810 * Standard 2 of 5 barcodes.
811 * Used in airline ticket marking, photofinishing
812 * Contains digits (0 to 9) and encodes the data only in the width of bars.
813 * @param $code (string) code to represent.
814 * @param $checksum (boolean) if true add a checksum to the code
815 * @return array barcode representation.
816 * @protected
817 */
818 protected function barcode_s25($code, $checksum=false) {
819 $chr['0'] = '10101110111010';
820 $chr['1'] = '11101010101110';
821 $chr['2'] = '10111010101110';
822 $chr['3'] = '11101110101010';
823 $chr['4'] = '10101110101110';
824 $chr['5'] = '11101011101010';
825 $chr['6'] = '10111011101010';
826 $chr['7'] = '10101011101110';
827 $chr['8'] = '10101110111010';
828 $chr['9'] = '10111010111010';
829 if ($checksum) {
830 // add checksum
831 $code .= $this->checksum_s25($code);
832 }
833 if((strlen($code) % 2) != 0) {
834 // add leading zero if code-length is odd
835 $code = '0'.$code;
836 }
837 $seq = '11011010';
838 $clen = strlen($code);
839 for ($i = 0; $i < $clen; ++$i) {
840 $digit = $code{$i};
841 if (!isset($chr[$digit])) {
842 // invalid character
843 return false;
844 }
845 $seq .= $chr[$digit];
846 }
847 $seq .= '1101011';
848 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
849 return $this->binseq_to_array($seq, $bararray);
850 }
851
852 /**
853 * Convert binary barcode sequence to TCPDF barcode array.
854 * @param $seq (string) barcode as binary sequence.
855 * @param $bararray (array) barcode array.
856 * òparam array $bararray TCPDF barcode array to fill up
857 * @return array barcode representation.
858 * @protected
859 */
860 protected function binseq_to_array($seq, $bararray) {
861 $len = strlen($seq);
862 $w = 0;
863 $k = 0;
864 for ($i = 0; $i < $len; ++$i) {
865 $w += 1;
866 if (($i == ($len - 1)) OR (($i < ($len - 1)) AND ($seq{$i} != $seq{($i+1)}))) {
867 if ($seq{$i} == '1') {
868 $t = true; // bar
869 } else {
870 $t = false; // space
871 }
872 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
873 $bararray['maxw'] += $w;
874 ++$k;
875 $w = 0;
876 }
877 }
878 return $bararray;
879 }
880
881 /**
882 * Interleaved 2 of 5 barcodes.
883 * Compact numeric code, widely used in industry, air cargo
884 * Contains digits (0 to 9) and encodes the data in the width of both bars and spaces.
885 * @param $code (string) code to represent.
886 * @param $checksum (boolean) if true add a checksum to the code
887 * @return array barcode representation.
888 * @protected
889 */
890 protected function barcode_i25($code, $checksum=false) {
891 $chr['0'] = '11221';
892 $chr['1'] = '21112';
893 $chr['2'] = '12112';
894 $chr['3'] = '22111';
895 $chr['4'] = '11212';
896 $chr['5'] = '21211';
897 $chr['6'] = '12211';
898 $chr['7'] = '11122';
899 $chr['8'] = '21121';
900 $chr['9'] = '12121';
901 $chr['A'] = '11';
902 $chr['Z'] = '21';
903 if ($checksum) {
904 // add checksum
905 $code .= $this->checksum_s25($code);
906 }
907 if((strlen($code) % 2) != 0) {
908 // add leading zero if code-length is odd
909 $code = '0'.$code;
910 }
911 // add start and stop codes
912 $code = 'AA'.strtolower($code).'ZA';
913
914 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
915 $k = 0;
916 $clen = strlen($code);
917 for ($i = 0; $i < $clen; $i = ($i + 2)) {
918 $char_bar = $code{$i};
919 $char_space = $code{$i+1};
920 if((!isset($chr[$char_bar])) OR (!isset($chr[$char_space]))) {
921 // invalid character
922 return false;
923 }
924 // create a bar-space sequence
925 $seq = '';
926 $chrlen = strlen($chr[$char_bar]);
927 for ($s = 0; $s < $chrlen; $s++){
928 $seq .= $chr[$char_bar]{$s} . $chr[$char_space]{$s};
929 }
930 $seqlen = strlen($seq);
931 for ($j = 0; $j < $seqlen; ++$j) {
932 if (($j % 2) == 0) {
933 $t = true; // bar
934 } else {
935 $t = false; // space
936 }
937 $w = $seq{$j};
938 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
939 $bararray['maxw'] += $w;
940 ++$k;
941 }
942 }
943 return $bararray;
944 }
945
946 /**
947 * C128 barcodes.
948 * Very capable code, excellent density, high reliability; in very wide use world-wide
949 * @param $code (string) code to represent.
950 * @param $type (string) barcode type: A, B, C or empty for automatic switch (AUTO mode)
951 * @return array barcode representation.
952 * @protected
953 */
954 protected function barcode_c128($code, $type='') {
955 $chr = array(
956 '212222', /* 00 */
957 '222122', /* 01 */
958 '222221', /* 02 */
959 '121223', /* 03 */
960 '121322', /* 04 */
961 '131222', /* 05 */
962 '122213', /* 06 */
963 '122312', /* 07 */
964 '132212', /* 08 */
965 '221213', /* 09 */
966 '221312', /* 10 */
967 '231212', /* 11 */
968 '112232', /* 12 */
969 '122132', /* 13 */
970 '122231', /* 14 */
971 '113222', /* 15 */
972 '123122', /* 16 */
973 '123221', /* 17 */
974 '223211', /* 18 */
975 '221132', /* 19 */
976 '221231', /* 20 */
977 '213212', /* 21 */
978 '223112', /* 22 */
979 '312131', /* 23 */
980 '311222', /* 24 */
981 '321122', /* 25 */
982 '321221', /* 26 */
983 '312212', /* 27 */
984 '322112', /* 28 */
985 '322211', /* 29 */
986 '212123', /* 30 */
987 '212321', /* 31 */
988 '232121', /* 32 */
989 '111323', /* 33 */
990 '131123', /* 34 */
991 '131321', /* 35 */
992 '112313', /* 36 */
993 '132113', /* 37 */
994 '132311', /* 38 */
995 '211313', /* 39 */
996 '231113', /* 40 */
997 '231311', /* 41 */
998 '112133', /* 42 */
999 '112331', /* 43 */
1000 '132131', /* 44 */
1001 '113123', /* 45 */
1002 '113321', /* 46 */
1003 '133121', /* 47 */
1004 '313121', /* 48 */
1005 '211331', /* 49 */
1006 '231131', /* 50 */
1007 '213113', /* 51 */
1008 '213311', /* 52 */
1009 '213131', /* 53 */
1010 '311123', /* 54 */
1011 '311321', /* 55 */
1012 '331121', /* 56 */
1013 '312113', /* 57 */
1014 '312311', /* 58 */
1015 '332111', /* 59 */
1016 '314111', /* 60 */
1017 '221411', /* 61 */
1018 '431111', /* 62 */
1019 '111224', /* 63 */
1020 '111422', /* 64 */
1021 '121124', /* 65 */
1022 '121421', /* 66 */
1023 '141122', /* 67 */
1024 '141221', /* 68 */
1025 '112214', /* 69 */
1026 '112412', /* 70 */
1027 '122114', /* 71 */
1028 '122411', /* 72 */
1029 '142112', /* 73 */
1030 '142211', /* 74 */
1031 '241211', /* 75 */
1032 '221114', /* 76 */
1033 '413111', /* 77 */
1034 '241112', /* 78 */
1035 '134111', /* 79 */
1036 '111242', /* 80 */
1037 '121142', /* 81 */
1038 '121241', /* 82 */
1039 '114212', /* 83 */
1040 '124112', /* 84 */
1041 '124211', /* 85 */
1042 '411212', /* 86 */
1043 '421112', /* 87 */
1044 '421211', /* 88 */
1045 '212141', /* 89 */
1046 '214121', /* 90 */
1047 '412121', /* 91 */
1048 '111143', /* 92 */
1049 '111341', /* 93 */
1050 '131141', /* 94 */
1051 '114113', /* 95 */
1052 '114311', /* 96 */
1053 '411113', /* 97 */
1054 '411311', /* 98 */
1055 '113141', /* 99 */
1056 '114131', /* 100 */
1057 '311141', /* 101 */
1058 '411131', /* 102 */
1059 '211412', /* 103 START A */
1060 '211214', /* 104 START B */
1061 '211232', /* 105 START C */
1062 '233111', /* STOP */
1063 '200000' /* END */
1064 );
1065 // ASCII characters for code A (ASCII 00 - 95)
1066 $keys_a = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_';
1067 $keys_a .= chr(0).chr(1).chr(2).chr(3).chr(4).chr(5).chr(6).chr(7).chr(8).chr(9);
1068 $keys_a .= chr(10).chr(11).chr(12).chr(13).chr(14).chr(15).chr(16).chr(17).chr(18).chr(19);
1069 $keys_a .= chr(20).chr(21).chr(22).chr(23).chr(24).chr(25).chr(26).chr(27).chr(28).chr(29);
1070 $keys_a .= chr(30).chr(31);
1071 // ASCII characters for code B (ASCII 32 - 127)
1072 $keys_b = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'.chr(127);
1073 // special codes
1074 $fnc_a = array(241 => 102, 242 => 97, 243 => 96, 244 => 101);
1075 $fnc_b = array(241 => 102, 242 => 97, 243 => 96, 244 => 100);
1076 // array of symbols
1077 $code_data = array();
1078 // lenght of the code
1079 $len = strlen($code);
1080 switch(strtoupper($type)) {
1081 case 'A': { // MODE A
1082 $startid = 103;
1083 for ($i = 0; $i < $len; ++$i) {
1084 $char = $code{$i};
1085 $char_id = ord($char);
1086 if (($char_id >= 241) AND ($char_id <= 244)) {
1087 $code_data[] = $fnc_a[$char_id];
1088 } elseif (($char_id >= 0) AND ($char_id <= 95)) {
1089 $code_data[] = strpos($keys_a, $char);
1090 } else {
1091 return false;
1092 }
1093 }
1094 break;
1095 }
1096 case 'B': { // MODE B
1097 $startid = 104;
1098 for ($i = 0; $i < $len; ++$i) {
1099 $char = $code{$i};
1100 $char_id = ord($char);
1101 if (($char_id >= 241) AND ($char_id <= 244)) {
1102 $code_data[] = $fnc_b[$char_id];
1103 } elseif (($char_id >= 32) AND ($char_id <= 127)) {
1104 $code_data[] = strpos($keys_b, $char);
1105 } else {
1106 return false;
1107 }
1108 }
1109 break;
1110 }
1111 case 'C': { // MODE C
1112 $startid = 105;
1113 if (ord($code[0]) == 241) {
1114 $code_data[] = 102;
1115 $code = substr($code, 1);
1116 --$len;
1117 }
1118 if (($len % 2) != 0) {
1119 // the length must be even
1120 return false;
1121 }
1122 for ($i = 0; $i < $len; $i+=2) {
1123 $chrnum = $code{$i}.$code{$i+1};
1124 if (preg_match('/([0-9]{2})/', $chrnum) > 0) {
1125 $code_data[] = intval($chrnum);
1126 } else {
1127 return false;
1128 }
1129 }
1130 break;
1131 }
1132 default: { // MODE AUTO
1133 // split code into sequences
1134 $sequence = array();
1135 // get numeric sequences (if any)
1136 $numseq = array();
1137 preg_match_all('/([0-9]{4,})/', $code, $numseq, PREG_OFFSET_CAPTURE);
1138 if (isset($numseq[1]) AND !empty($numseq[1])) {
1139 $end_offset = 0;
1140 foreach ($numseq[1] as $val) {
1141 $offset = $val[1];
1142 if ($offset > $end_offset) {
1143 // non numeric sequence
1144 $sequence = array_merge($sequence, $this->get128ABsequence(substr($code, $end_offset, ($offset - $end_offset))));
1145 }
1146 // numeric sequence
1147 $slen = strlen($val[0]);
1148 if (($slen % 2) != 0) {
1149 // the length must be even
1150 --$slen;
1151 }
1152 $sequence[] = array('C', substr($code, $offset, $slen), $slen);
1153 $end_offset = $offset + $slen;
1154 }
1155 if ($end_offset < $len) {
1156 $sequence = array_merge($sequence, $this->get128ABsequence(substr($code, $end_offset)));
1157 }
1158 } else {
1159 // text code (non C mode)
1160 $sequence = array_merge($sequence, $this->get128ABsequence($code));
1161 }
1162 // process the sequence
1163 foreach ($sequence as $key => $seq) {
1164 switch($seq[0]) {
1165 case 'A': {
1166 if ($key == 0) {
1167 $startid = 103;
1168 } elseif ($sequence[($key - 1)][0] != 'A') {
1169 if (($seq[2] == 1) AND ($key > 0) AND ($sequence[($key - 1)][0] == 'B') AND (!isset($sequence[($key - 1)][3]))) {
1170 // single character shift
1171 $code_data[] = 98;
1172 // mark shift
1173 $sequence[$key][3] = true;
1174 } elseif (!isset($sequence[($key - 1)][3])) {
1175 $code_data[] = 101;
1176 }
1177 }
1178 for ($i = 0; $i < $seq[2]; ++$i) {
1179 $char = $seq[1]{$i};
1180 $char_id = ord($char);
1181 if (($char_id >= 241) AND ($char_id <= 244)) {
1182 $code_data[] = $fnc_a[$char_id];
1183 } else {
1184 $code_data[] = strpos($keys_a, $char);
1185 }
1186 }
1187 break;
1188 }
1189 case 'B': {
1190 if ($key == 0) {
1191 $tmpchr = ord($seq[1][0]);
1192 if (($seq[2] == 1) AND ($tmpchr >= 241) AND ($tmpchr <= 244) AND isset($sequence[($key + 1)]) AND ($sequence[($key + 1)][0] != 'B')) {
1193 switch ($sequence[($key + 1)][0]) {
1194 case 'A': {
1195 $startid = 103;
1196 $sequence[$key][0] = 'A';
1197 $code_data[] = $fnc_a[$tmpchr];
1198 break;
1199 }
1200 case 'C': {
1201 $startid = 105;
1202 $sequence[$key][0] = 'C';
1203 $code_data[] = $fnc_a[$tmpchr];
1204 break;
1205 }
1206 }
1207 break;
1208 } else {
1209 $startid = 104;
1210 }
1211 } elseif ($sequence[($key - 1)][0] != 'B') {
1212 if (($seq[2] == 1) AND ($key > 0) AND ($sequence[($key - 1)][0] == 'A') AND (!isset($sequence[($key - 1)][3]))) {
1213 // single character shift
1214 $code_data[] = 98;
1215 // mark shift
1216 $sequence[$key][3] = true;
1217 } elseif (!isset($sequence[($key - 1)][3])) {
1218 $code_data[] = 100;
1219 }
1220 }
1221 for ($i = 0; $i < $seq[2]; ++$i) {
1222 $char = $seq[1]{$i};
1223 $char_id = ord($char);
1224 if (($char_id >= 241) AND ($char_id <= 244)) {
1225 $code_data[] = $fnc_b[$char_id];
1226 } else {
1227 $code_data[] = strpos($keys_b, $char);
1228 }
1229 }
1230 break;
1231 }
1232 case 'C': {
1233 if ($key == 0) {
1234 $startid = 105;
1235 } elseif ($sequence[($key - 1)][0] != 'C') {
1236 $code_data[] = 99;
1237 }
1238 for ($i = 0; $i < $seq[2]; $i+=2) {
1239 $chrnum = $seq[1]{$i}.$seq[1]{$i+1};
1240 $code_data[] = intval($chrnum);
1241 }
1242 break;
1243 }
1244 }
1245 }
1246 }
1247 }
1248 // calculate check character
1249 $sum = $startid;
1250 foreach ($code_data as $key => $val) {
1251 $sum += ($val * ($key + 1));
1252 }
1253 // add check character
1254 $code_data[] = ($sum % 103);
1255 // add stop sequence
1256 $code_data[] = 106;
1257 $code_data[] = 107;
1258 // add start code at the beginning
1259 array_unshift($code_data, $startid);
1260 // build barcode array
1261 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1262 foreach ($code_data as $val) {
1263 $seq = $chr[$val];
1264 for ($j = 0; $j < 6; ++$j) {
1265 if (($j % 2) == 0) {
1266 $t = true; // bar
1267 } else {
1268 $t = false; // space
1269 }
1270 $w = $seq{$j};
1271 $bararray['bcode'][] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1272 $bararray['maxw'] += $w;
1273 }
1274 }
1275 return $bararray;
1276 }
1277
1278 /**
1279 * Split text code in A/B sequence for 128 code
1280 * @param $code (string) code to split.
1281 * @return array sequence
1282 * @protected
1283 */
1284 protected function get128ABsequence($code) {
1285 $len = strlen($code);
1286 $sequence = array();
1287 // get A sequences (if any)
1288 $numseq = array();
1289 preg_match_all('/([\0-\31])/', $code, $numseq, PREG_OFFSET_CAPTURE);
1290 if (isset($numseq[1]) AND !empty($numseq[1])) {
1291 $end_offset = 0;
1292 foreach ($numseq[1] as $val) {
1293 $offset = $val[1];
1294 if ($offset > $end_offset) {
1295 // B sequence
1296 $sequence[] = array('B', substr($code, $end_offset, ($offset - $end_offset)), ($offset - $end_offset));
1297 }
1298 // A sequence
1299 $slen = strlen($val[0]);
1300 $sequence[] = array('A', substr($code, $offset, $slen), $slen);
1301 $end_offset = $offset + $slen;
1302 }
1303 if ($end_offset < $len) {
1304 $sequence[] = array('B', substr($code, $end_offset), ($len - $end_offset));
1305 }
1306 } else {
1307 // only B sequence
1308 $sequence[] = array('B', $code, $len);
1309 }
1310 return $sequence;
1311 }
1312
1313 /**
1314 * EAN13 and UPC-A barcodes.
1315 * EAN13: European Article Numbering international retail product code
1316 * UPC-A: Universal product code seen on almost all retail products in the USA and Canada
1317 * UPC-E: Short version of UPC symbol
1318 * @param $code (string) code to represent.
1319 * @param $len (string) barcode type: 6 = UPC-E, 8 = EAN8, 13 = EAN13, 12 = UPC-A
1320 * @return array barcode representation.
1321 * @protected
1322 */
1323 protected function barcode_eanupc($code, $len=13) {
1324 $upce = false;
1325 if ($len == 6) {
1326 $len = 12; // UPC-A
1327 $upce = true; // UPC-E mode
1328 }
1329 $data_len = $len - 1;
1330 //Padding
1331 $code = str_pad($code, $data_len, '0', STR_PAD_LEFT);
1332 $code_len = strlen($code);
1333 // calculate check digit
1334 $sum_a = 0;
1335 for ($i = 1; $i < $data_len; $i+=2) {
1336 $sum_a += $code{$i};
1337 }
1338 if ($len > 12) {
1339 $sum_a *= 3;
1340 }
1341 $sum_b = 0;
1342 for ($i = 0; $i < $data_len; $i+=2) {
1343 $sum_b += ($code{$i});
1344 }
1345 if ($len < 13) {
1346 $sum_b *= 3;
1347 }
1348 $r = ($sum_a + $sum_b) % 10;
1349 if($r > 0) {
1350 $r = (10 - $r);
1351 }
1352 if ($code_len == $data_len) {
1353 // add check digit
1354 $code .= $r;
1355 } elseif ($r !== intval($code{$data_len})) {
1356 // wrong checkdigit
1357 return false;
1358 }
1359 if ($len == 12) {
1360 // UPC-A
1361 $code = '0'.$code;
1362 ++$len;
1363 }
1364 if ($upce) {
1365 // convert UPC-A to UPC-E
1366 $tmp = substr($code, 4, 3);
1367 if (($tmp == '000') OR ($tmp == '100') OR ($tmp == '200')) {
1368 // manufacturer code ends in 000, 100, or 200
1369 $upce_code = substr($code, 2, 2).substr($code, 9, 3).substr($code, 4, 1);
1370 } else {
1371 $tmp = substr($code, 5, 2);
1372 if ($tmp == '00') {
1373 // manufacturer code ends in 00
1374 $upce_code = substr($code, 2, 3).substr($code, 10, 2).'3';
1375 } else {
1376 $tmp = substr($code, 6, 1);
1377 if ($tmp == '0') {
1378 // manufacturer code ends in 0
1379 $upce_code = substr($code, 2, 4).substr($code, 11, 1).'4';
1380 } else {
1381 // manufacturer code does not end in zero
1382 $upce_code = substr($code, 2, 5).substr($code, 11, 1);
1383 }
1384 }
1385 }
1386 }
1387 //Convert digits to bars
1388 $codes = array(
1389 'A'=>array( // left odd parity
1390 '0'=>'0001101',
1391 '1'=>'0011001',
1392 '2'=>'0010011',
1393 '3'=>'0111101',
1394 '4'=>'0100011',
1395 '5'=>'0110001',
1396 '6'=>'0101111',
1397 '7'=>'0111011',
1398 '8'=>'0110111',
1399 '9'=>'0001011'),
1400 'B'=>array( // left even parity
1401 '0'=>'0100111',
1402 '1'=>'0110011',
1403 '2'=>'0011011',
1404 '3'=>'0100001',
1405 '4'=>'0011101',
1406 '5'=>'0111001',
1407 '6'=>'0000101',
1408 '7'=>'0010001',
1409 '8'=>'0001001',
1410 '9'=>'0010111'),
1411 'C'=>array( // right
1412 '0'=>'1110010',
1413 '1'=>'1100110',
1414 '2'=>'1101100',
1415 '3'=>'1000010',
1416 '4'=>'1011100',
1417 '5'=>'1001110',
1418 '6'=>'1010000',
1419 '7'=>'1000100',
1420 '8'=>'1001000',
1421 '9'=>'1110100')
1422 );
1423 $parities = array(
1424 '0'=>array('A','A','A','A','A','A'),
1425 '1'=>array('A','A','B','A','B','B'),
1426 '2'=>array('A','A','B','B','A','B'),
1427 '3'=>array('A','A','B','B','B','A'),
1428 '4'=>array('A','B','A','A','B','B'),
1429 '5'=>array('A','B','B','A','A','B'),
1430 '6'=>array('A','B','B','B','A','A'),
1431 '7'=>array('A','B','A','B','A','B'),
1432 '8'=>array('A','B','A','B','B','A'),
1433 '9'=>array('A','B','B','A','B','A')
1434 );
1435 $upce_parities = array();
1436 $upce_parities[0] = array(
1437 '0'=>array('B','B','B','A','A','A'),
1438 '1'=>array('B','B','A','B','A','A'),
1439 '2'=>array('B','B','A','A','B','A'),
1440 '3'=>array('B','B','A','A','A','B'),
1441 '4'=>array('B','A','B','B','A','A'),
1442 '5'=>array('B','A','A','B','B','A'),
1443 '6'=>array('B','A','A','A','B','B'),
1444 '7'=>array('B','A','B','A','B','A'),
1445 '8'=>array('B','A','B','A','A','B'),
1446 '9'=>array('B','A','A','B','A','B')
1447 );
1448 $upce_parities[1] = array(
1449 '0'=>array('A','A','A','B','B','B'),
1450 '1'=>array('A','A','B','A','B','B'),
1451 '2'=>array('A','A','B','B','A','B'),
1452 '3'=>array('A','A','B','B','B','A'),
1453 '4'=>array('A','B','A','A','B','B'),
1454 '5'=>array('A','B','B','A','A','B'),
1455 '6'=>array('A','B','B','B','A','A'),
1456 '7'=>array('A','B','A','B','A','B'),
1457 '8'=>array('A','B','A','B','B','A'),
1458 '9'=>array('A','B','B','A','B','A')
1459 );
1460 $k = 0;
1461 $seq = '101'; // left guard bar
1462 if ($upce) {
1463 $bararray = array('code' => $upce_code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1464 $p = $upce_parities[$code[1]][$r];
1465 for ($i = 0; $i < 6; ++$i) {
1466 $seq .= $codes[$p[$i]][$upce_code{$i}];
1467 }
1468 $seq .= '010101'; // right guard bar
1469 } else {
1470 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1471 $half_len = intval(ceil($len / 2));
1472 if ($len == 8) {
1473 for ($i = 0; $i < $half_len; ++$i) {
1474 $seq .= $codes['A'][$code{$i}];
1475 }
1476 } else {
1477 $p = $parities[$code[0]];
1478 for ($i = 1; $i < $half_len; ++$i) {
1479 $seq .= $codes[$p[$i-1]][$code{$i}];
1480 }
1481 }
1482 $seq .= '01010'; // center guard bar
1483 for ($i = $half_len; $i < $len; ++$i) {
1484 $seq .= $codes['C'][$code{$i}];
1485 }
1486 $seq .= '101'; // right guard bar
1487 }
1488 $clen = strlen($seq);
1489 $w = 0;
1490 for ($i = 0; $i < $clen; ++$i) {
1491 $w += 1;
1492 if (($i == ($clen - 1)) OR (($i < ($clen - 1)) AND ($seq{$i} != $seq{($i+1)}))) {
1493 if ($seq{$i} == '1') {
1494 $t = true; // bar
1495 } else {
1496 $t = false; // space
1497 }
1498 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1499 $bararray['maxw'] += $w;
1500 ++$k;
1501 $w = 0;
1502 }
1503 }
1504 return $bararray;
1505 }
1506
1507 /**
1508 * UPC-Based Extentions
1509 * 2-Digit Ext.: Used to indicate magazines and newspaper issue numbers
1510 * 5-Digit Ext.: Used to mark suggested retail price of books
1511 * @param $code (string) code to represent.
1512 * @param $len (string) barcode type: 2 = 2-Digit, 5 = 5-Digit
1513 * @return array barcode representation.
1514 * @protected
1515 */
1516 protected function barcode_eanext($code, $len=5) {
1517 //Padding
1518 $code = str_pad($code, $len, '0', STR_PAD_LEFT);
1519 // calculate check digit
1520 if ($len == 2) {
1521 $r = $code % 4;
1522 } elseif ($len == 5) {
1523 $r = (3 * ($code[0] + $code[2] + $code[4])) + (9 * ($code[1] + $code[3]));
1524 $r %= 10;
1525 } else {
1526 return false;
1527 }
1528 //Convert digits to bars
1529 $codes = array(
1530 'A'=>array( // left odd parity
1531 '0'=>'0001101',
1532 '1'=>'0011001',
1533 '2'=>'0010011',
1534 '3'=>'0111101',
1535 '4'=>'0100011',
1536 '5'=>'0110001',
1537 '6'=>'0101111',
1538 '7'=>'0111011',
1539 '8'=>'0110111',
1540 '9'=>'0001011'),
1541 'B'=>array( // left even parity
1542 '0'=>'0100111',
1543 '1'=>'0110011',
1544 '2'=>'0011011',
1545 '3'=>'0100001',
1546 '4'=>'0011101',
1547 '5'=>'0111001',
1548 '6'=>'0000101',
1549 '7'=>'0010001',
1550 '8'=>'0001001',
1551 '9'=>'0010111')
1552 );
1553 $parities = array();
1554 $parities[2] = array(
1555 '0'=>array('A','A'),
1556 '1'=>array('A','B'),
1557 '2'=>array('B','A'),
1558 '3'=>array('B','B')
1559 );
1560 $parities[5] = array(
1561 '0'=>array('B','B','A','A','A'),
1562 '1'=>array('B','A','B','A','A'),
1563 '2'=>array('B','A','A','B','A'),
1564 '3'=>array('B','A','A','A','B'),
1565 '4'=>array('A','B','B','A','A'),
1566 '5'=>array('A','A','B','B','A'),
1567 '6'=>array('A','A','A','B','B'),
1568 '7'=>array('A','B','A','B','A'),
1569 '8'=>array('A','B','A','A','B'),
1570 '9'=>array('A','A','B','A','B')
1571 );
1572 $p = $parities[$len][$r];
1573 $seq = '1011'; // left guard bar
1574 $seq .= $codes[$p[0]][$code[0]];
1575 for ($i = 1; $i < $len; ++$i) {
1576 $seq .= '01'; // separator
1577 $seq .= $codes[$p[$i]][$code{$i}];
1578 }
1579 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1580 return $this->binseq_to_array($seq, $bararray);
1581 }
1582
1583 /**
1584 * POSTNET and PLANET barcodes.
1585 * Used by U.S. Postal Service for automated mail sorting
1586 * @param $code (string) zip code to represent. Must be a string containing a zip code of the form DDDDD or DDDDD-DDDD.
1587 * @param $planet (boolean) if true print the PLANET barcode, otherwise print POSTNET
1588 * @return array barcode representation.
1589 * @protected
1590 */
1591 protected function barcode_postnet($code, $planet=false) {
1592 // bar lenght
1593 if ($planet) {
1594 $barlen = Array(
1595 0 => Array(1,1,2,2,2),
1596 1 => Array(2,2,2,1,1),
1597 2 => Array(2,2,1,2,1),
1598 3 => Array(2,2,1,1,2),
1599 4 => Array(2,1,2,2,1),
1600 5 => Array(2,1,2,1,2),
1601 6 => Array(2,1,1,2,2),
1602 7 => Array(1,2,2,2,1),
1603 8 => Array(1,2,2,1,2),
1604 9 => Array(1,2,1,2,2)
1605 );
1606 } else {
1607 $barlen = Array(
1608 0 => Array(2,2,1,1,1),
1609 1 => Array(1,1,1,2,2),
1610 2 => Array(1,1,2,1,2),
1611 3 => Array(1,1,2,2,1),
1612 4 => Array(1,2,1,1,2),
1613 5 => Array(1,2,1,2,1),
1614 6 => Array(1,2,2,1,1),
1615 7 => Array(2,1,1,1,2),
1616 8 => Array(2,1,1,2,1),
1617 9 => Array(2,1,2,1,1)
1618 );
1619 }
1620 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 2, 'bcode' => array());
1621 $k = 0;
1622 $code = str_replace('-', '', $code);
1623 $code = str_replace(' ', '', $code);
1624 $len = strlen($code);
1625 // calculate checksum
1626 $sum = 0;
1627 for ($i = 0; $i < $len; ++$i) {
1628 $sum += intval($code{$i});
1629 }
1630 $chkd = ($sum % 10);
1631 if($chkd > 0) {
1632 $chkd = (10 - $chkd);
1633 }
1634 $code .= $chkd;
1635 $len = strlen($code);
1636 // start bar
1637 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0);
1638 $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1639 $bararray['maxw'] += 2;
1640 for ($i = 0; $i < $len; ++$i) {
1641 for ($j = 0; $j < 5; ++$j) {
1642 $h = $barlen[$code{$i}][$j];
1643 $p = floor(1 / $h);
1644 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
1645 $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1646 $bararray['maxw'] += 2;
1647 }
1648 }
1649 // end bar
1650 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0);
1651 $bararray['maxw'] += 1;
1652 return $bararray;
1653 }
1654
1655 /**
1656 * RMS4CC - CBC - KIX
1657 * RMS4CC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code) - KIX (Klant index - Customer index)
1658 * RM4SCC is the name of the barcode symbology used by the Royal Mail for its Cleanmail service.
1659 * @param $code (string) code to print
1660 * @param $kix (boolean) if true prints the KIX variation (doesn't use the start and end symbols, and the checksum) - in this case the house number must be sufficed with an X and placed at the end of the code.
1661 * @return array barcode representation.
1662 * @protected
1663 */
1664 protected function barcode_rms4cc($code, $kix=false) {
1665 $notkix = !$kix;
1666 // bar mode
1667 // 1 = pos 1, length 2
1668 // 2 = pos 1, length 3
1669 // 3 = pos 2, length 1
1670 // 4 = pos 2, length 2
1671 $barmode = array(
1672 '0' => array(3,3,2,2),
1673 '1' => array(3,4,1,2),
1674 '2' => array(3,4,2,1),
1675 '3' => array(4,3,1,2),
1676 '4' => array(4,3,2,1),
1677 '5' => array(4,4,1,1),
1678 '6' => array(3,1,4,2),
1679 '7' => array(3,2,3,2),
1680 '8' => array(3,2,4,1),
1681 '9' => array(4,1,3,2),
1682 'A' => array(4,1,4,1),
1683 'B' => array(4,2,3,1),
1684 'C' => array(3,1,2,4),
1685 'D' => array(3,2,1,4),
1686 'E' => array(3,2,2,3),
1687 'F' => array(4,1,1,4),
1688 'G' => array(4,1,2,3),
1689 'H' => array(4,2,1,3),
1690 'I' => array(1,3,4,2),
1691 'J' => array(1,4,3,2),
1692 'K' => array(1,4,4,1),
1693 'L' => array(2,3,3,2),
1694 'M' => array(2,3,4,1),
1695 'N' => array(2,4,3,1),
1696 'O' => array(1,3,2,4),
1697 'P' => array(1,4,1,4),
1698 'Q' => array(1,4,2,3),
1699 'R' => array(2,3,1,4),
1700 'S' => array(2,3,2,3),
1701 'T' => array(2,4,1,3),
1702 'U' => array(1,1,4,4),
1703 'V' => array(1,2,3,4),
1704 'W' => array(1,2,4,3),
1705 'X' => array(2,1,3,4),
1706 'Y' => array(2,1,4,3),
1707 'Z' => array(2,2,3,3)
1708 );
1709 $code = strtoupper($code);
1710 $len = strlen($code);
1711 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 3, 'bcode' => array());
1712 if ($notkix) {
1713 // table for checksum calculation (row,col)
1714 $checktable = array(
1715 '0' => array(1,1),
1716 '1' => array(1,2),
1717 '2' => array(1,3),
1718 '3' => array(1,4),
1719 '4' => array(1,5),
1720 '5' => array(1,0),
1721 '6' => array(2,1),
1722 '7' => array(2,2),
1723 '8' => array(2,3),
1724 '9' => array(2,4),
1725 'A' => array(2,5),
1726 'B' => array(2,0),
1727 'C' => array(3,1),
1728 'D' => array(3,2),
1729 'E' => array(3,3),
1730 'F' => array(3,4),
1731 'G' => array(3,5),
1732 'H' => array(3,0),
1733 'I' => array(4,1),
1734 'J' => array(4,2),
1735 'K' => array(4,3),
1736 'L' => array(4,4),
1737 'M' => array(4,5),
1738 'N' => array(4,0),
1739 'O' => array(5,1),
1740 'P' => array(5,2),
1741 'Q' => array(5,3),
1742 'R' => array(5,4),
1743 'S' => array(5,5),
1744 'T' => array(5,0),
1745 'U' => array(0,1),
1746 'V' => array(0,2),
1747 'W' => array(0,3),
1748 'X' => array(0,4),
1749 'Y' => array(0,5),
1750 'Z' => array(0,0)
1751 );
1752 $row = 0;
1753 $col = 0;
1754 for ($i = 0; $i < $len; ++$i) {
1755 $row += $checktable[$code{$i}][0];
1756 $col += $checktable[$code{$i}][1];
1757 }
1758 $row %= 6;
1759 $col %= 6;
1760 $chk = array_keys($checktable, array($row,$col));
1761 $code .= $chk[0];
1762 ++$len;
1763 }
1764 $k = 0;
1765 if ($notkix) {
1766 // start bar
1767 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 2, 'p' => 0);
1768 $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1769 $bararray['maxw'] += 2;
1770 }
1771 for ($i = 0; $i < $len; ++$i) {
1772 for ($j = 0; $j < 4; ++$j) {
1773 switch ($barmode[$code{$i}][$j]) {
1774 case 1: {
1775 $p = 0;
1776 $h = 2;
1777 break;
1778 }
1779 case 2: {
1780 $p = 0;
1781 $h = 3;
1782 break;
1783 }
1784 case 3: {
1785 $p = 1;
1786 $h = 1;
1787 break;
1788 }
1789 case 4: {
1790 $p = 1;
1791 $h = 2;
1792 break;
1793 }
1794 }
1795 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
1796 $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
1797 $bararray['maxw'] += 2;
1798 }
1799 }
1800 if ($notkix) {
1801 // stop bar
1802 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 3, 'p' => 0);
1803 $bararray['maxw'] += 1;
1804 }
1805 return $bararray;
1806 }
1807
1808 /**
1809 * CODABAR barcodes.
1810 * Older code often used in library systems, sometimes in blood banks
1811 * @param $code (string) code to represent.
1812 * @return array barcode representation.
1813 * @protected
1814 */
1815 protected function barcode_codabar($code) {
1816 $chr = array(
1817 '0' => '11111221',
1818 '1' => '11112211',
1819 '2' => '11121121',
1820 '3' => '22111111',
1821 '4' => '11211211',
1822 '5' => '21111211',
1823 '6' => '12111121',
1824 '7' => '12112111',
1825 '8' => '12211111',
1826 '9' => '21121111',
1827 '-' => '11122111',
1828 '$' => '11221111',
1829 ':' => '21112121',
1830 '/' => '21211121',
1831 '.' => '21212111',
1832 '+' => '11222221',
1833 'A' => '11221211',
1834 'B' => '12121121',
1835 'C' => '11121221',
1836 'D' => '11122211'
1837 );
1838 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1839 $k = 0;
1840 $w = 0;
1841 $seq = '';
1842 $code = 'A'.strtoupper($code).'A';
1843 $len = strlen($code);
1844 for ($i = 0; $i < $len; ++$i) {
1845 if (!isset($chr[$code{$i}])) {
1846 return false;
1847 }
1848 $seq = $chr[$code{$i}];
1849 for ($j = 0; $j < 8; ++$j) {
1850 if (($j % 2) == 0) {
1851 $t = true; // bar
1852 } else {
1853 $t = false; // space
1854 }
1855 $w = $seq{$j};
1856 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1857 $bararray['maxw'] += $w;
1858 ++$k;
1859 }
1860 }
1861 return $bararray;
1862 }
1863
1864 /**
1865 * CODE11 barcodes.
1866 * Used primarily for labeling telecommunications equipment
1867 * @param $code (string) code to represent.
1868 * @return array barcode representation.
1869 * @protected
1870 */
1871 protected function barcode_code11($code) {
1872 $chr = array(
1873 '0' => '111121',
1874 '1' => '211121',
1875 '2' => '121121',
1876 '3' => '221111',
1877 '4' => '112121',
1878 '5' => '212111',
1879 '6' => '122111',
1880 '7' => '111221',
1881 '8' => '211211',
1882 '9' => '211111',
1883 '-' => '112111',
1884 'S' => '112211'
1885 );
1886 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1887 $k = 0;
1888 $w = 0;
1889 $seq = '';
1890 $len = strlen($code);
1891 // calculate check digit C
1892 $p = 1;
1893 $check = 0;
1894 for ($i = ($len - 1); $i >= 0; --$i) {
1895 $digit = $code{$i};
1896 if ($digit == '-') {
1897 $dval = 10;
1898 } else {
1899 $dval = intval($digit);
1900 }
1901 $check += ($dval * $p);
1902 ++$p;
1903 if ($p > 10) {
1904 $p = 1;
1905 }
1906 }
1907 $check %= 11;
1908 if ($check == 10) {
1909 $check = '-';
1910 }
1911 $code .= $check;
1912 if ($len > 10) {
1913 // calculate check digit K
1914 $p = 1;
1915 $check = 0;
1916 for ($i = $len; $i >= 0; --$i) {
1917 $digit = $code{$i};
1918 if ($digit == '-') {
1919 $dval = 10;
1920 } else {
1921 $dval = intval($digit);
1922 }
1923 $check += ($dval * $p);
1924 ++$p;
1925 if ($p > 9) {
1926 $p = 1;
1927 }
1928 }
1929 $check %= 11;
1930 $code .= $check;
1931 ++$len;
1932 }
1933 $code = 'S'.$code.'S';
1934 $len += 3;
1935 for ($i = 0; $i < $len; ++$i) {
1936 if (!isset($chr[$code{$i}])) {
1937 return false;
1938 }
1939 $seq = $chr[$code{$i}];
1940 for ($j = 0; $j < 6; ++$j) {
1941 if (($j % 2) == 0) {
1942 $t = true; // bar
1943 } else {
1944 $t = false; // space
1945 }
1946 $w = $seq{$j};
1947 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1948 $bararray['maxw'] += $w;
1949 ++$k;
1950 }
1951 }
1952 return $bararray;
1953 }
1954
1955 /**
1956 * Pharmacode
1957 * Contains digits (0 to 9)
1958 * @param $code (string) code to represent.
1959 * @return array barcode representation.
1960 * @protected
1961 */
1962 protected function barcode_pharmacode($code) {
1963 $seq = '';
1964 $code = intval($code);
1965 while ($code > 0) {
1966 if (($code % 2) == 0) {
1967 $seq .= '11100';
1968 $code -= 2;
1969 } else {
1970 $seq .= '100';
1971 $code -= 1;
1972 }
1973 $code /= 2;
1974 }
1975 $seq = substr($seq, 0, -2);
1976 $seq = strrev($seq);
1977 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1978 return $this->binseq_to_array($seq, $bararray);
1979 }
1980
1981 /**
1982 * Pharmacode two-track
1983 * Contains digits (0 to 9)
1984 * @param $code (string) code to represent.
1985 * @return array barcode representation.
1986 * @protected
1987 */
1988 protected function barcode_pharmacode2t($code) {
1989 $seq = '';
1990 $code = intval($code);
1991 do {
1992 switch ($code % 3) {
1993 case 0: {
1994 $seq .= '3';
1995 $code = ($code - 3) / 3;
1996 break;
1997 }
1998 case 1: {
1999 $seq .= '1';
2000 $code = ($code - 1) / 3;
2001 break;
2002 }
2003 case 2: {
2004 $seq .= '2';
2005 $code = ($code - 2) / 3;
2006 break;
2007 }
2008 }
2009 } while($code != 0);
2010 $seq = strrev($seq);
2011 $k = 0;
2012 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 2, 'bcode' => array());
2013 $len = strlen($seq);
2014 for ($i = 0; $i < $len; ++$i) {
2015 switch ($seq{$i}) {
2016 case '1': {
2017 $p = 1;
2018 $h = 1;
2019 break;
2020 }
2021 case '2': {
2022 $p = 0;
2023 $h = 1;
2024 break;
2025 }
2026 case '3': {
2027 $p = 0;
2028 $h = 2;
2029 break;
2030 }
2031 }
2032 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
2033 $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
2034 $bararray['maxw'] += 2;
2035 }
2036 unset($bararray['bcode'][($k - 1)]);
2037 --$bararray['maxw'];
2038 return $bararray;
2039 }
2040
2041
2042 /**
2043 * IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200
2044 * (requires PHP bcmath extension)
2045 * Intelligent Mail barcode is a 65-bar code for use on mail in the United States.
2046 * The fields are described as follows:<ul><li>The Barcode Identifier shall be assigned by USPS to encode the presort identification that is currently printed in human readable form on the optional endorsement line (OEL) as well as for future USPS use. This shall be two digits, with the second digit in the range of 0–4. The allowable encoding ranges shall be 00–04, 10–14, 20–24, 30–34, 40–44, 50–54, 60–64, 70–74, 80–84, and 90–94.</li><li>The Service Type Identifier shall be assigned by USPS for any combination of services requested on the mailpiece. The allowable encoding range shall be 000http://it2.php.net/manual/en/function.dechex.php–999. Each 3-digit value shall correspond to a particular mail class with a particular combination of service(s). Each service program, such as OneCode Confirm and OneCode ACS, shall provide the list of Service Type Identifier values.</li><li>The Mailer or Customer Identifier shall be assigned by USPS as a unique, 6 or 9 digit number that identifies a business entity. The allowable encoding range for the 6 digit Mailer ID shall be 000000- 899999, while the allowable encoding range for the 9 digit Mailer ID shall be 900000000-999999999.</li><li>The Serial or Sequence Number shall be assigned by the mailer for uniquely identifying and tracking mailpieces. The allowable encoding range shall be 000000000–999999999 when used with a 6 digit Mailer ID and 000000-999999 when used with a 9 digit Mailer ID. e. The Delivery Point ZIP Code shall be assigned by the mailer for routing the mailpiece. This shall replace POSTNET for routing the mailpiece to its final delivery point. The length may be 0, 5, 9, or 11 digits. The allowable encoding ranges shall be no ZIP Code, 00000–99999, 000000000–999999999, and 00000000000–99999999999.</li></ul>
2047 * @param $code (string) code to print, separate the ZIP (routing code) from the rest using a minus char '-' (BarcodeID_ServiceTypeID_MailerID_SerialNumber-RoutingCode)
2048 * @return array barcode representation.
2049 * @protected
2050 */
2051 protected function barcode_imb($code) {
2052 $asc_chr = array(4,0,2,6,3,5,1,9,8,7,1,2,0,6,4,8,2,9,5,3,0,1,3,7,4,6,8,9,2,0,5,1,9,4,3,8,6,7,1,2,4,3,9,5,7,8,3,0,2,1,4,0,9,1,7,0,2,4,6,3,7,1,9,5,8);
2053 $dsc_chr = array(7,1,9,5,8,0,2,4,6,3,5,8,9,7,3,0,6,1,7,4,6,8,9,2,5,1,7,5,4,3,8,7,6,0,2,5,4,9,3,0,1,6,8,2,0,4,5,9,6,7,5,2,6,3,8,5,1,9,8,7,4,0,2,6,3);
2054 $asc_pos = array(3,0,8,11,1,12,8,11,10,6,4,12,2,7,9,6,7,9,2,8,4,0,12,7,10,9,0,7,10,5,7,9,6,8,2,12,1,4,2,0,1,5,4,6,12,1,0,9,4,7,5,10,2,6,9,11,2,12,6,7,5,11,0,3,2);
2055 $dsc_pos = array(2,10,12,5,9,1,5,4,3,9,11,5,10,1,6,3,4,1,10,0,2,11,8,6,1,12,3,8,6,4,4,11,0,6,1,9,11,5,3,7,3,10,7,11,8,2,10,3,5,8,0,3,12,11,8,4,5,1,3,0,7,12,9,8,10);
2056 $code_arr = explode('-', $code);
2057 $tracking_number = $code_arr[0];
2058 if (isset($code_arr[1])) {
2059 $routing_code = $code_arr[1];
2060 } else {
2061 $routing_code = '';
2062 }
2063 // Conversion of Routing Code
2064 switch (strlen($routing_code)) {
2065 case 0: {
2066 $binary_code = 0;
2067 break;
2068 }
2069 case 5: {
2070 $binary_code = bcadd($routing_code, '1');
2071 break;
2072 }
2073 case 9: {
2074 $binary_code = bcadd($routing_code, '100001');
2075 break;
2076 }
2077 case 11: {
2078 $binary_code = bcadd($routing_code, '1000100001');
2079 break;
2080 }
2081 default: {
2082 return false;
2083 break;
2084 }
2085 }
2086 $binary_code = bcmul($binary_code, 10);
2087 $binary_code = bcadd($binary_code, $tracking_number[0]);
2088 $binary_code = bcmul($binary_code, 5);
2089 $binary_code = bcadd($binary_code, $tracking_number[1]);
2090 $binary_code .= substr($tracking_number, 2, 18);
2091 // convert to hexadecimal
2092 $binary_code = $this->dec_to_hex($binary_code);
2093 // pad to get 13 bytes
2094 $binary_code = str_pad($binary_code, 26, '0', STR_PAD_LEFT);
2095 // convert string to array of bytes
2096 $binary_code_arr = chunk_split($binary_code, 2, "\r");
2097 $binary_code_arr = substr($binary_code_arr, 0, -1);
2098 $binary_code_arr = explode("\r", $binary_code_arr);
2099 // calculate frame check sequence
2100 $fcs = $this->imb_crc11fcs($binary_code_arr);
2101 // exclude first 2 bits from first byte
2102 $first_byte = sprintf('%2s', dechex((hexdec($binary_code_arr[0]) << 2) >> 2));
2103 $binary_code_102bit = $first_byte.substr($binary_code, 2);
2104 // convert binary data to codewords
2105 $codewords = array();
2106 $data = $this->hex_to_dec($binary_code_102bit);
2107 $codewords[0] = bcmod($data, 636) * 2;
2108 $data = bcdiv($data, 636);
2109 for ($i = 1; $i < 9; ++$i) {
2110 $codewords[$i] = bcmod($data, 1365);
2111 $data = bcdiv($data, 1365);
2112 }
2113 $codewords[9] = $data;
2114 if (($fcs >> 10) == 1) {
2115 $codewords[9] += 659;
2116 }
2117 // generate lookup tables
2118 $table2of13 = $this->imb_tables(2, 78);
2119 $table5of13 = $this->imb_tables(5, 1287);
2120 // convert codewords to characters
2121 $characters = array();
2122 $bitmask = 512;
2123 foreach($codewords as $k => $val) {
2124 if ($val <= 1286) {
2125 $chrcode = $table5of13[$val];
2126 } else {
2127 $chrcode = $table2of13[($val - 1287)];
2128 }
2129 if (($fcs & $bitmask) > 0) {
2130 // bitwise invert
2131 $chrcode = ((~$chrcode) & 8191);
2132 }
2133 $characters[] = $chrcode;
2134 $bitmask /= 2;
2135 }
2136 $characters = array_reverse($characters);
2137 // build bars
2138 $k = 0;
2139 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 3, 'bcode' => array());
2140 for ($i = 0; $i < 65; ++$i) {
2141 $asc = (($characters[$asc_chr[$i]] & pow(2, $asc_pos[$i])) > 0);
2142 $dsc = (($characters[$dsc_chr[$i]] & pow(2, $dsc_pos[$i])) > 0);
2143 if ($asc AND $dsc) {
2144 // full bar (F)
2145 $p = 0;
2146 $h = 3;
2147 } elseif ($asc) {
2148 // ascender (A)
2149 $p = 0;
2150 $h = 2;
2151 } elseif ($dsc) {
2152 // descender (D)
2153 $p = 1;
2154 $h = 2;
2155 } else {
2156 // tracker (T)
2157 $p = 1;
2158 $h = 1;
2159 }
2160 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
2161 $bararray['bcode'][$k++] = array('t' => 0, 'w' => 1, 'h' => 2, 'p' => 0);
2162 $bararray['maxw'] += 2;
2163 }
2164 unset($bararray['bcode'][($k - 1)]);
2165 --$bararray['maxw'];
2166 return $bararray;
2167 }
2168
2169 /**
2170 * Convert large integer number to hexadecimal representation.
2171 * (requires PHP bcmath extension)
2172 * @param $number (string) number to convert specified as a string
2173 * @return string hexadecimal representation
2174 */
2175 public function dec_to_hex($number) {
2176 $i = 0;
2177 $hex = array();
2178 if($number == 0) {
2179 return '00';
2180 }
2181 while($number > 0) {
2182 if($number == 0) {
2183 array_push($hex, '0');
2184 } else {
2185 array_push($hex, strtoupper(dechex(bcmod($number, '16'))));
2186 $number = bcdiv($number, '16', 0);
2187 }
2188 }
2189 $hex = array_reverse($hex);
2190 return implode($hex);
2191 }
2192
2193 /**
2194 * Convert large hexadecimal number to decimal representation (string).
2195 * (requires PHP bcmath extension)
2196 * @param $hex (string) hexadecimal number to convert specified as a string
2197 * @return string hexadecimal representation
2198 */
2199 public function hex_to_dec($hex) {
2200 $dec = 0;
2201 $bitval = 1;
2202 $len = strlen($hex);
2203 for($pos = ($len - 1); $pos >= 0; --$pos) {
2204 $dec = bcadd($dec, bcmul(hexdec($hex{$pos}), $bitval));
2205 $bitval = bcmul($bitval, 16);
2206 }
2207 return $dec;
2208 }
2209
2210 /**
2211 * Intelligent Mail Barcode calculation of Frame Check Sequence
2212 * @param $code_arr (string) array of hexadecimal values (13 bytes holding 102 bits right justified).
2213 * @return int 11 bit Frame Check Sequence as integer (decimal base)
2214 * @protected
2215 */
2216 protected function imb_crc11fcs($code_arr) {
2217 $genpoly = 0x0F35; // generator polynomial
2218 $fcs = 0x07FF; // Frame Check Sequence
2219 // do most significant byte skipping the 2 most significant bits
2220 $data = hexdec($code_arr[0]) << 5;
2221 for ($bit = 2; $bit < 8; ++$bit) {
2222 if (($fcs ^ $data) & 0x400) {
2223 $fcs = ($fcs << 1) ^ $genpoly;
2224 } else {
2225 $fcs = ($fcs << 1);
2226 }
2227 $fcs &= 0x7FF;
2228 $data <<= 1;
2229 }
2230 // do rest of bytes
2231 for ($byte = 1; $byte < 13; ++$byte) {
2232 $data = hexdec($code_arr[$byte]) << 3;
2233 for ($bit = 0; $bit < 8; ++$bit) {
2234 if (($fcs ^ $data) & 0x400) {
2235 $fcs = ($fcs << 1) ^ $genpoly;
2236 } else {
2237 $fcs = ($fcs << 1);
2238 }
2239 $fcs &= 0x7FF;
2240 $data <<= 1;
2241 }
2242 }
2243 return $fcs;
2244 }
2245
2246 /**
2247 * Reverse unsigned short value
2248 * @param $num (int) value to reversr
2249 * @return int reversed value
2250 * @protected
2251 */
2252 protected function imb_reverse_us($num) {
2253 $rev = 0;
2254 for ($i = 0; $i < 16; ++$i) {
2255 $rev <<= 1;
2256 $rev |= ($num & 1);
2257 $num >>= 1;
2258 }
2259 return $rev;
2260 }
2261
2262 /**
2263 * generate Nof13 tables used for Intelligent Mail Barcode
2264 * @param $n (int) is the type of table: 2 for 2of13 table, 5 for 5of13table
2265 * @param $size (int) size of table (78 for n=2 and 1287 for n=5)
2266 * @return array requested table
2267 * @protected
2268 */
2269 protected function imb_tables($n, $size) {
2270 $table = array();
2271 $lli = 0; // LUT lower index
2272 $lui = $size - 1; // LUT upper index
2273 for ($count = 0; $count < 8192; ++$count) {
2274 $bit_count = 0;
2275 for ($bit_index = 0; $bit_index < 13; ++$bit_index) {
2276 $bit_count += intval(($count & (1 << $bit_index)) != 0);
2277 }
2278 // if we don't have the right number of bits on, go on to the next value
2279 if ($bit_count == $n) {
2280 $reverse = ($this->imb_reverse_us($count) >> 3);
2281 // if the reverse is less than count, we have already visited this pair before
2282 if ($reverse >= $count) {
2283 // If count is symmetric, place it at the first free slot from the end of the list.
2284 // Otherwise, place it at the first free slot from the beginning of the list AND place $reverse ath the next free slot from the beginning of the list
2285 if ($reverse == $count) {
2286 $table[$lui] = $count;
2287 --$lui;
2288 } else {
2289 $table[$lli] = $count;
2290 ++$lli;
2291 $table[$lli] = $reverse;
2292 ++$lli;
2293 }
2294 }
2295 }
2296 }
2297 return $table;
2298 }
2299
2300} // end of class
2301//============================================================+
2302// END OF FILE
2303//============================================================+
diff --git a/inc/3rdparty/libraries/tcpdf/tcpdf_barcodes_2d.php b/inc/3rdparty/libraries/tcpdf/tcpdf_barcodes_2d.php
new file mode 100644
index 00000000..13e23655
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/tcpdf_barcodes_2d.php
@@ -0,0 +1,349 @@
1<?php
2//============================================================+
3// File name : tcpdf_barcodes_2d.php
4// Version : 1.0.015
5// Begin : 2009-04-07
6// Last Update : 2014-05-20
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) 2009-2014 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 GNU Lesser General Public License
25// along with TCPDF. If not, see <http://www.gnu.org/licenses/>.
26//
27// See LICENSE.TXT file for more information.
28// -------------------------------------------------------------------
29//
30// Description : PHP class to creates array representations for
31// 2D barcodes to be used with TCPDF.
32//
33//============================================================+
34
35/**
36 * @file
37 * PHP class to creates array representations for 2D barcodes to be used with TCPDF.
38 * @package com.tecnick.tcpdf
39 * @author Nicola Asuni
40 * @version 1.0.015
41 */
42
43/**
44 * @class TCPDF2DBarcode
45 * PHP class to creates array representations for 2D barcodes to be used with TCPDF (http://www.tcpdf.org).
46 * @package com.tecnick.tcpdf
47 * @version 1.0.015
48 * @author Nicola Asuni
49 */
50class TCPDF2DBarcode {
51
52 /**
53 * Array representation of barcode.
54 * @protected
55 */
56 protected $barcode_array = false;
57
58 /**
59 * This is the class constructor.
60 * Return an array representations for 2D barcodes:<ul>
61 * <li>$arrcode['code'] code to be printed on text label</li>
62 * <li>$arrcode['num_rows'] required number of rows</li>
63 * <li>$arrcode['num_cols'] required number of columns</li>
64 * <li>$arrcode['bcode'][$r][$c] value of the cell is $r row and $c column (0 = transparent, 1 = black)</li></ul>
65 * @param $code (string) code to print
66 * @param $type (string) type of barcode: <ul><li>DATAMATRIX : Datamatrix (ISO/IEC 16022)</li><li>PDF417 : PDF417 (ISO/IEC 15438:2006)</li><li>PDF417,a,e,t,s,f,o0,o1,o2,o3,o4,o5,o6 : PDF417 with parameters: a = aspect ratio (width/height); e = error correction level (0-8); t = total number of macro segments; s = macro segment index (0-99998); f = file ID; o0 = File Name (text); o1 = Segment Count (numeric); o2 = Time Stamp (numeric); o3 = Sender (text); o4 = Addressee (text); o5 = File Size (numeric); o6 = Checksum (numeric). NOTES: Parameters t, s and f are required for a Macro Control Block, all other parametrs are optional. To use a comma character ',' on text options, replace it with the character 255: "\xff".</li><li>QRCODE : QRcode Low error correction</li><li>QRCODE,L : QRcode Low error correction</li><li>QRCODE,M : QRcode Medium error correction</li><li>QRCODE,Q : QRcode Better error correction</li><li>QRCODE,H : QR-CODE Best error correction</li><li>RAW: raw mode - comma-separad list of array rows</li><li>RAW2: raw mode - array rows are surrounded by square parenthesis.</li><li>TEST : Test matrix</li></ul>
67 */
68 public function __construct($code, $type) {
69 $this->setBarcode($code, $type);
70 }
71
72 /**
73 * Return an array representations of barcode.
74 * @return array
75 */
76 public function getBarcodeArray() {
77 return $this->barcode_array;
78 }
79
80 /**
81 * Send barcode as SVG image object to the standard output.
82 * @param $w (int) Width of a single rectangle element in user units.
83 * @param $h (int) Height of a single rectangle element in user units.
84 * @param $color (string) Foreground color (in SVG format) for bar elements (background is transparent).
85 * @public
86 */
87 public function getBarcodeSVG($w=3, $h=3, $color='black') {
88 // send headers
89 $code = $this->getBarcodeSVGcode($w, $h, $color);
90 header('Content-Type: application/svg+xml');
91 header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1
92 header('Pragma: public');
93 header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past
94 header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
95 header('Content-Disposition: inline; filename="'.md5($code).'.svg";');
96 //header('Content-Length: '.strlen($code));
97 echo $code;
98 }
99
100 /**
101 * Return a SVG string representation of barcode.
102 * @param $w (int) Width of a single rectangle element in user units.
103 * @param $h (int) Height of a single rectangle element in user units.
104 * @param $color (string) Foreground color (in SVG format) for bar elements (background is transparent).
105 * @return string SVG code.
106 * @public
107 */
108 public function getBarcodeSVGcode($w=3, $h=3, $color='black') {
109 // replace table for special characters
110 $repstr = array("\0" => '', '&' => '&amp;', '<' => '&lt;', '>' => '&gt;');
111 $svg = '<'.'?'.'xml version="1.0" standalone="no"'.'?'.'>'."\n";
112 $svg .= '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'."\n";
113 $svg .= '<svg width="'.round(($this->barcode_array['num_cols'] * $w), 3).'" height="'.round(($this->barcode_array['num_rows'] * $h), 3).'" version="1.1" xmlns="http://www.w3.org/2000/svg">'."\n";
114 $svg .= "\t".'<desc>'.strtr($this->barcode_array['code'], $repstr).'</desc>'."\n";
115 $svg .= "\t".'<g id="elements" fill="'.$color.'" stroke="none">'."\n";
116 // print barcode elements
117 $y = 0;
118 // for each row
119 for ($r = 0; $r < $this->barcode_array['num_rows']; ++$r) {
120 $x = 0;
121 // for each column
122 for ($c = 0; $c < $this->barcode_array['num_cols']; ++$c) {
123 if ($this->barcode_array['bcode'][$r][$c] == 1) {
124 // draw a single barcode cell
125 $svg .= "\t\t".'<rect x="'.$x.'" y="'.$y.'" width="'.$w.'" height="'.$h.'" />'."\n";
126 }
127 $x += $w;
128 }
129 $y += $h;
130 }
131 $svg .= "\t".'</g>'."\n";
132 $svg .= '</svg>'."\n";
133 return $svg;
134 }
135
136 /**
137 * Return an HTML representation of barcode.
138 * @param $w (int) Width of a single rectangle element in pixels.
139 * @param $h (int) Height of a single rectangle element in pixels.
140 * @param $color (string) Foreground color for bar elements (background is transparent).
141 * @return string HTML code.
142 * @public
143 */
144 public function getBarcodeHTML($w=10, $h=10, $color='black') {
145 $html = '<div style="font-size:0;position:relative;width:'.($w * $this->barcode_array['num_cols']).'px;height:'.($h * $this->barcode_array['num_rows']).'px;">'."\n";
146 // print barcode elements
147 $y = 0;
148 // for each row
149 for ($r = 0; $r < $this->barcode_array['num_rows']; ++$r) {
150 $x = 0;
151 // for each column
152 for ($c = 0; $c < $this->barcode_array['num_cols']; ++$c) {
153 if ($this->barcode_array['bcode'][$r][$c] == 1) {
154 // draw a single barcode cell
155 $html .= '<div style="background-color:'.$color.';width:'.$w.'px;height:'.$h.'px;position:absolute;left:'.$x.'px;top:'.$y.'px;">&nbsp;</div>'."\n";
156 }
157 $x += $w;
158 }
159 $y += $h;
160 }
161 $html .= '</div>'."\n";
162 return $html;
163 }
164
165 /**
166 * Send a PNG image representation of barcode (requires GD or Imagick library).
167 * @param $w (int) Width of a single rectangle element in pixels.
168 * @param $h (int) Height of a single rectangle element in pixels.
169 * @param $color (array) RGB (0-255) foreground color for bar elements (background is transparent).
170 * @public
171 */
172 public function getBarcodePNG($w=3, $h=3, $color=array(0,0,0)) {
173 $data = $this->getBarcodePngData($w, $h, $color);
174 // send headers
175 header('Content-Type: image/png');
176 header('Cache-Control: public, must-revalidate, max-age=0'); // HTTP/1.1
177 header('Pragma: public');
178 header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past
179 header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
180 //header('Content-Length: '.strlen($data));
181 echo $data;
182
183 }
184
185 /**
186 * Return a PNG image representation of barcode (requires GD or Imagick library).
187 * @param $w (int) Width of a single rectangle element in pixels.
188 * @param $h (int) Height of a single rectangle element in pixels.
189 * @param $color (array) RGB (0-255) foreground color for bar elements (background is transparent).
190 * @return image or false in case of error.
191 * @public
192 */
193 public function getBarcodePngData($w=3, $h=3, $color=array(0,0,0)) {
194 // calculate image size
195 $width = ($this->barcode_array['num_cols'] * $w);
196 $height = ($this->barcode_array['num_rows'] * $h);
197 if (function_exists('imagecreate')) {
198 // GD library
199 $imagick = false;
200 $png = imagecreate($width, $height);
201 $bgcol = imagecolorallocate($png, 255, 255, 255);
202 imagecolortransparent($png, $bgcol);
203 $fgcol = imagecolorallocate($png, $color[0], $color[1], $color[2]);
204 } elseif (extension_loaded('imagick')) {
205 $imagick = true;
206 $bgcol = new imagickpixel('rgb(255,255,255');
207 $fgcol = new imagickpixel('rgb('.$color[0].','.$color[1].','.$color[2].')');
208 $png = new Imagick();
209 $png->newImage($width, $height, 'none', 'png');
210 $bar = new imagickdraw();
211 $bar->setfillcolor($fgcol);
212 } else {
213 return false;
214 }
215 // print barcode elements
216 $y = 0;
217 // for each row
218 for ($r = 0; $r < $this->barcode_array['num_rows']; ++$r) {
219 $x = 0;
220 // for each column
221 for ($c = 0; $c < $this->barcode_array['num_cols']; ++$c) {
222 if ($this->barcode_array['bcode'][$r][$c] == 1) {
223 // draw a single barcode cell
224 if ($imagick) {
225 $bar->rectangle($x, $y, ($x + $w - 1), ($y + $h - 1));
226 } else {
227 imagefilledrectangle($png, $x, $y, ($x + $w - 1), ($y + $h - 1), $fgcol);
228 }
229 }
230 $x += $w;
231 }
232 $y += $h;
233 }
234 if ($imagick) {
235 $png->drawimage($bar);
236 return $png;
237 } else {
238 ob_start();
239 imagepng($png);
240 $imagedata = ob_get_clean();
241 imagedestroy($png);
242 return $imagedata;
243 }
244 }
245
246 /**
247 * Set the barcode.
248 * @param $code (string) code to print
249 * @param $type (string) type of barcode: <ul><li>DATAMATRIX : Datamatrix (ISO/IEC 16022)</li><li>PDF417 : PDF417 (ISO/IEC 15438:2006)</li><li>PDF417,a,e,t,s,f,o0,o1,o2,o3,o4,o5,o6 : PDF417 with parameters: a = aspect ratio (width/height); e = error correction level (0-8); t = total number of macro segments; s = macro segment index (0-99998); f = file ID; o0 = File Name (text); o1 = Segment Count (numeric); o2 = Time Stamp (numeric); o3 = Sender (text); o4 = Addressee (text); o5 = File Size (numeric); o6 = Checksum (numeric). NOTES: Parameters t, s and f are required for a Macro Control Block, all other parametrs are optional. To use a comma character ',' on text options, replace it with the character 255: "\xff".</li><li>QRCODE : QRcode Low error correction</li><li>QRCODE,L : QRcode Low error correction</li><li>QRCODE,M : QRcode Medium error correction</li><li>QRCODE,Q : QRcode Better error correction</li><li>QRCODE,H : QR-CODE Best error correction</li><li>RAW: raw mode - comma-separad list of array rows</li><li>RAW2: raw mode - array rows are surrounded by square parenthesis.</li><li>TEST : Test matrix</li></ul>
250 * @return array
251 */
252 public function setBarcode($code, $type) {
253 $mode = explode(',', $type);
254 $qrtype = strtoupper($mode[0]);
255 switch ($qrtype) {
256 case 'DATAMATRIX': { // DATAMATRIX (ISO/IEC 16022)
257 require_once(dirname(__FILE__).'/include/barcodes/datamatrix.php');
258 $qrcode = new Datamatrix($code);
259 $this->barcode_array = $qrcode->getBarcodeArray();
260 $this->barcode_array['code'] = $code;
261 break;
262 }
263 case 'PDF417': { // PDF417 (ISO/IEC 15438:2006)
264 require_once(dirname(__FILE__).'/include/barcodes/pdf417.php');
265 if (!isset($mode[1]) OR ($mode[1] === '')) {
266 $aspectratio = 2; // default aspect ratio (width / height)
267 } else {
268 $aspectratio = floatval($mode[1]);
269 }
270 if (!isset($mode[2]) OR ($mode[2] === '')) {
271 $ecl = -1; // default error correction level (auto)
272 } else {
273 $ecl = intval($mode[2]);
274 }
275 // set macro block
276 $macro = array();
277 if (isset($mode[3]) AND ($mode[3] !== '') AND isset($mode[4]) AND ($mode[4] !== '') AND isset($mode[5]) AND ($mode[5] !== '')) {
278 $macro['segment_total'] = intval($mode[3]);
279 $macro['segment_index'] = intval($mode[4]);
280 $macro['file_id'] = strtr($mode[5], "\xff", ',');
281 for ($i = 0; $i < 7; ++$i) {
282 $o = $i + 6;
283 if (isset($mode[$o]) AND ($mode[$o] !== '')) {
284 // add option
285 $macro['option_'.$i] = strtr($mode[$o], "\xff", ',');
286 }
287 }
288 }
289 $qrcode = new PDF417($code, $ecl, $aspectratio, $macro);
290 $this->barcode_array = $qrcode->getBarcodeArray();
291 $this->barcode_array['code'] = $code;
292 break;
293 }
294 case 'QRCODE': { // QR-CODE
295 require_once(dirname(__FILE__).'/include/barcodes/qrcode.php');
296 if (!isset($mode[1]) OR (!in_array($mode[1],array('L','M','Q','H')))) {
297 $mode[1] = 'L'; // Ddefault: Low error correction
298 }
299 $qrcode = new QRcode($code, strtoupper($mode[1]));
300 $this->barcode_array = $qrcode->getBarcodeArray();
301 $this->barcode_array['code'] = $code;
302 break;
303 }
304 case 'RAW':
305 case 'RAW2': { // RAW MODE
306 // remove spaces
307 $code = preg_replace('/[\s]*/si', '', $code);
308 if (strlen($code) < 3) {
309 break;
310 }
311 if ($qrtype == 'RAW') {
312 // comma-separated rows
313 $rows = explode(',', $code);
314 } else { // RAW2
315 // rows enclosed in square parentheses
316 $code = substr($code, 1, -1);
317 $rows = explode('][', $code);
318 }
319 $this->barcode_array['num_rows'] = count($rows);
320 $this->barcode_array['num_cols'] = strlen($rows[0]);
321 $this->barcode_array['bcode'] = array();
322 foreach ($rows as $r) {
323 $this->barcode_array['bcode'][] = str_split($r, 1);
324 }
325 $this->barcode_array['code'] = $code;
326 break;
327 }
328 case 'TEST': { // TEST MODE
329 $this->barcode_array['num_rows'] = 5;
330 $this->barcode_array['num_cols'] = 15;
331 $this->barcode_array['bcode'] = array(
332 array(1,1,1,0,1,1,1,0,1,1,1,0,1,1,1),
333 array(0,1,0,0,1,0,0,0,1,0,0,0,0,1,0),
334 array(0,1,0,0,1,1,0,0,1,1,1,0,0,1,0),
335 array(0,1,0,0,1,0,0,0,0,0,1,0,0,1,0),
336 array(0,1,0,0,1,1,1,0,1,1,1,0,0,1,0));
337 $this->barcode_array['code'] = $code;
338 break;
339 }
340 default: {
341 $this->barcode_array = false;
342 }
343 }
344 }
345} // end of class
346
347//============================================================+
348// END OF FILE
349//============================================================+
diff --git a/inc/3rdparty/libraries/tcpdf/tcpdf_import.php b/inc/3rdparty/libraries/tcpdf/tcpdf_import.php
new file mode 100644
index 00000000..09d726ba
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/tcpdf_import.php
@@ -0,0 +1,104 @@
1<?php
2//============================================================+
3// File name : tcpdf_import.php
4// Version : 1.0.001
5// Begin : 2011-05-23
6// Last Update : 2013-09-17
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) 2011-2013 Nicola Asuni - Tecnick.com LTD
11//
12// This file is part of TCPDF software library.
13//
14// TCPDF is free software: you can redistribute it and/or modify it
15// under the terms of the GNU Lesser General Public License as
16// published by the Free Software Foundation, either version 3 of the
17// License, or (at your option) any later version.
18//
19// TCPDF is distributed in the hope that it will be useful, but
20// WITHOUT ANY WARRANTY; without even the implied warranty of
21// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22// See the GNU Lesser General Public License for more details.
23//
24// You should have received a copy of the License
25// along with TCPDF. If not, see
26// <http://www.tecnick.com/pagefiles/tcpdf/LICENSE.TXT>.
27//
28// See LICENSE.TXT file for more information.
29// -------------------------------------------------------------------
30//
31// Description : This is a PHP class extension of the TCPDF library to
32// import existing PDF documents.
33//
34//============================================================+
35
36/**
37 * @file
38 * !!! THIS CLASS IS UNDER DEVELOPMENT !!!
39 * This is a PHP class extension of the TCPDF (http://www.tcpdf.org) library to import existing PDF documents.<br>
40 * @package com.tecnick.tcpdf
41 * @author Nicola Asuni
42 * @version 1.0.001
43 */
44
45// include the TCPDF class
46require_once(dirname(__FILE__).'/tcpdf.php');
47// include PDF parser class
48require_once(dirname(__FILE__).'/tcpdf_parser.php');
49
50/**
51 * @class TCPDF_IMPORT
52 * !!! THIS CLASS IS UNDER DEVELOPMENT !!!
53 * PHP class extension of the TCPDF (http://www.tcpdf.org) library to import existing PDF documents.<br>
54 * @package com.tecnick.tcpdf
55 * @brief PHP class extension of the TCPDF library to import existing PDF documents.
56 * @version 1.0.001
57 * @author Nicola Asuni - info@tecnick.com
58 */
59class TCPDF_IMPORT extends TCPDF {
60
61 /**
62 * Import an existing PDF document
63 * @param $filename (string) Filename of the PDF document to import.
64 * @return true in case of success, false otherwise
65 * @public
66 * @since 1.0.000 (2011-05-24)
67 */
68 public function importPDF($filename) {
69 // load document
70 $rawdata = file_get_contents($filename);
71 if ($rawdata === false) {
72 $this->Error('Unable to get the content of the file: '.$filename);
73 }
74 // configuration parameters for parser
75 $cfg = array(
76 'die_for_errors' => false,
77 'ignore_filter_decoding_errors' => true,
78 'ignore_missing_filter_decoders' => true,
79 );
80 try {
81 // parse PDF data
82 $pdf = new TCPDF_PARSER($rawdata, $cfg);
83 } catch (Exception $e) {
84 die($e->getMessage());
85 }
86 // get the parsed data
87 $data = $pdf->getParsedData();
88 // release some memory
89 unset($rawdata);
90
91 // ...
92
93
94 print_r($data); // DEBUG
95
96
97 unset($pdf);
98 }
99
100} // END OF CLASS
101
102//============================================================+
103// END OF FILE
104//============================================================+
diff --git a/inc/3rdparty/libraries/tcpdf/tcpdf_parser.php b/inc/3rdparty/libraries/tcpdf/tcpdf_parser.php
new file mode 100644
index 00000000..0b2a7e14
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/tcpdf_parser.php
@@ -0,0 +1,811 @@
1<?php
2//============================================================+
3// File name : tcpdf_parser.php
4// Version : 1.0.014
5// Begin : 2011-05-23
6// Last Update : 2014-02-18
7// Author : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com
8// License : http://www.tecnick.com/pagefiles/tcpdf/LICENSE.TXT GNU-LGPLv3
9// -------------------------------------------------------------------
10// Copyright (C) 2011-2014 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 : This is a PHP class for parsing PDF documents.
32//
33//============================================================+
34
35/**
36 * @file
37 * This is a PHP class for parsing PDF documents.<br>
38 * @package com.tecnick.tcpdf
39 * @author Nicola Asuni
40 * @version 1.0.014
41 */
42
43// include class for decoding filters
44require_once(dirname(__FILE__).'/include/tcpdf_filters.php');
45
46/**
47 * @class TCPDF_PARSER
48 * This is a PHP class for parsing PDF documents.<br>
49 * @package com.tecnick.tcpdf
50 * @brief This is a PHP class for parsing PDF documents..
51 * @version 1.0.010
52 * @author Nicola Asuni - info@tecnick.com
53 */
54class TCPDF_PARSER {
55
56 /**
57 * Raw content of the PDF document.
58 * @private
59 */
60 private $pdfdata = '';
61
62 /**
63 * XREF data.
64 * @protected
65 */
66 protected $xref = array();
67
68 /**
69 * Array of PDF objects.
70 * @protected
71 */
72 protected $objects = array();
73
74 /**
75 * Class object for decoding filters.
76 * @private
77 */
78 private $FilterDecoders;
79
80 /**
81 * Array of configuration parameters.
82 * @private
83 */
84 private $cfg = array(
85 'die_for_errors' => false,
86 'ignore_filter_decoding_errors' => true,
87 'ignore_missing_filter_decoders' => true,
88 );
89
90// -----------------------------------------------------------------------------
91
92 /**
93 * Parse a PDF document an return an array of objects.
94 * @param $data (string) PDF data to parse.
95 * @param $cfg (array) Array of configuration parameters:
96 * 'die_for_errors' : if true termitate the program execution in case of error, otherwise thows an exception;
97 * 'ignore_filter_decoding_errors' : if true ignore filter decoding errors;
98 * 'ignore_missing_filter_decoders' : if true ignore missing filter decoding errors.
99 * @public
100 * @since 1.0.000 (2011-05-24)
101 */
102 public function __construct($data, $cfg=array()) {
103 if (empty($data)) {
104 $this->Error('Empty PDF data.');
105 }
106 // find the pdf header starting position
107 if (($trimpos = strpos($data, '%PDF-')) === FALSE) {
108 $this->Error('Invalid PDF data: missing %PDF header.');
109 }
110 // get PDF content string
111 $this->pdfdata = substr($data, $trimpos);
112 // get length
113 $pdflen = strlen($this->pdfdata);
114 // set configuration parameters
115 $this->setConfig($cfg);
116 // get xref and trailer data
117 $this->xref = $this->getXrefData();
118 // parse all document objects
119 $this->objects = array();
120 foreach ($this->xref['xref'] as $obj => $offset) {
121 if (!isset($this->objects[$obj]) AND ($offset > 0)) {
122 // decode objects with positive offset
123 $this->objects[$obj] = $this->getIndirectObject($obj, $offset, true);
124 }
125 }
126 // release some memory
127 unset($this->pdfdata);
128 $this->pdfdata = '';
129 }
130
131 /**
132 * Set the configuration parameters.
133 * @param $cfg (array) Array of configuration parameters:
134 * 'die_for_errors' : if true termitate the program execution in case of error, otherwise thows an exception;
135 * 'ignore_filter_decoding_errors' : if true ignore filter decoding errors;
136 * 'ignore_missing_filter_decoders' : if true ignore missing filter decoding errors.
137 * @public
138 */
139 protected function setConfig($cfg) {
140 if (isset($cfg['die_for_errors'])) {
141 $this->cfg['die_for_errors'] = !!$cfg['die_for_errors'];
142 }
143 if (isset($cfg['ignore_filter_decoding_errors'])) {
144 $this->cfg['ignore_filter_decoding_errors'] = !!$cfg['ignore_filter_decoding_errors'];
145 }
146 if (isset($cfg['ignore_missing_filter_decoders'])) {
147 $this->cfg['ignore_missing_filter_decoders'] = !!$cfg['ignore_missing_filter_decoders'];
148 }
149 }
150
151 /**
152 * Return an array of parsed PDF document objects.
153 * @return (array) Array of parsed PDF document objects.
154 * @public
155 * @since 1.0.000 (2011-06-26)
156 */
157 public function getParsedData() {
158 return array($this->xref, $this->objects);
159 }
160
161 /**
162 * Get Cross-Reference (xref) table and trailer data from PDF document data.
163 * @param $offset (int) xref offset (if know).
164 * @param $xref (array) previous xref array (if any).
165 * @return Array containing xref and trailer data.
166 * @protected
167 * @since 1.0.000 (2011-05-24)
168 */
169 protected function getXrefData($offset=0, $xref=array()) {
170 if ($offset == 0) {
171 // find last startxref
172 if (preg_match_all('/[\r\n]startxref[\s]*[\r\n]+([0-9]+)[\s]*[\r\n]+%%EOF/i', $this->pdfdata, $matches, PREG_SET_ORDER, $offset) == 0) {
173 $this->Error('Unable to find startxref');
174 }
175 $matches = array_pop($matches);
176 $startxref = $matches[1];
177 } elseif (strpos($this->pdfdata, 'xref', $offset) == $offset) {
178 // Already pointing at the xref table
179 $startxref = $offset;
180 } elseif (preg_match('/([0-9]+[\s][0-9]+[\s]obj)/i', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset)) {
181 // Cross-Reference Stream object
182 $startxref = $offset;
183 } elseif (preg_match('/[\r\n]startxref[\s]*[\r\n]+([0-9]+)[\s]*[\r\n]+%%EOF/i', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset)) {
184 // startxref found
185 $startxref = $matches[1][0];
186 } else {
187 $this->Error('Unable to find startxref');
188 }
189 // check xref position
190 if (strpos($this->pdfdata, 'xref', $startxref) == $startxref) {
191 // Cross-Reference
192 $xref = $this->decodeXref($startxref, $xref);
193 } else {
194 // Cross-Reference Stream
195 $xref = $this->decodeXrefStream($startxref, $xref);
196 }
197 if (empty($xref)) {
198 $this->Error('Unable to find xref');
199 }
200 return $xref;
201 }
202
203 /**
204 * Decode the Cross-Reference section
205 * @param $startxref (int) Offset at which the xref section starts (position of the 'xref' keyword).
206 * @param $xref (array) Previous xref array (if any).
207 * @return Array containing xref and trailer data.
208 * @protected
209 * @since 1.0.000 (2011-06-20)
210 */
211 protected function decodeXref($startxref, $xref=array()) {
212 $startxref += 4; // 4 is the lenght of the word 'xref'
213 // skip initial white space chars: \x00 null (NUL), \x09 horizontal tab (HT), \x0A line feed (LF), \x0C form feed (FF), \x0D carriage return (CR), \x20 space (SP)
214 $offset = $startxref + strspn($this->pdfdata, "\x00\x09\x0a\x0c\x0d\x20", $startxref);
215 // initialize object number
216 $obj_num = 0;
217 // search for cross-reference entries or subsection
218 while (preg_match('/([0-9]+)[\x20]([0-9]+)[\x20]?([nf]?)(\r\n|[\x20]?[\r\n])/', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) {
219 if ($matches[0][1] != $offset) {
220 // we are on another section
221 break;
222 }
223 $offset += strlen($matches[0][0]);
224 if ($matches[3][0] == 'n') {
225 // create unique object index: [object number]_[generation number]
226 $index = $obj_num.'_'.intval($matches[2][0]);
227 // check if object already exist
228 if (!isset($xref['xref'][$index])) {
229 // store object offset position
230 $xref['xref'][$index] = intval($matches[1][0]);
231 }
232 ++$obj_num;
233 } elseif ($matches[3][0] == 'f') {
234 ++$obj_num;
235 } else {
236 // object number (index)
237 $obj_num = intval($matches[1][0]);
238 }
239 }
240 // get trailer data
241 if (preg_match('/trailer[\s]*<<(.*)>>/isU', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) {
242 $trailer_data = $matches[1][0];
243 if (!isset($xref['trailer']) OR empty($xref['trailer'])) {
244 // get only the last updated version
245 $xref['trailer'] = array();
246 // parse trailer_data
247 if (preg_match('/Size[\s]+([0-9]+)/i', $trailer_data, $matches) > 0) {
248 $xref['trailer']['size'] = intval($matches[1]);
249 }
250 if (preg_match('/Root[\s]+([0-9]+)[\s]+([0-9]+)[\s]+R/i', $trailer_data, $matches) > 0) {
251 $xref['trailer']['root'] = intval($matches[1]).'_'.intval($matches[2]);
252 }
253 if (preg_match('/Encrypt[\s]+([0-9]+)[\s]+([0-9]+)[\s]+R/i', $trailer_data, $matches) > 0) {
254 $xref['trailer']['encrypt'] = intval($matches[1]).'_'.intval($matches[2]);
255 }
256 if (preg_match('/Info[\s]+([0-9]+)[\s]+([0-9]+)[\s]+R/i', $trailer_data, $matches) > 0) {
257 $xref['trailer']['info'] = intval($matches[1]).'_'.intval($matches[2]);
258 }
259 if (preg_match('/ID[\s]*[\[][\s]*[<]([^>]*)[>][\s]*[<]([^>]*)[>]/i', $trailer_data, $matches) > 0) {
260 $xref['trailer']['id'] = array();
261 $xref['trailer']['id'][0] = $matches[1];
262 $xref['trailer']['id'][1] = $matches[2];
263 }
264 }
265 if (preg_match('/Prev[\s]+([0-9]+)/i', $trailer_data, $matches) > 0) {
266 // get previous xref
267 $xref = $this->getXrefData(intval($matches[1]), $xref);
268 }
269 } else {
270 $this->Error('Unable to find trailer');
271 }
272 return $xref;
273 }
274
275 /**
276 * Decode the Cross-Reference Stream section
277 * @param $startxref (int) Offset at which the xref section starts.
278 * @param $xref (array) Previous xref array (if any).
279 * @return Array containing xref and trailer data.
280 * @protected
281 * @since 1.0.003 (2013-03-16)
282 */
283 protected function decodeXrefStream($startxref, $xref=array()) {
284 // try to read Cross-Reference Stream
285 $xrefobj = $this->getRawObject($startxref);
286 $xrefcrs = $this->getIndirectObject($xrefobj[1], $startxref, true);
287 if (!isset($xref['trailer']) OR empty($xref['trailer'])) {
288 // get only the last updated version
289 $xref['trailer'] = array();
290 $filltrailer = true;
291 } else {
292 $filltrailer = false;
293 }
294 if (!isset($xref['xref'])) {
295 $xref['xref'] = array();
296 }
297 $valid_crs = false;
298 $columns = 0;
299 $sarr = $xrefcrs[0][1];
300 foreach ($sarr as $k => $v) {
301 if (($v[0] == '/') AND ($v[1] == 'Type') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == '/') AND ($sarr[($k +1)][1] == 'XRef'))) {
302 $valid_crs = true;
303 } elseif (($v[0] == '/') AND ($v[1] == 'Index') AND (isset($sarr[($k +1)]))) {
304 // first object number in the subsection
305 $index_first = intval($sarr[($k +1)][1][0][1]);
306 // number of entries in the subsection
307 $index_entries = intval($sarr[($k +1)][1][1][1]);
308 } elseif (($v[0] == '/') AND ($v[1] == 'Prev') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == 'numeric'))) {
309 // get previous xref offset
310 $prevxref = intval($sarr[($k +1)][1]);
311 } elseif (($v[0] == '/') AND ($v[1] == 'W') AND (isset($sarr[($k +1)]))) {
312 // number of bytes (in the decoded stream) of the corresponding field
313 $wb = array();
314 $wb[0] = intval($sarr[($k +1)][1][0][1]);
315 $wb[1] = intval($sarr[($k +1)][1][1][1]);
316 $wb[2] = intval($sarr[($k +1)][1][2][1]);
317 } elseif (($v[0] == '/') AND ($v[1] == 'DecodeParms') AND (isset($sarr[($k +1)][1]))) {
318 $decpar = $sarr[($k +1)][1];
319 foreach ($decpar as $kdc => $vdc) {
320 if (($vdc[0] == '/') AND ($vdc[1] == 'Columns') AND (isset($decpar[($kdc +1)]) AND ($decpar[($kdc +1)][0] == 'numeric'))) {
321 $columns = intval($decpar[($kdc +1)][1]);
322 } elseif (($vdc[0] == '/') AND ($vdc[1] == 'Predictor') AND (isset($decpar[($kdc +1)]) AND ($decpar[($kdc +1)][0] == 'numeric'))) {
323 $predictor = intval($decpar[($kdc +1)][1]);
324 }
325 }
326 } elseif ($filltrailer) {
327 if (($v[0] == '/') AND ($v[1] == 'Size') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == 'numeric'))) {
328 $xref['trailer']['size'] = $sarr[($k +1)][1];
329 } elseif (($v[0] == '/') AND ($v[1] == 'Root') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == 'objref'))) {
330 $xref['trailer']['root'] = $sarr[($k +1)][1];
331 } elseif (($v[0] == '/') AND ($v[1] == 'Info') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == 'objref'))) {
332 $xref['trailer']['info'] = $sarr[($k +1)][1];
333 } elseif (($v[0] == '/') AND ($v[1] == 'Encrypt') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == 'objref'))) {
334 $xref['trailer']['encrypt'] = $sarr[($k +1)][1];
335 } elseif (($v[0] == '/') AND ($v[1] == 'ID') AND (isset($sarr[($k +1)]))) {
336 $xref['trailer']['id'] = array();
337 $xref['trailer']['id'][0] = $sarr[($k +1)][1][0][1];
338 $xref['trailer']['id'][1] = $sarr[($k +1)][1][1][1];
339 }
340 }
341 }
342 // decode data
343 if ($valid_crs AND isset($xrefcrs[1][3][0])) {
344 // number of bytes in a row
345 $rowlen = ($columns + 1);
346 // convert the stream into an array of integers
347 $sdata = unpack('C*', $xrefcrs[1][3][0]);
348 // split the rows
349 $sdata = array_chunk($sdata, $rowlen);
350 // initialize decoded array
351 $ddata = array();
352 // initialize first row with zeros
353 $prev_row = array_fill (0, $rowlen, 0);
354 // for each row apply PNG unpredictor
355 foreach ($sdata as $k => $row) {
356 // initialize new row
357 $ddata[$k] = array();
358 // get PNG predictor value
359 $predictor = (10 + $row[0]);
360 // for each byte on the row
361 for ($i=1; $i<=$columns; ++$i) {
362 // new index
363 $j = ($i - 1);
364 $row_up = $prev_row[$j];
365 if ($i == 1) {
366 $row_left = 0;
367 $row_upleft = 0;
368 } else {
369 $row_left = $row[($i - 1)];
370 $row_upleft = $prev_row[($j - 1)];
371 }
372 switch ($predictor) {
373 case 10: { // PNG prediction (on encoding, PNG None on all rows)
374 $ddata[$k][$j] = $row[$i];
375 break;
376 }
377 case 11: { // PNG prediction (on encoding, PNG Sub on all rows)
378 $ddata[$k][$j] = (($row[$i] + $row_left) & 0xff);
379 break;
380 }
381 case 12: { // PNG prediction (on encoding, PNG Up on all rows)
382 $ddata[$k][$j] = (($row[$i] + $row_up) & 0xff);
383 break;
384 }
385 case 13: { // PNG prediction (on encoding, PNG Average on all rows)
386 $ddata[$k][$j] = (($row[$i] + (($row_left + $row_up) / 2)) & 0xff);
387 break;
388 }
389 case 14: { // PNG prediction (on encoding, PNG Paeth on all rows)
390 // initial estimate
391 $p = ($row_left + $row_up - $row_upleft);
392 // distances
393 $pa = abs($p - $row_left);
394 $pb = abs($p - $row_up);
395 $pc = abs($p - $row_upleft);
396 $pmin = min($pa, $pb, $pc);
397 // return minumum distance
398 switch ($pmin) {
399 case $pa: {
400 $ddata[$k][$j] = (($row[$i] + $row_left) & 0xff);
401 break;
402 }
403 case $pb: {
404 $ddata[$k][$j] = (($row[$i] + $row_up) & 0xff);
405 break;
406 }
407 case $pc: {
408 $ddata[$k][$j] = (($row[$i] + $row_upleft) & 0xff);
409 break;
410 }
411 }
412 break;
413 }
414 default: { // PNG prediction (on encoding, PNG optimum)
415 $this->Error('Unknown PNG predictor');
416 break;
417 }
418 }
419 }
420 $prev_row = $ddata[$k];
421 } // end for each row
422 // complete decoding
423 $sdata = array();
424 // for every row
425 foreach ($ddata as $k => $row) {
426 // initialize new row
427 $sdata[$k] = array(0, 0, 0);
428 if ($wb[0] == 0) {
429 // default type field
430 $sdata[$k][0] = 1;
431 }
432 $i = 0; // count bytes in the row
433 // for every column
434 for ($c = 0; $c < 3; ++$c) {
435 // for every byte on the column
436 for ($b = 0; $b < $wb[$c]; ++$b) {
437 if (isset($row[$i])) {
438 $sdata[$k][$c] += ($row[$i] << (($wb[$c] - 1 - $b) * 8));
439 }
440 ++$i;
441 }
442 }
443 }
444 $ddata = array();
445 // fill xref
446 if (isset($index_first)) {
447 $obj_num = $index_first;
448 } else {
449 $obj_num = 0;
450 }
451 foreach ($sdata as $k => $row) {
452 switch ($row[0]) {
453 case 0: { // (f) linked list of free objects
454 break;
455 }
456 case 1: { // (n) objects that are in use but are not compressed
457 // create unique object index: [object number]_[generation number]
458 $index = $obj_num.'_'.$row[2];
459 // check if object already exist
460 if (!isset($xref['xref'][$index])) {
461 // store object offset position
462 $xref['xref'][$index] = $row[1];
463 }
464 break;
465 }
466 case 2: { // compressed objects
467 // $row[1] = object number of the object stream in which this object is stored
468 // $row[2] = index of this object within the object stream
469 $index = $row[1].'_0_'.$row[2];
470 $xref['xref'][$index] = -1;
471 break;
472 }
473 default: { // null objects
474 break;
475 }
476 }
477 ++$obj_num;
478 }
479 } // end decoding data
480 if (isset($prevxref)) {
481 // get previous xref
482 $xref = $this->getXrefData($prevxref, $xref);
483 }
484 return $xref;
485 }
486
487 /**
488 * Get object type, raw value and offset to next object
489 * @param $offset (int) Object offset.
490 * @return array containing object type, raw value and offset to next object
491 * @protected
492 * @since 1.0.000 (2011-06-20)
493 */
494 protected function getRawObject($offset=0) {
495 $objtype = ''; // object type to be returned
496 $objval = ''; // object value to be returned
497 // skip initial white space chars: \x00 null (NUL), \x09 horizontal tab (HT), \x0A line feed (LF), \x0C form feed (FF), \x0D carriage return (CR), \x20 space (SP)
498 $offset += strspn($this->pdfdata, "\x00\x09\x0a\x0c\x0d\x20", $offset);
499 // get first char
500 $char = $this->pdfdata[$offset];
501 // get object type
502 switch ($char) {
503 case '%': { // \x25 PERCENT SIGN
504 // skip comment and search for next token
505 $next = strcspn($this->pdfdata, "\r\n", $offset);
506 if ($next > 0) {
507 $offset += $next;
508 return $this->getRawObject($offset);
509 }
510 break;
511 }
512 case '/': { // \x2F SOLIDUS
513 // name object
514 $objtype = $char;
515 ++$offset;
516 if (preg_match('/^([^\x00\x09\x0a\x0c\x0d\x20\s\x28\x29\x3c\x3e\x5b\x5d\x7b\x7d\x2f\x25]+)/', substr($this->pdfdata, $offset, 256), $matches) == 1) {
517 $objval = $matches[1]; // unescaped value
518 $offset += strlen($objval);
519 }
520 break;
521 }
522 case '(': // \x28 LEFT PARENTHESIS
523 case ')': { // \x29 RIGHT PARENTHESIS
524 // literal string object
525 $objtype = $char;
526 ++$offset;
527 $strpos = $offset;
528 if ($char == '(') {
529 $open_bracket = 1;
530 while ($open_bracket > 0) {
531 if (!isset($this->pdfdata{$strpos})) {
532 break;
533 }
534 $ch = $this->pdfdata{$strpos};
535 switch ($ch) {
536 case '\\': { // REVERSE SOLIDUS (5Ch) (Backslash)
537 // skip next character
538 ++$strpos;
539 break;
540 }
541 case '(': { // LEFT PARENHESIS (28h)
542 ++$open_bracket;
543 break;
544 }
545 case ')': { // RIGHT PARENTHESIS (29h)
546 --$open_bracket;
547 break;
548 }
549 }
550 ++$strpos;
551 }
552 $objval = substr($this->pdfdata, $offset, ($strpos - $offset - 1));
553 $offset = $strpos;
554 }
555 break;
556 }
557 case '[': // \x5B LEFT SQUARE BRACKET
558 case ']': { // \x5D RIGHT SQUARE BRACKET
559 // array object
560 $objtype = $char;
561 ++$offset;
562 if ($char == '[') {
563 // get array content
564 $objval = array();
565 do {
566 // get element
567 $element = $this->getRawObject($offset);
568 $offset = $element[2];
569 $objval[] = $element;
570 } while ($element[0] != ']');
571 // remove closing delimiter
572 array_pop($objval);
573 }
574 break;
575 }
576 case '<': // \x3C LESS-THAN SIGN
577 case '>': { // \x3E GREATER-THAN SIGN
578 if (isset($this->pdfdata{($offset + 1)}) AND ($this->pdfdata{($offset + 1)} == $char)) {
579 // dictionary object
580 $objtype = $char.$char;
581 $offset += 2;
582 if ($char == '<') {
583 // get array content
584 $objval = array();
585 do {
586 // get element
587 $element = $this->getRawObject($offset);
588 $offset = $element[2];
589 $objval[] = $element;
590 } while ($element[0] != '>>');
591 // remove closing delimiter
592 array_pop($objval);
593 }
594 } else {
595 // hexadecimal string object
596 $objtype = $char;
597 ++$offset;
598 if (($char == '<') AND (preg_match('/^([0-9A-Fa-f\x09\x0a\x0c\x0d\x20]+)>/iU', substr($this->pdfdata, $offset), $matches) == 1)) {
599 // remove white space characters
600 $objval = strtr($matches[1], "\x09\x0a\x0c\x0d\x20", '');
601 $offset += strlen($matches[0]);
602 } elseif (($endpos = strpos($this->pdfdata, '>', $offset)) !== FALSE) {
603 $offset = $endpos + 1;
604 }
605 }
606 break;
607 }
608 default: {
609 if (substr($this->pdfdata, $offset, 6) == 'endobj') {
610 // indirect object
611 $objtype = 'endobj';
612 $offset += 6;
613 } elseif (substr($this->pdfdata, $offset, 4) == 'null') {
614 // null object
615 $objtype = 'null';
616 $offset += 4;
617 $objval = 'null';
618 } elseif (substr($this->pdfdata, $offset, 4) == 'true') {
619 // boolean true object
620 $objtype = 'boolean';
621 $offset += 4;
622 $objval = 'true';
623 } elseif (substr($this->pdfdata, $offset, 5) == 'false') {
624 // boolean false object
625 $objtype = 'boolean';
626 $offset += 5;
627 $objval = 'false';
628 } elseif (substr($this->pdfdata, $offset, 6) == 'stream') {
629 // start stream object
630 $objtype = 'stream';
631 $offset += 6;
632 if (preg_match('/^([\r]?[\n])/isU', substr($this->pdfdata, $offset), $matches) == 1) {
633 $offset += strlen($matches[0]);
634 if (preg_match('/(endstream)[\x09\x0a\x0c\x0d\x20]/isU', substr($this->pdfdata, $offset), $matches, PREG_OFFSET_CAPTURE) == 1) {
635 $objval = substr($this->pdfdata, $offset, $matches[0][1]);
636 $offset += $matches[1][1];
637 }
638 }
639 } elseif (substr($this->pdfdata, $offset, 9) == 'endstream') {
640 // end stream object
641 $objtype = 'endstream';
642 $offset += 9;
643 } elseif (preg_match('/^([0-9]+)[\s]+([0-9]+)[\s]+R/iU', substr($this->pdfdata, $offset, 33), $matches) == 1) {
644 // indirect object reference
645 $objtype = 'objref';
646 $offset += strlen($matches[0]);
647 $objval = intval($matches[1]).'_'.intval($matches[2]);
648 } elseif (preg_match('/^([0-9]+)[\s]+([0-9]+)[\s]+obj/iU', substr($this->pdfdata, $offset, 33), $matches) == 1) {
649 // object start
650 $objtype = 'obj';
651 $objval = intval($matches[1]).'_'.intval($matches[2]);
652 $offset += strlen ($matches[0]);
653 } elseif (($numlen = strspn($this->pdfdata, '+-.0123456789', $offset)) > 0) {
654 // numeric object
655 $objtype = 'numeric';
656 $objval = substr($this->pdfdata, $offset, $numlen);
657 $offset += $numlen;
658 }
659 break;
660 }
661 }
662 return array($objtype, $objval, $offset);
663 }
664
665 /**
666 * Get content of indirect object.
667 * @param $obj_ref (string) Object number and generation number separated by underscore character.
668 * @param $offset (int) Object offset.
669 * @param $decoding (boolean) If true decode streams.
670 * @return array containing object data.
671 * @protected
672 * @since 1.0.000 (2011-05-24)
673 */
674 protected function getIndirectObject($obj_ref, $offset=0, $decoding=true) {
675 $obj = explode('_', $obj_ref);
676 if (($obj === false) OR (count($obj) != 2)) {
677 $this->Error('Invalid object reference: '.$obj);
678 return;
679 }
680 $objref = $obj[0].' '.$obj[1].' obj';
681 // ignore leading zeros
682 $offset += strspn($this->pdfdata, '0', $offset);
683 if (strpos($this->pdfdata, $objref, $offset) != $offset) {
684 // an indirect reference to an undefined object shall be considered a reference to the null object
685 return array('null', 'null', $offset);
686 }
687 // starting position of object content
688 $offset += strlen($objref);
689 // get array of object content
690 $objdata = array();
691 $i = 0; // object main index
692 do {
693 // get element
694 $element = $this->getRawObject($offset);
695 $offset = $element[2];
696 // decode stream using stream's dictionary information
697 if ($decoding AND ($element[0] == 'stream') AND (isset($objdata[($i - 1)][0])) AND ($objdata[($i - 1)][0] == '<<')) {
698 $element[3] = $this->decodeStream($objdata[($i - 1)][1], $element[1]);
699 }
700 $objdata[$i] = $element;
701 ++$i;
702 } while ($element[0] != 'endobj');
703 // remove closing delimiter
704 array_pop($objdata);
705 // return raw object content
706 return $objdata;
707 }
708
709 /**
710 * Get the content of object, resolving indect object reference if necessary.
711 * @param $obj (string) Object value.
712 * @return array containing object data.
713 * @protected
714 * @since 1.0.000 (2011-06-26)
715 */
716 protected function getObjectVal($obj) {
717 if ($obj[0] == 'objref') {
718 // reference to indirect object
719 if (isset($this->objects[$obj[1]])) {
720 // this object has been already parsed
721 return $this->objects[$obj[1]];
722 } elseif (isset($this->xref[$obj[1]])) {
723 // parse new object
724 $this->objects[$obj[1]] = $this->getIndirectObject($obj[1], $this->xref[$obj[1]], false);
725 return $this->objects[$obj[1]];
726 }
727 }
728 return $obj;
729 }
730
731 /**
732 * Decode the specified stream.
733 * @param $sdic (array) Stream's dictionary array.
734 * @param $stream (string) Stream to decode.
735 * @return array containing decoded stream data and remaining filters.
736 * @protected
737 * @since 1.0.000 (2011-06-22)
738 */
739 protected function decodeStream($sdic, $stream) {
740 // get stream lenght and filters
741 $slength = strlen($stream);
742 if ($slength <= 0) {
743 return array('', array());
744 }
745 $filters = array();
746 foreach ($sdic as $k => $v) {
747 if ($v[0] == '/') {
748 if (($v[1] == 'Length') AND (isset($sdic[($k + 1)])) AND ($sdic[($k + 1)][0] == 'numeric')) {
749 // get declared stream lenght
750 $declength = intval($sdic[($k + 1)][1]);
751 if ($declength < $slength) {
752 $stream = substr($stream, 0, $declength);
753 $slength = $declength;
754 }
755 } elseif (($v[1] == 'Filter') AND (isset($sdic[($k + 1)]))) {
756 // resolve indirect object
757 $objval = $this->getObjectVal($sdic[($k + 1)]);
758 if ($objval[0] == '/') {
759 // single filter
760 $filters[] = $objval[1];
761 } elseif ($objval[0] == '[') {
762 // array of filters
763 foreach ($objval[1] as $flt) {
764 if ($flt[0] == '/') {
765 $filters[] = $flt[1];
766 }
767 }
768 }
769 }
770 }
771 }
772 // decode the stream
773 $remaining_filters = array();
774 foreach ($filters as $filter) {
775 if (in_array($filter, TCPDF_FILTERS::getAvailableFilters())) {
776 try {
777 $stream = TCPDF_FILTERS::decodeFilter($filter, $stream);
778 } catch (Exception $e) {
779 $emsg = $e->getMessage();
780 if ((($emsg[0] == '~') AND !$this->cfg['ignore_missing_filter_decoders'])
781 OR (($emsg[0] != '~') AND !$this->cfg['ignore_filter_decoding_errors'])) {
782 $this->Error($e->getMessage());
783 }
784 }
785 } else {
786 // add missing filter to array
787 $remaining_filters[] = $filter;
788 }
789 }
790 return array($stream, $remaining_filters);
791 }
792
793 /**
794 * Throw an exception or print an error message and die if the K_TCPDF_PARSER_THROW_EXCEPTION_ERROR constant is set to true.
795 * @param $msg (string) The error message
796 * @public
797 * @since 1.0.000 (2011-05-23)
798 */
799 public function Error($msg) {
800 if ($this->cfg['die_for_errors']) {
801 die('<strong>TCPDF_PARSER ERROR: </strong>'.$msg);
802 } else {
803 throw new Exception('TCPDF_PARSER ERROR: '.$msg);
804 }
805 }
806
807} // END OF TCPDF_PARSER CLASS
808
809//============================================================+
810// END OF FILE
811//============================================================+
diff --git a/inc/3rdparty/libraries/tcpdf/tools/.htaccess b/inc/3rdparty/libraries/tcpdf/tools/.htaccess
new file mode 100644
index 00000000..8d2f2563
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/tools/.htaccess
@@ -0,0 +1 @@
deny from all
diff --git a/inc/3rdparty/libraries/tcpdf/tools/convert_fonts_examples.txt b/inc/3rdparty/libraries/tcpdf/tools/convert_fonts_examples.txt
new file mode 100644
index 00000000..d5f8a4ea
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/tools/convert_fonts_examples.txt
@@ -0,0 +1,28 @@
1./tcpdf_addfont.php -b -t Type1 -f 4 -e symbol -i pdfasymbol.pfb
2./tcpdf_addfont.php -b -t Type1 -f 4 -i pdfazapfdingbats.pfb
3./tcpdf_addfont.php -b -t Type1 -f 32 -e cp1252 -i pdfatimes.pfb,pdfatimesb.pfb,pdfahelvetica.pfb,pdfahelveticab.pfb
4./tcpdf_addfont.php -b -t Type1 -f 33 -e cp1252 -i pdfacourier.pfb,pdfacourierb.pfb
5./tcpdf_addfont.php -b -t Type1 -f 96 -e cp1252 -i pdfahelveticabi.pfb,pdfahelveticai.pfb,pdfatimesi.pfb,pdfatimesbi.pfb
6./tcpdf_addfont.php -b -t Type1 -f 97 -e cp1252 -i pdfacourieri.pfb,pdfacourierbi.pfb
7
8
9./tcpdf_addfont.php -b -t TrueTypeUnicode -f 32 -i DejaVuSans.ttf,DejaVuSans-Bold.ttf,DejaVuSansCondensed.ttf,DejaVuSansCondensed-Bold.ttf,DejaVuSans-ExtraLight.ttf,DejaVuSerif.ttf,DejaVuSerif-Bold.ttf,DejaVuSerifCondensed.ttf,DejaVuSerifCondensed-Bold.ttf
10./tcpdf_addfont.php -b -t TrueTypeUnicode -f 33 -i DejaVuSansMono.ttf,DejaVuSansMono-Bold.ttf
11./tcpdf_addfont.php -b -t TrueTypeUnicode -f 96 -i DejaVuSans-BoldOblique.ttf,DejaVuSansCondensed-BoldOblique.ttf,DejaVuSansCondensed-Oblique.ttf,DejaVuSerifCondensed-BoldItalic.ttf,DejaVuSerifCondensed-Italic.ttf,DejaVuSerif-Italic.ttf,DejaVuSerif-BoldItalic.ttf,DejaVuSans-Oblique.ttf
12./tcpdf_addfont.php -b -t TrueTypeUnicode -f 97 -i DejaVuSansMono-BoldOblique.ttf,DejaVuSansMono-Oblique.ttf
13
14
15
16./tcpdf_addfont.php -b -t TrueTypeUnicode -f 32 -i FreeSans.ttf,FreeSansBold.ttf,FreeSerif.ttf,FreeSerifBold.ttf
17./tcpdf_addfont.php -b -t TrueTypeUnicode -f 33 -i FreeMono.ttf,FreeMonoBold.ttf
18./tcpdf_addfont.php -b -t TrueTypeUnicode -f 96 -i FreeSansBoldOblique.ttf,FreeSansOblique.ttf,FreeSerifBoldItalic.ttf,FreeSerifItalic.ttf
19./tcpdf_addfont.php -b -t TrueTypeUnicode -f 97 -i FreeMonoBoldOblique.ttf,FreeMonoOblique.ttf
20
21
22./tcpdf_addfont.php -b -t TrueTypeUnicode -i aeAlArabiya.ttf,aeFurat.ttf
23
24
25./tcpdf_addfont.php -b -t CID0JP -f 32 -i cid0jp.ttf
26./tcpdf_addfont.php -b -t CID0KR -f 32 -i cid0kr.ttf
27./tcpdf_addfont.php -b -t CID0CS -f 32 -i cid0cs.ttf
28./tcpdf_addfont.php -b -t CID0CT -f 32 -i cid0ct.ttf
diff --git a/inc/3rdparty/libraries/tcpdf/tools/tcpdf_addfont.php b/inc/3rdparty/libraries/tcpdf/tools/tcpdf_addfont.php
new file mode 100755
index 00000000..c0b258ec
--- /dev/null
+++ b/inc/3rdparty/libraries/tcpdf/tools/tcpdf_addfont.php
@@ -0,0 +1,269 @@
1#!/usr/bin/php -q
2<?php
3//============================================================+
4// File name : tcpdf_addfont.php
5// Version : 1.0.002
6// Begin : 2013-05-13
7// Last Update : 2013-08-05
8// Authors : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com
9// Remi Collet
10// License : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html)
11// -------------------------------------------------------------------
12// Copyright (C) 2011-2013 Nicola Asuni - Tecnick.com LTD
13//
14// This file is part of TCPDF software library.
15//
16// TCPDF is free software: you can redistribute it and/or modify it
17// under the terms of the GNU Lesser General Public License as
18// published by the Free Software Foundation, either version 3 of the
19// License, or (at your option) any later version.
20//
21// TCPDF is distributed in the hope that it will be useful, but
22// WITHOUT ANY WARRANTY; without even the implied warranty of
23// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
24// See the GNU Lesser General Public License for more details.
25//
26// You should have received a copy of the License
27// along with TCPDF. If not, see
28// <http://www.tecnick.com/pagefiles/tcpdf/LICENSE.TXT>.
29//
30// See LICENSE.TXT file for more information.
31// -------------------------------------------------------------------
32//
33// Description : This is a command line script to generate TCPDF fonts.
34//
35//============================================================+
36
37/**
38 * @file
39 * This is a command line script to generate TCPDF fonts.<br>
40 * @package com.tecnick.tcpdf
41 * @version 1.0.000
42 */
43
44if (php_sapi_name() != 'cli') {
45 echo 'You need to run this command from console.';
46 exit(1);
47}
48
49$tcpdf_include_dirs = array(realpath(dirname(__FILE__).'/../tcpdf.php'), '/usr/share/php/tcpdf/tcpdf.php', '/usr/share/tcpdf/tcpdf.php', '/usr/share/php-tcpdf/tcpdf.php', '/var/www/tcpdf/tcpdf.php', '/var/www/html/tcpdf/tcpdf.php', '/usr/local/apache2/htdocs/tcpdf/tcpdf.php');
50foreach ($tcpdf_include_dirs as $tcpdf_include_path) {
51 if (@file_exists($tcpdf_include_path)) {
52 require_once($tcpdf_include_path);
53 break;
54 }
55}
56
57/**
58 * Display help guide for this command.
59 */
60function showHelp() {
61 $help = <<<EOD
62tcpdf_addfont - command line tool to convert fonts for the TCPDF library.
63
64Usage: tcpdf_addfont.php [ options ] -i fontfile[,fontfile]...
65
66Options:
67
68 -t
69 --type Font type. Leave empty for autodetect mode.
70 Valid values are:
71 TrueTypeUnicode
72 TrueType
73 Type1
74 CID0JP = CID-0 Japanese
75 CID0KR = CID-0 Korean
76 CID0CS = CID-0 Chinese Simplified
77 CID0CT = CID-0 Chinese Traditional
78
79 -e
80 --enc Name of the encoding table to use. Leave empty for
81 default mode. Omit this parameter for TrueType Unicode
82 and symbolic fonts like Symbol or ZapfDingBats.
83
84 -f
85 --flags Unsigned 32-bit integer containing flags specifying
86 various characteristics of the font (PDF32000:2008 -
87 9.8.2 Font Descriptor Flags): +1 for fixed font; +4 for
88 symbol or +32 for non-symbol; +64 for italic. Fixed and
89 Italic mode are generally autodetected so you have to
90 set it to 32 = non-symbolic font (default) or 4 =
91 symbolic font.
92
93 -o
94 --outpath Output path for generated font files (must be writeable
95 by the web server). Leave empty for default font folder.
96
97 -p
98 --platid Platform ID for CMAP table to extract (when building a
99 Unicode font for Windows this value should be 3, for
100 Macintosh should be 1).
101
102 -n
103 --encid Encoding ID for CMAP table to extract (when building a
104 Unicode font for Windows this value should be 1, for
105 Macintosh should be 0). When Platform ID is 3, legal
106 values for Encoding ID are: 0=Symbol, 1=Unicode,
107 2=ShiftJIS, 3=PRC, 4=Big5, 5=Wansung, 6=Johab,
108 7=Reserved, 8=Reserved, 9=Reserved, 10=UCS-4.
109
110 -b
111 --addcbbox Includes the character bounding box information on the
112 php font file.
113
114 -l
115 --link Link to system font instead of copying the font data #
116 (not transportable) - Note: do not work with Type1 fonts.
117
118 -i
119 --fonts Comma-separated list of input font files.
120
121 -h
122 --help Display this help and exit.
123EOD;
124 echo $help."\n\n";
125 exit(0);
126}
127
128// remove the name of the executing script
129array_shift($argv);
130
131// no options chosen
132if (!is_array($argv)) {
133 showHelp();
134}
135
136// initialize the array of options
137$options = array('type'=>'', 'enc'=>'', 'flags'=>32, 'outpath'=>K_PATH_FONTS, 'platid'=>3, 'encid'=>1, 'addcbbox'=>false, 'link'=>false);
138
139// short input options
140$sopt = '';
141$sopt .= 't:';
142$sopt .= 'e:';
143$sopt .= 'f:';
144$sopt .= 'o:';
145$sopt .= 'p:';
146$sopt .= 'n:';
147$sopt .= 'b';
148$sopt .= 'l';
149$sopt .= 'i:';
150$sopt .= 'h';
151
152// long input options
153$lopt = array();
154$lopt[] = 'type:';
155$lopt[] = 'enc:';
156$lopt[] = 'flags:';
157$lopt[] = 'outpath:';
158$lopt[] = 'platid:';
159$lopt[] = 'encid:';
160$lopt[] = 'addcbbox';
161$lopt[] = 'link';
162$lopt[] = 'fonts:';
163$lopt[] = 'help';
164
165// parse input options
166$inopt = getopt($sopt, $lopt);
167
168// import options (with some sanitization)
169foreach ($inopt as $opt => $val) {
170 switch ($opt) {
171 case 't':
172 case 'type': {
173 if (in_array($val, array('TrueTypeUnicode', 'TrueType', 'Type1', 'CID0JP', 'CID0KR', 'CID0CS', 'CID0CT'))) {
174 $options['type'] = $val;
175 }
176 break;
177 }
178 case 'e':
179 case 'enc': {
180 $options['enc'] = $val;
181 break;
182 }
183 case 'f':
184 case 'flags': {
185 $options['flags'] = intval($val);
186 break;
187 }
188 case 'o':
189 case 'outpath': {
190 $options['outpath'] = realpath($val);
191 if (substr($options['outpath'], -1) != '/') {
192 $options['outpath'] .= '/';
193 }
194 break;
195 }
196 case 'p':
197 case 'platid': {
198 $options['platid'] = min(max(1, intval($val)), 3);
199 break;
200 }
201 case 'n':
202 case 'encid': {
203 $options['encid'] = min(max(0, intval($val)), 10);
204 break;
205 }
206 case 'b':
207 case 'addcbbox': {
208 $options['addcbbox'] = true;
209 break;
210 }
211 case 'l':
212 case 'link': {
213 $options['link'] = true;
214 break;
215 }
216 case 'i':
217 case 'fonts': {
218 $options['fonts'] = explode(',', $val);
219 break;
220 }
221 case 'h':
222 case 'help':
223 default: {
224 showHelp();
225 break;
226 }
227 } // end of switch
228} // end of while loop
229
230if (empty($options['fonts'])) {
231 echo "ERROR: missing input fonts (try --help for usage)\n\n";
232 exit(2);
233}
234
235// check the output path
236if (!is_dir($options['outpath']) OR !is_writable($options['outpath'])) {
237 echo "ERROR: Can't write to ".$options['outpath']."\n\n";
238 exit(3);
239}
240
241echo "\n>>> Converting fonts for TCPDF:\n";
242
243echo '*** Output dir set to '.$options['outpath']."\n";
244
245// check if there are conversion errors
246$errors = false;
247
248foreach ($options['fonts'] as $font) {
249 $fontfile = realpath($font);
250 $fontname = TCPDF_FONTS::addTTFfont($fontfile, $options['type'], $options['enc'], $options['flags'], $options['outpath'], $options['platid'], $options['encid'], $options['addcbbox'], $options['link']);
251 if ($fontname === false) {
252 $errors = true;
253 echo "--- ERROR: can't add ".$font."\n";
254 } else {
255 echo "+++ OK : ".$fontfile.' added as '.$fontname."\n";
256 }
257}
258
259if ($errors) {
260 echo "--- Process completed with ERRORS!\n\n";
261 exit(4);
262}
263
264echo ">>> Process successfully completed!\n\n";
265exit(0);
266
267//============================================================+
268// END OF FILE
269//============================================================+
diff --git a/inc/3rdparty/makefulltextfeed.php b/inc/3rdparty/makefulltextfeed.php
index a081f88b..27a62d73 100755
--- a/inc/3rdparty/makefulltextfeed.php
+++ b/inc/3rdparty/makefulltextfeed.php
@@ -31,6 +31,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
31//error_reporting(E_ALL ^ E_NOTICE); 31//error_reporting(E_ALL ^ E_NOTICE);
32ini_set("display_errors", 1); 32ini_set("display_errors", 1);
33@set_time_limit(120); 33@set_time_limit(120);
34libxml_use_internal_errors(true);
35
34 36
35// Deal with magic quotes 37// Deal with magic quotes
36if (get_magic_quotes_gpc()) { 38if (get_magic_quotes_gpc()) {
diff --git a/inc/3rdparty/site_config/standard/gist.github.com.txt b/inc/3rdparty/site_config/standard/gist.github.com.txt
index 90207862..f11b7b42 100755
--- a/inc/3rdparty/site_config/standard/gist.github.com.txt
+++ b/inc/3rdparty/site_config/standard/gist.github.com.txt
@@ -1,6 +1,4 @@
1body: //div[@class="highlight"]/pre
2 1
3prune: no 2title: //div[contains(@class,'gist-description')]
4tidy: no 3body: //div[contains(@class,'blob-wrapper')]
5 4test_url: https://gist.github.com/staltz/868e7e9bc2a7b8c1f754
6test_url: https://gist.github.com/1258908 \ No newline at end of file
diff --git a/inc/3rdparty/site_config/standard/jungle-world.com.txt b/inc/3rdparty/site_config/standard/jungle-world.com.txt
new file mode 100644
index 00000000..61e0087f
--- /dev/null
+++ b/inc/3rdparty/site_config/standard/jungle-world.com.txt
@@ -0,0 +1,3 @@
1title: //h1
2body: //div[contains(@class,'story')]
3test_url: http://jungle-world.com/artikel/2015/02/51207.html
diff --git a/inc/3rdparty/site_config/standard/toolinux.com.txt b/inc/3rdparty/site_config/standard/toolinux.com.txt
new file mode 100755
index 00000000..3f1a8405
--- /dev/null
+++ b/inc/3rdparty/site_config/standard/toolinux.com.txt
@@ -0,0 +1,5 @@
1title: //h2[contains(@class,'news')]
2body: //div[contains(@class,'articleContent')]
3date: substring-after(//div[@class = 'SupaDate']/text(), 'le')
4
5test_url: http://www.toolinux.com/Wi-Fi-Linksys-WRT-la-legende-de