diff options
Diffstat (limited to 'inc/3rdparty/libraries/mpdf/classes')
-rw-r--r-- | inc/3rdparty/libraries/mpdf/classes/barcode.php | 1965 | ||||
-rw-r--r-- | inc/3rdparty/libraries/mpdf/classes/bmp.php | 248 | ||||
-rw-r--r-- | inc/3rdparty/libraries/mpdf/classes/cssmgr.php | 1566 | ||||
-rw-r--r-- | inc/3rdparty/libraries/mpdf/classes/directw.php | 408 | ||||
-rw-r--r-- | inc/3rdparty/libraries/mpdf/classes/form.php | 1498 | ||||
-rw-r--r-- | inc/3rdparty/libraries/mpdf/classes/gif.php | 700 | ||||
-rw-r--r-- | inc/3rdparty/libraries/mpdf/classes/grad.php | 723 | ||||
-rw-r--r-- | inc/3rdparty/libraries/mpdf/classes/indic.php | 433 | ||||
-rw-r--r-- | inc/3rdparty/libraries/mpdf/classes/meter.php | 224 | ||||
-rw-r--r-- | inc/3rdparty/libraries/mpdf/classes/svg.php | 2600 | ||||
-rw-r--r-- | inc/3rdparty/libraries/mpdf/classes/tocontents.php | 468 | ||||
-rw-r--r-- | inc/3rdparty/libraries/mpdf/classes/ttfontsuni.php | 2065 | ||||
-rw-r--r-- | inc/3rdparty/libraries/mpdf/classes/ttfontsuni_analysis.php | 463 | ||||
-rw-r--r-- | inc/3rdparty/libraries/mpdf/classes/wmf.php | 236 |
14 files changed, 13597 insertions, 0 deletions
diff --git a/inc/3rdparty/libraries/mpdf/classes/barcode.php b/inc/3rdparty/libraries/mpdf/classes/barcode.php new file mode 100644 index 00000000..2a002693 --- /dev/null +++ b/inc/3rdparty/libraries/mpdf/classes/barcode.php | |||
@@ -0,0 +1,1965 @@ | |||
1 | <?php | ||
2 | |||
3 | // Adapted for mPDF from TCPDF barcode. Original Details left below. | ||
4 | |||
5 | //============================================================+ | ||
6 | // File name : barcodes.php | ||
7 | // Begin : 2008-06-09 | ||
8 | // Last Update : 2009-04-15 | ||
9 | // Version : 1.0.008 | ||
10 | // License : GNU LGPL (http://www.gnu.org/copyleft/lesser.html) | ||
11 | // ---------------------------------------------------------------------------- | ||
12 | // Copyright (C) 2008-2009 Nicola Asuni - Tecnick.com S.r.l. | ||
13 | // | ||
14 | // This program is free software: you can redistribute it and/or modify | ||
15 | // it under the terms of the GNU Lesser General Public License as published by | ||
16 | // the Free Software Foundation, either version 2.1 of the License, or | ||
17 | // (at your option) any later version. | ||
18 | // | ||
19 | // This program is distributed in the hope that it will be useful, | ||
20 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
22 | // 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 this program. 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 | // Author: Nicola Asuni | ||
34 | // | ||
35 | // (c) Copyright: | ||
36 | // Nicola Asuni | ||
37 | // Tecnick.com S.r.l. | ||
38 | // Via della Pace, 11 | ||
39 | // 09044 Quartucciu (CA) | ||
40 | // ITALY | ||
41 | // www.tecnick.com | ||
42 | // info@tecnick.com | ||
43 | //============================================================+ | ||
44 | |||
45 | class PDFBarcode { | ||
46 | |||
47 | protected $barcode_array; | ||
48 | protected $gapwidth; | ||
49 | protected $print_ratio; | ||
50 | protected $daft; | ||
51 | |||
52 | public function __construct() { | ||
53 | |||
54 | } | ||
55 | |||
56 | public function getBarcodeArray($code, $type, $pr='') { | ||
57 | $this->setBarcode($code, $type, $pr); | ||
58 | return $this->barcode_array; | ||
59 | } | ||
60 | public function getChecksum($code, $type) { | ||
61 | $this->setBarcode($code, $type); | ||
62 | if (!$this->barcode_array) { return ''; } | ||
63 | else { return $this->barcode_array['checkdigit']; } | ||
64 | } | ||
65 | |||
66 | public function setBarcode($code, $type, $pr='') { | ||
67 | $this->print_ratio = 1; | ||
68 | switch (strtoupper($type)) { | ||
69 | case 'ISBN': | ||
70 | case 'ISSN': | ||
71 | case 'EAN13': { // EAN 13 | ||
72 | $arrcode = $this->barcode_eanupc($code, 13); | ||
73 | $arrcode['lightmL'] = 11; // LEFT light margin = x X-dim (http://www.gs1uk.org) | ||
74 | $arrcode['lightmR'] = 7; // RIGHT light margin = x X-dim (http://www.gs1uk.org) | ||
75 | $arrcode['nom-X'] = 0.33; // Nominal value for X-dim in mm (http://www.gs1uk.org) | ||
76 | $arrcode['nom-H'] = 25.93; // Nominal bar height in mm incl. numerals (http://www.gs1uk.org) | ||
77 | break; | ||
78 | } | ||
79 | case 'UPCA': { // UPC-A | ||
80 | $arrcode = $this->barcode_eanupc($code, 12); | ||
81 | $arrcode['lightmL'] = 9; // LEFT light margin = x X-dim (http://www.gs1uk.org) | ||
82 | $arrcode['lightmR'] = 9; // RIGHT light margin = x X-dim (http://www.gs1uk.org) | ||
83 | $arrcode['nom-X'] = 0.33; // Nominal value for X-dim in mm (http://www.gs1uk.org) | ||
84 | $arrcode['nom-H'] = 25.91; // Nominal bar height in mm incl. numerals (http://www.gs1uk.org) | ||
85 | break; | ||
86 | } | ||
87 | case 'UPCE': { // UPC-E | ||
88 | $arrcode = $this->barcode_eanupc($code, 6); | ||
89 | $arrcode['lightmL'] = 9; // LEFT light margin = x X-dim (http://www.gs1uk.org) | ||
90 | $arrcode['lightmR'] = 7; // RIGHT light margin = x X-dim (http://www.gs1uk.org) | ||
91 | $arrcode['nom-X'] = 0.33; // Nominal value for X-dim in mm (http://www.gs1uk.org) | ||
92 | $arrcode['nom-H'] = 25.93; // Nominal bar height in mm incl. numerals (http://www.gs1uk.org) | ||
93 | break; | ||
94 | } | ||
95 | case 'EAN8': { // EAN 8 | ||
96 | $arrcode = $this->barcode_eanupc($code, 8); | ||
97 | $arrcode['lightmL'] = 7; // LEFT light margin = x X-dim (http://www.gs1uk.org) | ||
98 | $arrcode['lightmR'] = 7; // RIGHT light margin = x X-dim (http://www.gs1uk.org) | ||
99 | $arrcode['nom-X'] = 0.33; // Nominal value for X-dim in mm (http://www.gs1uk.org) | ||
100 | $arrcode['nom-H'] = 21.64; // Nominal bar height in mm incl. numerals (http://www.gs1uk.org) | ||
101 | break; | ||
102 | } | ||
103 | case 'EAN2': { // 2-Digits UPC-Based Extention | ||
104 | $arrcode = $this->barcode_eanext($code, 2); | ||
105 | $arrcode['lightmL'] = 7; // LEFT light margin = x X-dim (estimated) | ||
106 | $arrcode['lightmR'] = 7; // RIGHT light margin = x X-dim (estimated) | ||
107 | $arrcode['sepM'] = 9; // SEPARATION margin = x X-dim (http://web.archive.org/web/19990501035133/http://www.uc-council.org/d36-d.htm) | ||
108 | $arrcode['nom-X'] = 0.33; // Nominal value for X-dim in mm (http://www.gs1uk.org) | ||
109 | $arrcode['nom-H'] = 20; // Nominal bar height in mm incl. numerals (estimated) not used when combined | ||
110 | break; | ||
111 | } | ||
112 | case 'EAN5': { // 5-Digits UPC-Based Extention | ||
113 | $arrcode = $this->barcode_eanext($code, 5); | ||
114 | $arrcode['lightmL'] = 7; // LEFT light margin = x X-dim (estimated) | ||
115 | $arrcode['lightmR'] = 7; // RIGHT light margin = x X-dim (estimated) | ||
116 | $arrcode['sepM'] = 9; // SEPARATION margin = x X-dim (http://web.archive.org/web/19990501035133/http://www.uc-council.org/d36-d.htm) | ||
117 | $arrcode['nom-X'] = 0.33; // Nominal value for X-dim in mm (http://www.gs1uk.org) | ||
118 | $arrcode['nom-H'] = 20; // Nominal bar height in mm incl. numerals (estimated) not used when combined | ||
119 | break; | ||
120 | } | ||
121 | |||
122 | case 'IMB': { // IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200 | ||
123 | $xdim = 0.508; // Nominal value for X-dim (bar width) in mm (spec.) | ||
124 | $bpi = 22; // Bars per inch | ||
125 | // Ratio of Nominal value for width of spaces in mm / Nominal value for X-dim (bar width) in mm based on bars per inch | ||
126 | $this->gapwidth = ((25.4/$bpi) - $xdim)/$xdim; | ||
127 | $this->daft = array('D'=>2, 'A'=>2, 'F'=>3, 'T'=>1); // Descender; Ascender; Full; Tracker bar heights | ||
128 | $arrcode = $this->barcode_imb($code); | ||
129 | $arrcode['nom-X'] = $xdim ; | ||
130 | $arrcode['nom-H'] = 3.68; // Nominal value for Height of Full bar in mm (spec.) | ||
131 | // USPS-B-3200 Revision C = 4.623 | ||
132 | // USPS-B-3200 Revision E = 3.68 | ||
133 | $arrcode['quietL'] = 3.175; // LEFT Quiet margin = mm (spec.) | ||
134 | $arrcode['quietR'] = 3.175; // RIGHT Quiet margin = mm (spec.) | ||
135 | $arrcode['quietTB'] = 0.711; // TOP/BOTTOM Quiet margin = mm (spec.) | ||
136 | break; | ||
137 | } | ||
138 | case 'RM4SCC': { // RM4SCC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code) | ||
139 | $xdim = 0.508; // Nominal value for X-dim (bar width) in mm (spec.) | ||
140 | $bpi = 22; // Bars per inch | ||
141 | // Ratio of Nominal value for width of spaces in mm / Nominal value for X-dim (bar width) in mm based on bars per inch | ||
142 | $this->gapwidth = ((25.4/$bpi) - $xdim)/$xdim; | ||
143 | $this->daft = array('D'=>5, 'A'=>5, 'F'=>8, 'T'=>2); // Descender; Ascender; Full; Tracker bar heights | ||
144 | $arrcode = $this->barcode_rm4scc($code, false); | ||
145 | $arrcode['nom-X'] = $xdim ; | ||
146 | $arrcode['nom-H'] = 5.0; // Nominal value for Height of Full bar in mm (spec.) | ||
147 | $arrcode['quietL'] = 2; // LEFT Quiet margin = mm (spec.) | ||
148 | $arrcode['quietR'] = 2; // RIGHT Quiet margin = mm (spec.) | ||
149 | $arrcode['quietTB'] = 2; // TOP/BOTTOM Quiet margin = mm (spec?) | ||
150 | break; | ||
151 | } | ||
152 | case 'KIX': { // KIX (Klant index - Customer index) | ||
153 | $xdim = 0.508; // Nominal value for X-dim (bar width) in mm (spec.) | ||
154 | $bpi = 22; // Bars per inch | ||
155 | // Ratio of Nominal value for width of spaces in mm / Nominal value for X-dim (bar width) in mm based on bars per inch | ||
156 | $this->gapwidth = ((25.4/$bpi) - $xdim)/$xdim; | ||
157 | $this->daft = array('D'=>5, 'A'=>5, 'F'=>8, 'T'=>2); // Descender; Ascender; Full; Tracker bar heights | ||
158 | $arrcode = $this->barcode_rm4scc($code, true); | ||
159 | $arrcode['nom-X'] = $xdim ; | ||
160 | $arrcode['nom-H'] = 5.0; // Nominal value for Height of Full bar in mm (? spec.) | ||
161 | $arrcode['quietL'] = 2; // LEFT Quiet margin = mm (spec.) | ||
162 | $arrcode['quietR'] = 2; // RIGHT Quiet margin = mm (spec.) | ||
163 | $arrcode['quietTB'] = 2; // TOP/BOTTOM Quiet margin = mm (spec.) | ||
164 | break; | ||
165 | } | ||
166 | case 'POSTNET': { // POSTNET | ||
167 | $xdim = 0.508; // Nominal value for X-dim (bar width) in mm (spec.) | ||
168 | $bpi = 22; // Bars per inch | ||
169 | // Ratio of Nominal value for width of spaces in mm / Nominal value for X-dim (bar width) in mm based on bars per inch | ||
170 | $this->gapwidth = ((25.4/$bpi) - $xdim)/$xdim; | ||
171 | $arrcode = $this->barcode_postnet($code, false); | ||
172 | $arrcode['nom-X'] = $xdim ; | ||
173 | $arrcode['nom-H'] = 3.175; // Nominal value for Height of Full bar in mm (spec.) | ||
174 | $arrcode['quietL'] = 3.175; // LEFT Quiet margin = mm (?spec.) | ||
175 | $arrcode['quietR'] = 3.175; // RIGHT Quiet margin = mm (?spec.) | ||
176 | $arrcode['quietTB'] = 1.016; // TOP/BOTTOM Quiet margin = mm (?spec.) | ||
177 | break; | ||
178 | } | ||
179 | case 'PLANET': { // PLANET | ||
180 | $xdim = 0.508; // Nominal value for X-dim (bar width) in mm (spec.) | ||
181 | $bpi = 22; // Bars per inch | ||
182 | // Ratio of Nominal value for width of spaces in mm / Nominal value for X-dim (bar width) in mm based on bars per inch | ||
183 | $this->gapwidth = ((25.4/$bpi) - $xdim)/$xdim; | ||
184 | $arrcode = $this->barcode_postnet($code, true); | ||
185 | $arrcode['nom-X'] = $xdim ; | ||
186 | $arrcode['nom-H'] = 3.175; // Nominal value for Height of Full bar in mm (spec.) | ||
187 | $arrcode['quietL'] = 3.175; // LEFT Quiet margin = mm (?spec.) | ||
188 | $arrcode['quietR'] = 3.175; // RIGHT Quiet margin = mm (?spec.) | ||
189 | $arrcode['quietTB'] = 1.016; // TOP/BOTTOM Quiet margin = mm (?spec.) | ||
190 | break; | ||
191 | } | ||
192 | |||
193 | case 'C93': { // CODE 93 - USS-93 | ||
194 | $arrcode = $this->barcode_code93($code); | ||
195 | if ($arrcode == false) { break; } | ||
196 | $arrcode['nom-X'] = 0.381; // Nominal value for X-dim (bar width) in mm (2 X min. spec.) | ||
197 | $arrcode['nom-H'] = 10; // Nominal value for Height of Full bar in mm (non-spec.) | ||
198 | $arrcode['lightmL'] = 10; // LEFT light margin = x X-dim (spec.) | ||
199 | $arrcode['lightmR'] = 10; // RIGHT light margin = x X-dim (spec.) | ||
200 | $arrcode['lightTB'] = 0; // TOP/BOTTOM light margin = x X-dim (non-spec.) | ||
201 | break; | ||
202 | } | ||
203 | case 'CODE11': { // CODE 11 | ||
204 | if ($pr > 0) { $this->print_ratio = $pr; } | ||
205 | else { $this->print_ratio = 3; } // spec: Pr= 1:2.24 - 1:3.5 | ||
206 | $arrcode = $this->barcode_code11($code); | ||
207 | if ($arrcode == false) { break; } | ||
208 | $arrcode['nom-X'] = 0.381; // Nominal value for X-dim (bar width) in mm (2 X min. spec.) | ||
209 | $arrcode['nom-H'] = 10; // Nominal value for Height of Full bar in mm (non-spec.) | ||
210 | $arrcode['lightmL'] = 10; // LEFT light margin = x X-dim (spec.) | ||
211 | $arrcode['lightmR'] = 10; // RIGHT light margin = x X-dim (spec.) | ||
212 | $arrcode['lightTB'] = 0; // TOP/BOTTOM light margin = x X-dim (non-spec.) | ||
213 | break; | ||
214 | } | ||
215 | case 'MSI': // MSI (Variation of Plessey code) | ||
216 | case 'MSI+': { // MSI + CHECKSUM (modulo 11) | ||
217 | if (strtoupper($type)=='MSI') { $arrcode = $this->barcode_msi($code, false); } | ||
218 | if (strtoupper($type)=='MSI+') { $arrcode = $this->barcode_msi($code, true); } | ||
219 | if ($arrcode == false) { break; } | ||
220 | $arrcode['nom-X'] = 0.381; // Nominal value for X-dim (bar width) in mm (2 X min. spec.) | ||
221 | $arrcode['nom-H'] = 10; // Nominal value for Height of Full bar in mm (non-spec.) | ||
222 | $arrcode['lightmL'] = 12; // LEFT light margin = x X-dim (spec.) | ||
223 | $arrcode['lightmR'] = 12; // RIGHT light margin = x X-dim (spec.) | ||
224 | $arrcode['lightTB'] = 0; // TOP/BOTTOM light margin = x X-dim (non-spec.) | ||
225 | break; | ||
226 | } | ||
227 | case 'CODABAR': { // CODABAR | ||
228 | if ($pr > 0) { $this->print_ratio = $pr; } | ||
229 | else { $this->print_ratio = 2.5; } // spec: Pr= 1:2 - 1:3 (>2.2 if X<0.50) | ||
230 | if (strtoupper($type)=='CODABAR') { $arrcode = $this->barcode_codabar($code); } | ||
231 | if ($arrcode == false) { break; } | ||
232 | $arrcode['nom-X'] = 0.381; // Nominal value for X-dim (bar width) in mm (2 X min. spec.) | ||
233 | $arrcode['nom-H'] = 10; // Nominal value for Height of Full bar in mm (non-spec.) | ||
234 | $arrcode['lightmL'] = 10; // LEFT light margin = x X-dim (spec.) | ||
235 | $arrcode['lightmR'] = 10; // RIGHT light margin = x X-dim (spec.) | ||
236 | $arrcode['lightTB'] = 0; // TOP/BOTTOM light margin = x X-dim (non-spec.) | ||
237 | break; | ||
238 | } | ||
239 | case 'C128A': // CODE 128 A | ||
240 | case 'C128B': // CODE 128 B | ||
241 | case 'C128C': // CODE 128 C | ||
242 | case 'EAN128A': // EAN 128 A | ||
243 | case 'EAN128B': // EAN 128 B | ||
244 | case 'EAN128C': { // EAN 128 C | ||
245 | if (strtoupper($type)=='C128A') { $arrcode = $this->barcode_c128($code, 'A'); } | ||
246 | if (strtoupper($type)=='C128B') { $arrcode = $this->barcode_c128($code, 'B'); } | ||
247 | if (strtoupper($type)=='C128C') { $arrcode = $this->barcode_c128($code, 'C'); } | ||
248 | if (strtoupper($type)=='EAN128A') { $arrcode = $this->barcode_c128($code, 'A', true); } | ||
249 | if (strtoupper($type)=='EAN128B') { $arrcode = $this->barcode_c128($code, 'B', true); } | ||
250 | if (strtoupper($type)=='EAN128C') { $arrcode = $this->barcode_c128($code, 'C', true); } | ||
251 | if ($arrcode == false) { break; } | ||
252 | $arrcode['nom-X'] = 0.381; // Nominal value for X-dim (bar width) in mm (2 X min. spec.) | ||
253 | $arrcode['nom-H'] = 10; // Nominal value for Height of Full bar in mm (non-spec.) | ||
254 | $arrcode['lightmL'] = 10; // LEFT light margin = x X-dim (spec.) | ||
255 | $arrcode['lightmR'] = 10; // RIGHT light margin = x X-dim (spec.) | ||
256 | $arrcode['lightTB'] = 0; // TOP/BOTTOM light margin = x X-dim (non-spec.) | ||
257 | break; | ||
258 | } | ||
259 | case 'C39': // CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9. | ||
260 | case 'C39+': // CODE 39 with checksum | ||
261 | case 'C39E': // CODE 39 EXTENDED | ||
262 | case 'C39E+': { // CODE 39 EXTENDED + CHECKSUM | ||
263 | if ($pr > 0) { $this->print_ratio = $pr; } | ||
264 | else { $this->print_ratio = 2.5; } // spec: Pr= 1:2 - 1:3 (>2.2 if X<0.50) | ||
265 | $code = str_replace(chr(194).chr(160), ' ', $code); // mPDF 5.3.95 (for utf-8 encoded) | ||
266 | $code = str_replace(chr(160), ' ', $code); // mPDF 5.3.95 (for win-1252) | ||
267 | if (strtoupper($type)=='C39') { $arrcode = $this->barcode_code39($code, false, false); } | ||
268 | if (strtoupper($type)=='C39+') { $arrcode = $this->barcode_code39($code, false, true); } | ||
269 | if (strtoupper($type)=='C39E') { $arrcode = $this->barcode_code39($code, true, false); } | ||
270 | if (strtoupper($type)=='C39E+') { $arrcode = $this->barcode_code39($code, true, true); } | ||
271 | if ($arrcode == false) { break; } | ||
272 | $arrcode['nom-X'] = 0.381; // Nominal value for X-dim (bar width) in mm (2 X min. spec.) | ||
273 | $arrcode['nom-H'] = 10; // Nominal value for Height of Full bar in mm (non-spec.) | ||
274 | $arrcode['lightmL'] = 10; // LEFT light margin = x X-dim (spec.) | ||
275 | $arrcode['lightmR'] = 10; // RIGHT light margin = x X-dim (spec.) | ||
276 | $arrcode['lightTB'] = 0; // TOP/BOTTOM light margin = x X-dim (non-spec.) | ||
277 | break; | ||
278 | } | ||
279 | case 'S25': // Standard 2 of 5 | ||
280 | case 'S25+': { // Standard 2 of 5 + CHECKSUM | ||
281 | if ($pr > 0) { $this->print_ratio = $pr; } | ||
282 | else { $this->print_ratio = 3; } // spec: Pr=1:3/1:4.5 | ||
283 | if (strtoupper($type)=='S25') { $arrcode = $this->barcode_s25($code, false); } | ||
284 | if (strtoupper($type)=='S25+') { $arrcode = $this->barcode_s25($code, true); } | ||
285 | if ($arrcode == false) { break; } | ||
286 | $arrcode['nom-X'] = 0.381; // Nominal value for X-dim (bar width) in mm (2 X min. spec.) | ||
287 | $arrcode['nom-H'] = 10; // Nominal value for Height of Full bar in mm (non-spec.) | ||
288 | $arrcode['lightmL'] = 10; // LEFT light margin = x X-dim (spec.) | ||
289 | $arrcode['lightmR'] = 10; // RIGHT light margin = x X-dim (spec.) | ||
290 | $arrcode['lightTB'] = 0; // TOP/BOTTOM light margin = x X-dim (non-spec.) | ||
291 | break; | ||
292 | } | ||
293 | case 'I25': // Interleaved 2 of 5 | ||
294 | case 'I25+': { // Interleaved 2 of 5 + CHECKSUM | ||
295 | if ($pr > 0) { $this->print_ratio = $pr; } | ||
296 | else { $this->print_ratio = 2.5; } // spec: Pr= 1:2 - 1:3 (>2.2 if X<0.50) | ||
297 | if (strtoupper($type)=='I25') { $arrcode = $this->barcode_i25($code, false); } | ||
298 | if (strtoupper($type)=='I25+') { $arrcode = $this->barcode_i25($code, true); } | ||
299 | if ($arrcode == false) { break; } | ||
300 | $arrcode['nom-X'] = 0.381; // Nominal value for X-dim (bar width) in mm (2 X min. spec.) | ||
301 | $arrcode['nom-H'] = 10; // Nominal value for Height of Full bar in mm (non-spec.) | ||
302 | $arrcode['lightmL'] = 10; // LEFT light margin = x X-dim (spec.) | ||
303 | $arrcode['lightmR'] = 10; // RIGHT light margin = x X-dim (spec.) | ||
304 | $arrcode['lightTB'] = 0; // TOP/BOTTOM light margin = x X-dim (non-spec.) | ||
305 | break; | ||
306 | } | ||
307 | case 'I25B': // Interleaved 2 of 5 + Bearer bars | ||
308 | case 'I25B+': { // Interleaved 2 of 5 + CHECKSUM + Bearer bars | ||
309 | if ($pr > 0) { $this->print_ratio = $pr; } | ||
310 | else { $this->print_ratio = 2.5; } // spec: Pr= 1:2 - 1:3 (>2.2 if X<0.50) | ||
311 | if (strtoupper($type)=='I25B') { $arrcode = $this->barcode_i25($code, false); } | ||
312 | if (strtoupper($type)=='I25B+') { $arrcode = $this->barcode_i25($code, true); } | ||
313 | if ($arrcode == false) { break; } | ||
314 | $arrcode['nom-X'] = 0.381; // Nominal value for X-dim (bar width) in mm (2 X min. spec.) | ||
315 | $arrcode['nom-H'] = 10; // Nominal value for Height of Full bar in mm (non-spec.) | ||
316 | $arrcode['lightmL'] = 10; // LEFT light margin = x X-dim (spec.) | ||
317 | $arrcode['lightmR'] = 10; // RIGHT light margin = x X-dim (spec.) | ||
318 | $arrcode['lightTB'] = 2; // TOP/BOTTOM light margin = x X-dim (non-spec.) - used for bearer bars | ||
319 | break; | ||
320 | } | ||
321 | default: { | ||
322 | $this->barcode_array = false; | ||
323 | } | ||
324 | } | ||
325 | $this->barcode_array = $arrcode; | ||
326 | } | ||
327 | |||
328 | /** | ||
329 | * CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9. | ||
330 | */ | ||
331 | protected function barcode_code39($code, $extended=false, $checksum=false) { | ||
332 | $chr['0'] = '111221211'; | ||
333 | $chr['1'] = '211211112'; | ||
334 | $chr['2'] = '112211112'; | ||
335 | $chr['3'] = '212211111'; | ||
336 | $chr['4'] = '111221112'; | ||
337 | $chr['5'] = '211221111'; | ||
338 | $chr['6'] = '112221111'; | ||
339 | $chr['7'] = '111211212'; | ||
340 | $chr['8'] = '211211211'; | ||
341 | $chr['9'] = '112211211'; | ||
342 | $chr['A'] = '211112112'; | ||
343 | $chr['B'] = '112112112'; | ||
344 | $chr['C'] = '212112111'; | ||
345 | $chr['D'] = '111122112'; | ||
346 | $chr['E'] = '211122111'; | ||
347 | $chr['F'] = '112122111'; | ||
348 | $chr['G'] = '111112212'; | ||
349 | $chr['H'] = '211112211'; | ||
350 | $chr['I'] = '112112211'; | ||
351 | $chr['J'] = '111122211'; | ||
352 | $chr['K'] = '211111122'; | ||
353 | $chr['L'] = '112111122'; | ||
354 | $chr['M'] = '212111121'; | ||
355 | $chr['N'] = '111121122'; | ||
356 | $chr['O'] = '211121121'; | ||
357 | $chr['P'] = '112121121'; | ||
358 | $chr['Q'] = '111111222'; | ||
359 | $chr['R'] = '211111221'; | ||
360 | $chr['S'] = '112111221'; | ||
361 | $chr['T'] = '111121221'; | ||
362 | $chr['U'] = '221111112'; | ||
363 | $chr['V'] = '122111112'; | ||
364 | $chr['W'] = '222111111'; | ||
365 | $chr['X'] = '121121112'; | ||
366 | $chr['Y'] = '221121111'; | ||
367 | $chr['Z'] = '122121111'; | ||
368 | $chr['-'] = '121111212'; | ||
369 | $chr['.'] = '221111211'; | ||
370 | $chr[' '] = '122111211'; | ||
371 | $chr['$'] = '121212111'; | ||
372 | $chr['/'] = '121211121'; | ||
373 | $chr['+'] = '121112121'; | ||
374 | $chr['%'] = '111212121'; | ||
375 | $chr['*'] = '121121211'; | ||
376 | |||
377 | $code = strtoupper($code); | ||
378 | if ($extended) { | ||
379 | // extended mode | ||
380 | $code = $this->encode_code39_ext($code); | ||
381 | } | ||
382 | if ($code === false) { | ||
383 | return false; | ||
384 | } | ||
385 | if ($checksum) { | ||
386 | // checksum | ||
387 | $checkdigit = $this->checksum_code39($code); | ||
388 | $code .= $checkdigit ; | ||
389 | } | ||
390 | // add start and stop codes | ||
391 | $code = '*'.$code.'*'; | ||
392 | |||
393 | $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); | ||
394 | $k = 0; | ||
395 | $clen = strlen($code); | ||
396 | for ($i = 0; $i < $clen; ++$i) { | ||
397 | $char = $code[$i]; | ||
398 | if(!isset($chr[$char])) { | ||
399 | // invalid character | ||
400 | return false; | ||
401 | } | ||
402 | for ($j = 0; $j < 9; ++$j) { | ||
403 | if (($j % 2) == 0) { | ||
404 | $t = true; // bar | ||
405 | } else { | ||
406 | $t = false; // space | ||
407 | } | ||
408 | $x = $chr[$char][$j]; | ||
409 | if ($x == 2) { $w = $this->print_ratio; } | ||
410 | else { $w = 1; } | ||
411 | |||
412 | $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); | ||
413 | $bararray['maxw'] += $w; | ||
414 | ++$k; | ||
415 | } | ||
416 | $bararray['bcode'][$k] = array('t' => false, 'w' => 1, 'h' => 1, 'p' => 0); | ||
417 | $bararray['maxw'] += 1; | ||
418 | ++$k; | ||
419 | } | ||
420 | $bararray['checkdigit'] = $checkdigit; | ||
421 | return $bararray; | ||
422 | } | ||
423 | |||
424 | /** | ||
425 | * Encode a string to be used for CODE 39 Extended mode. | ||
426 | */ | ||
427 | protected function encode_code39_ext($code) { | ||
428 | $encode = array( | ||
429 | chr(0) => '%U', chr(1) => '$A', chr(2) => '$B', chr(3) => '$C', | ||
430 | chr(4) => '$D', chr(5) => '$E', chr(6) => '$F', chr(7) => '$G', | ||
431 | chr(8) => '$H', chr(9) => '$I', chr(10) => '$J', chr(11) => '£K', | ||
432 | chr(12) => '$L', chr(13) => '$M', chr(14) => '$N', chr(15) => '$O', | ||
433 | chr(16) => '$P', chr(17) => '$Q', chr(18) => '$R', chr(19) => '$S', | ||
434 | chr(20) => '$T', chr(21) => '$U', chr(22) => '$V', chr(23) => '$W', | ||
435 | chr(24) => '$X', chr(25) => '$Y', chr(26) => '$Z', chr(27) => '%A', | ||
436 | chr(28) => '%B', chr(29) => '%C', chr(30) => '%D', chr(31) => '%E', | ||
437 | chr(32) => ' ', chr(33) => '/A', chr(34) => '/B', chr(35) => '/C', | ||
438 | chr(36) => '/D', chr(37) => '/E', chr(38) => '/F', chr(39) => '/G', | ||
439 | chr(40) => '/H', chr(41) => '/I', chr(42) => '/J', chr(43) => '/K', | ||
440 | chr(44) => '/L', chr(45) => '-', chr(46) => '.', chr(47) => '/O', | ||
441 | chr(48) => '0', chr(49) => '1', chr(50) => '2', chr(51) => '3', | ||
442 | chr(52) => '4', chr(53) => '5', chr(54) => '6', chr(55) => '7', | ||
443 | chr(56) => '8', chr(57) => '9', chr(58) => '/Z', chr(59) => '%F', | ||
444 | chr(60) => '%G', chr(61) => '%H', chr(62) => '%I', chr(63) => '%J', | ||
445 | chr(64) => '%V', chr(65) => 'A', chr(66) => 'B', chr(67) => 'C', | ||
446 | chr(68) => 'D', chr(69) => 'E', chr(70) => 'F', chr(71) => 'G', | ||
447 | chr(72) => 'H', chr(73) => 'I', chr(74) => 'J', chr(75) => 'K', | ||
448 | chr(76) => 'L', chr(77) => 'M', chr(78) => 'N', chr(79) => 'O', | ||
449 | chr(80) => 'P', chr(81) => 'Q', chr(82) => 'R', chr(83) => 'S', | ||
450 | chr(84) => 'T', chr(85) => 'U', chr(86) => 'V', chr(87) => 'W', | ||
451 | chr(88) => 'X', chr(89) => 'Y', chr(90) => 'Z', chr(91) => '%K', | ||
452 | chr(92) => '%L', chr(93) => '%M', chr(94) => '%N', chr(95) => '%O', | ||
453 | chr(96) => '%W', chr(97) => '+A', chr(98) => '+B', chr(99) => '+C', | ||
454 | chr(100) => '+D', chr(101) => '+E', chr(102) => '+F', chr(103) => '+G', | ||
455 | chr(104) => '+H', chr(105) => '+I', chr(106) => '+J', chr(107) => '+K', | ||
456 | chr(108) => '+L', chr(109) => '+M', chr(110) => '+N', chr(111) => '+O', | ||
457 | chr(112) => '+P', chr(113) => '+Q', chr(114) => '+R', chr(115) => '+S', | ||
458 | chr(116) => '+T', chr(117) => '+U', chr(118) => '+V', chr(119) => '+W', | ||
459 | chr(120) => '+X', chr(121) => '+Y', chr(122) => '+Z', chr(123) => '%P', | ||
460 | chr(124) => '%Q', chr(125) => '%R', chr(126) => '%S', chr(127) => '%T'); | ||
461 | $code_ext = ''; | ||
462 | $clen = strlen($code); | ||
463 | for ($i = 0 ; $i < $clen; ++$i) { | ||
464 | if (ord($code[$i]) > 127) { | ||
465 | return false; | ||
466 | } | ||
467 | $code_ext .= $encode[$code[$i]]; | ||
468 | } | ||
469 | return $code_ext; | ||
470 | } | ||
471 | |||
472 | /** | ||
473 | * Calculate CODE 39 checksum (modulo 43). | ||
474 | */ | ||
475 | protected function checksum_code39($code) { | ||
476 | $chars = array( | ||
477 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', | ||
478 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', | ||
479 | 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', | ||
480 | 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%'); | ||
481 | $sum = 0; | ||
482 | $clen = strlen($code); | ||
483 | for ($i = 0 ; $i < $clen; ++$i) { | ||
484 | $k = array_keys($chars, $code[$i]); | ||
485 | $sum += $k[0]; | ||
486 | } | ||
487 | $j = ($sum % 43); | ||
488 | return $chars[$j]; | ||
489 | } | ||
490 | |||
491 | /** | ||
492 | * CODE 93 - USS-93 | ||
493 | * Compact code similar to Code 39 | ||
494 | */ | ||
495 | protected function barcode_code93($code) { | ||
496 | $chr['0'] = '131112'; | ||
497 | $chr['1'] = '111213'; | ||
498 | $chr['2'] = '111312'; | ||
499 | $chr['3'] = '111411'; | ||
500 | $chr['4'] = '121113'; | ||
501 | $chr['5'] = '121212'; | ||
502 | $chr['6'] = '121311'; | ||
503 | $chr['7'] = '111114'; | ||
504 | $chr['8'] = '131211'; | ||
505 | $chr['9'] = '141111'; | ||
506 | $chr['A'] = '211113'; | ||
507 | $chr['B'] = '211212'; | ||
508 | $chr['C'] = '211311'; | ||
509 | $chr['D'] = '221112'; | ||
510 | $chr['E'] = '221211'; | ||
511 | $chr['F'] = '231111'; | ||
512 | $chr['G'] = '112113'; | ||
513 | $chr['H'] = '112212'; | ||
514 | $chr['I'] = '112311'; | ||
515 | $chr['J'] = '122112'; | ||
516 | $chr['K'] = '132111'; | ||
517 | $chr['L'] = '111123'; | ||
518 | $chr['M'] = '111222'; | ||
519 | $chr['N'] = '111321'; | ||
520 | $chr['O'] = '121122'; | ||
521 | $chr['P'] = '131121'; | ||
522 | $chr['Q'] = '212112'; | ||
523 | $chr['R'] = '212211'; | ||
524 | $chr['S'] = '211122'; | ||
525 | $chr['T'] = '211221'; | ||
526 | $chr['U'] = '221121'; | ||
527 | $chr['V'] = '222111'; | ||
528 | $chr['W'] = '112122'; | ||
529 | $chr['X'] = '112221'; | ||
530 | $chr['Y'] = '122121'; | ||
531 | $chr['Z'] = '123111'; | ||
532 | $chr['-'] = '121131'; | ||
533 | $chr['.'] = '311112'; | ||
534 | $chr[' '] = '311211'; | ||
535 | $chr['$'] = '321111'; | ||
536 | $chr['/'] = '112131'; | ||
537 | $chr['+'] = '113121'; | ||
538 | $chr['%'] = '211131'; | ||
539 | $chr[128] = '121221'; // ($) | ||
540 | $chr[129] = '311121'; // (/) | ||
541 | $chr[130] = '122211'; // (+) | ||
542 | $chr[131] = '312111'; // (%) | ||
543 | $chr['*'] = '111141'; | ||
544 | $code = strtoupper($code); | ||
545 | $encode = array( | ||
546 | chr(0) => chr(131).'U', chr(1) => chr(128).'A', chr(2) => chr(128).'B', chr(3) => chr(128).'C', | ||
547 | chr(4) => chr(128).'D', chr(5) => chr(128).'E', chr(6) => chr(128).'F', chr(7) => chr(128).'G', | ||
548 | chr(8) => chr(128).'H', chr(9) => chr(128).'I', chr(10) => chr(128).'J', chr(11) => '£K', | ||
549 | chr(12) => chr(128).'L', chr(13) => chr(128).'M', chr(14) => chr(128).'N', chr(15) => chr(128).'O', | ||
550 | chr(16) => chr(128).'P', chr(17) => chr(128).'Q', chr(18) => chr(128).'R', chr(19) => chr(128).'S', | ||
551 | chr(20) => chr(128).'T', chr(21) => chr(128).'U', chr(22) => chr(128).'V', chr(23) => chr(128).'W', | ||
552 | chr(24) => chr(128).'X', chr(25) => chr(128).'Y', chr(26) => chr(128).'Z', chr(27) => chr(131).'A', | ||
553 | chr(28) => chr(131).'B', chr(29) => chr(131).'C', chr(30) => chr(131).'D', chr(31) => chr(131).'E', | ||
554 | chr(32) => ' ', chr(33) => chr(129).'A', chr(34) => chr(129).'B', chr(35) => chr(129).'C', | ||
555 | chr(36) => chr(129).'D', chr(37) => chr(129).'E', chr(38) => chr(129).'F', chr(39) => chr(129).'G', | ||
556 | chr(40) => chr(129).'H', chr(41) => chr(129).'I', chr(42) => chr(129).'J', chr(43) => chr(129).'K', | ||
557 | chr(44) => chr(129).'L', chr(45) => '-', chr(46) => '.', chr(47) => chr(129).'O', | ||
558 | chr(48) => '0', chr(49) => '1', chr(50) => '2', chr(51) => '3', | ||
559 | chr(52) => '4', chr(53) => '5', chr(54) => '6', chr(55) => '7', | ||
560 | chr(56) => '8', chr(57) => '9', chr(58) => chr(129).'Z', chr(59) => chr(131).'F', | ||
561 | chr(60) => chr(131).'G', chr(61) => chr(131).'H', chr(62) => chr(131).'I', chr(63) => chr(131).'J', | ||
562 | chr(64) => chr(131).'V', chr(65) => 'A', chr(66) => 'B', chr(67) => 'C', | ||
563 | chr(68) => 'D', chr(69) => 'E', chr(70) => 'F', chr(71) => 'G', | ||
564 | chr(72) => 'H', chr(73) => 'I', chr(74) => 'J', chr(75) => 'K', | ||
565 | chr(76) => 'L', chr(77) => 'M', chr(78) => 'N', chr(79) => 'O', | ||
566 | chr(80) => 'P', chr(81) => 'Q', chr(82) => 'R', chr(83) => 'S', | ||
567 | chr(84) => 'T', chr(85) => 'U', chr(86) => 'V', chr(87) => 'W', | ||
568 | chr(88) => 'X', chr(89) => 'Y', chr(90) => 'Z', chr(91) => chr(131).'K', | ||
569 | chr(92) => chr(131).'L', chr(93) => chr(131).'M', chr(94) => chr(131).'N', chr(95) => chr(131).'O', | ||
570 | chr(96) => chr(131).'W', chr(97) => chr(130).'A', chr(98) => chr(130).'B', chr(99) => chr(130).'C', | ||
571 | chr(100) => chr(130).'D', chr(101) => chr(130).'E', chr(102) => chr(130).'F', chr(103) => chr(130).'G', | ||
572 | chr(104) => chr(130).'H', chr(105) => chr(130).'I', chr(106) => chr(130).'J', chr(107) => chr(130).'K', | ||
573 | chr(108) => chr(130).'L', chr(109) => chr(130).'M', chr(110) => chr(130).'N', chr(111) => chr(130).'O', | ||
574 | chr(112) => chr(130).'P', chr(113) => chr(130).'Q', chr(114) => chr(130).'R', chr(115) => chr(130).'S', | ||
575 | chr(116) => chr(130).'T', chr(117) => chr(130).'U', chr(118) => chr(130).'V', chr(119) => chr(130).'W', | ||
576 | chr(120) => chr(130).'X', chr(121) => chr(130).'Y', chr(122) => chr(130).'Z', chr(123) => chr(131).'P', | ||
577 | chr(124) => chr(131).'Q', chr(125) => chr(131).'R', chr(126) => chr(131).'S', chr(127) => chr(131).'T'); | ||
578 | $code_ext = ''; | ||
579 | $clen = strlen($code); | ||
580 | for ($i = 0 ; $i < $clen; ++$i) { | ||
581 | if (ord($code[$i]) > 127) { | ||
582 | return false; | ||
583 | } | ||
584 | $code_ext .= $encode[$code[$i]]; | ||
585 | } | ||
586 | // checksum | ||
587 | $checkdigit = $this->checksum_code93($code); | ||
588 | $code .= $checkdigit ; | ||
589 | // add start and stop codes | ||
590 | $code = '*'.$code.'*'; | ||
591 | $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); | ||
592 | $k = 0; | ||
593 | $clen = strlen($code); | ||
594 | for ($i = 0; $i < $clen; ++$i) { | ||
595 | $char = $code[$i]; | ||
596 | if(!isset($chr[$char])) { | ||
597 | // invalid character | ||
598 | return false; | ||
599 | } | ||
600 | for ($j = 0; $j < 6; ++$j) { | ||
601 | if (($j % 2) == 0) { | ||
602 | $t = true; // bar | ||
603 | } else { | ||
604 | $t = false; // space | ||
605 | } | ||
606 | $w = $chr[$char][$j]; | ||
607 | $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); | ||
608 | $bararray['maxw'] += $w; | ||
609 | ++$k; | ||
610 | } | ||
611 | } | ||
612 | $bararray['bcode'][$k] = array('t' => true, 'w' => 1, 'h' => 1, 'p' => 0); | ||
613 | $bararray['maxw'] += 1; | ||
614 | ++$k; | ||
615 | $bararray['checkdigit'] = $checkdigit; | ||
616 | return $bararray; | ||
617 | } | ||
618 | |||
619 | /** | ||
620 | * Calculate CODE 93 checksum (modulo 47). | ||
621 | */ | ||
622 | protected function checksum_code93($code) { | ||
623 | $chars = array( | ||
624 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', | ||
625 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', | ||
626 | 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', | ||
627 | 'W', 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%'); | ||
628 | // translate special characters | ||
629 | $code = strtr($code, chr(128).chr(129).chr(130).chr(131), '$/+%'); | ||
630 | $len = strlen($code); | ||
631 | // calculate check digit C | ||
632 | $p = 1; | ||
633 | $check = 0; | ||
634 | for ($i = ($len - 1); $i >= 0; --$i) { | ||
635 | $k = array_keys($chars, $code[$i]); | ||
636 | $check += ($k[0] * $p); | ||
637 | ++$p; | ||
638 | if ($p > 20) { | ||
639 | $p = 1; | ||
640 | } | ||
641 | } | ||
642 | $check %= 47; | ||
643 | $c = $chars[$check]; | ||
644 | $code .= $c; | ||
645 | // calculate check digit K | ||
646 | $p = 1; | ||
647 | $check = 0; | ||
648 | for ($i = $len; $i >= 0; --$i) { | ||
649 | $k = array_keys($chars, $code[$i]); | ||
650 | $check += ($k[0] * $p); | ||
651 | ++$p; | ||
652 | if ($p > 15) { | ||
653 | $p = 1; | ||
654 | } | ||
655 | } | ||
656 | $check %= 47; | ||
657 | $k = $chars[$check]; | ||
658 | return $c.$k; | ||
659 | } | ||
660 | |||
661 | /** | ||
662 | * Checksum for standard 2 of 5 barcodes. | ||
663 | */ | ||
664 | protected function checksum_s25($code) { | ||
665 | $len = strlen($code); | ||
666 | $sum = 0; | ||
667 | for ($i = 0; $i < $len; $i+=2) { | ||
668 | $sum += $code[$i]; | ||
669 | } | ||
670 | $sum *= 3; | ||
671 | for ($i = 1; $i < $len; $i+=2) { | ||
672 | $sum += ($code[$i]); | ||
673 | } | ||
674 | $r = $sum % 10; | ||
675 | if($r > 0) { | ||
676 | $r = (10 - $r); | ||
677 | } | ||
678 | return $r; | ||
679 | } | ||
680 | |||
681 | /** | ||
682 | * MSI. | ||
683 | * Variation of Plessey code, with similar applications | ||
684 | * Contains digits (0 to 9) and encodes the data only in the width of bars. | ||
685 | */ | ||
686 | protected function barcode_msi($code, $checksum=false) { | ||
687 | $chr['0'] = '100100100100'; | ||
688 | $chr['1'] = '100100100110'; | ||
689 | $chr['2'] = '100100110100'; | ||
690 | $chr['3'] = '100100110110'; | ||
691 | $chr['4'] = '100110100100'; | ||
692 | $chr['5'] = '100110100110'; | ||
693 | $chr['6'] = '100110110100'; | ||
694 | $chr['7'] = '100110110110'; | ||
695 | $chr['8'] = '110100100100'; | ||
696 | $chr['9'] = '110100100110'; | ||
697 | $chr['A'] = '110100110100'; | ||
698 | $chr['B'] = '110100110110'; | ||
699 | $chr['C'] = '110110100100'; | ||
700 | $chr['D'] = '110110100110'; | ||
701 | $chr['E'] = '110110110100'; | ||
702 | $chr['F'] = '110110110110'; | ||
703 | if ($checksum) { | ||
704 | // add checksum | ||
705 | $clen = strlen($code); | ||
706 | $p = 2; | ||
707 | $check = 0; | ||
708 | for ($i = ($clen - 1); $i >= 0; --$i) { | ||
709 | $check += (hexdec($code[$i]) * $p); | ||
710 | ++$p; | ||
711 | if ($p > 7) { | ||
712 | $p = 2; | ||
713 | } | ||
714 | } | ||
715 | $check %= 11; | ||
716 | if ($check > 0) { | ||
717 | $check = 11 - $check; | ||
718 | } | ||
719 | $code .= $check; | ||
720 | $checkdigit = $check; | ||
721 | } | ||
722 | $seq = '110'; // left guard | ||
723 | $clen = strlen($code); | ||
724 | for ($i = 0; $i < $clen; ++$i) { | ||
725 | $digit = $code[$i]; | ||
726 | if (!isset($chr[$digit])) { | ||
727 | // invalid character | ||
728 | return false; | ||
729 | } | ||
730 | $seq .= $chr[$digit]; | ||
731 | } | ||
732 | $seq .= '1001'; // right guard | ||
733 | $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); | ||
734 | $bararray['checkdigit'] = $checkdigit; | ||
735 | return $this->binseq_to_array($seq, $bararray); | ||
736 | } | ||
737 | |||
738 | /** | ||
739 | * Standard 2 of 5 barcodes. | ||
740 | * Used in airline ticket marking, photofinishing | ||
741 | * Contains digits (0 to 9) and encodes the data only in the width of bars. | ||
742 | */ | ||
743 | protected function barcode_s25($code, $checksum=false) { | ||
744 | $chr['0'] = '10101110111010'; | ||
745 | $chr['1'] = '11101010101110'; | ||
746 | $chr['2'] = '10111010101110'; | ||
747 | $chr['3'] = '11101110101010'; | ||
748 | $chr['4'] = '10101110101110'; | ||
749 | $chr['5'] = '11101011101010'; | ||
750 | $chr['6'] = '10111011101010'; | ||
751 | $chr['7'] = '10101011101110'; | ||
752 | $chr['8'] = '10101110111010'; | ||
753 | $chr['9'] = '10111010111010'; | ||
754 | if ($checksum) { | ||
755 | // add checksum | ||
756 | $checkdigit = $this->checksum_s25($code); | ||
757 | $code .= $checkdigit ; | ||
758 | } | ||
759 | if((strlen($code) % 2) != 0) { | ||
760 | // add leading zero if code-length is odd | ||
761 | $code = '0'.$code; | ||
762 | } | ||
763 | $seq = '11011010'; | ||
764 | $clen = strlen($code); | ||
765 | for ($i = 0; $i < $clen; ++$i) { | ||
766 | $digit = $code[$i]; | ||
767 | if (!isset($chr[$digit])) { | ||
768 | // invalid character | ||
769 | return false; | ||
770 | } | ||
771 | $seq .= $chr[$digit]; | ||
772 | } | ||
773 | $seq .= '1101011'; | ||
774 | $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); | ||
775 | $bararray['checkdigit'] = $checkdigit; | ||
776 | return $this->binseq_to_array($seq, $bararray); | ||
777 | } | ||
778 | |||
779 | /** | ||
780 | * Convert binary barcode sequence to barcode array | ||
781 | */ | ||
782 | protected function binseq_to_array($seq, $bararray) { | ||
783 | $len = strlen($seq); | ||
784 | $w = 0; | ||
785 | $k = 0; | ||
786 | for ($i = 0; $i < $len; ++$i) { | ||
787 | $w += 1; | ||
788 | if (($i == ($len - 1)) OR (($i < ($len - 1)) AND ($seq[$i] != $seq[($i+1)]))) { | ||
789 | if ($seq[$i] == '1') { | ||
790 | $t = true; // bar | ||
791 | } else { | ||
792 | $t = false; // space | ||
793 | } | ||
794 | $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); | ||
795 | $bararray['maxw'] += $w; | ||
796 | ++$k; | ||
797 | $w = 0; | ||
798 | } | ||
799 | } | ||
800 | return $bararray; | ||
801 | } | ||
802 | |||
803 | /** | ||
804 | * Interleaved 2 of 5 barcodes. | ||
805 | * Compact numeric code, widely used in industry, air cargo | ||
806 | * Contains digits (0 to 9) and encodes the data in the width of both bars and spaces. | ||
807 | */ | ||
808 | protected function barcode_i25($code, $checksum=false) { | ||
809 | $chr['0'] = '11221'; | ||
810 | $chr['1'] = '21112'; | ||
811 | $chr['2'] = '12112'; | ||
812 | $chr['3'] = '22111'; | ||
813 | $chr['4'] = '11212'; | ||
814 | $chr['5'] = '21211'; | ||
815 | $chr['6'] = '12211'; | ||
816 | $chr['7'] = '11122'; | ||
817 | $chr['8'] = '21121'; | ||
818 | $chr['9'] = '12121'; | ||
819 | $chr['A'] = '11'; | ||
820 | $chr['Z'] = '21'; | ||
821 | if ($checksum) { | ||
822 | // add checksum | ||
823 | $checkdigit = $this->checksum_s25($code); | ||
824 | $code .= $checkdigit ; | ||
825 | } | ||
826 | if((strlen($code) % 2) != 0) { | ||
827 | // add leading zero if code-length is odd | ||
828 | $code = '0'.$code; | ||
829 | } | ||
830 | // add start and stop codes | ||
831 | $code = 'AA'.strtolower($code).'ZA'; | ||
832 | |||
833 | $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); | ||
834 | $k = 0; | ||
835 | $clen = strlen($code); | ||
836 | for ($i = 0; $i < $clen; $i = ($i + 2)) { | ||
837 | $char_bar = $code[$i]; | ||
838 | $char_space = $code[$i+1]; | ||
839 | if((!isset($chr[$char_bar])) OR (!isset($chr[$char_space]))) { | ||
840 | // invalid character | ||
841 | return false; | ||
842 | } | ||
843 | // create a bar-space sequence | ||
844 | $seq = ''; | ||
845 | $chrlen = strlen($chr[$char_bar]); | ||
846 | for ($s = 0; $s < $chrlen; $s++){ | ||
847 | $seq .= $chr[$char_bar][$s] . $chr[$char_space][$s]; | ||
848 | } | ||
849 | $seqlen = strlen($seq); | ||
850 | for ($j = 0; $j < $seqlen; ++$j) { | ||
851 | if (($j % 2) == 0) { | ||
852 | $t = true; // bar | ||
853 | } else { | ||
854 | $t = false; // space | ||
855 | } | ||
856 | $x = $seq[$j]; | ||
857 | if ($x == 2) { $w = $this->print_ratio; } | ||
858 | else { $w = 1; } | ||
859 | |||
860 | $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); | ||
861 | $bararray['maxw'] += $w; | ||
862 | ++$k; | ||
863 | } | ||
864 | } | ||
865 | $bararray['checkdigit'] = $checkdigit; | ||
866 | return $bararray; | ||
867 | } | ||
868 | |||
869 | /** | ||
870 | * C128 barcodes. | ||
871 | * Very capable code, excellent density, high reliability; in very wide use world-wide | ||
872 | */ | ||
873 | protected function barcode_c128($code, $type='B', $ean=false) { | ||
874 | $chr = array( | ||
875 | '212222', /* 00 */ | ||
876 | '222122', /* 01 */ | ||
877 | '222221', /* 02 */ | ||
878 | '121223', /* 03 */ | ||
879 | '121322', /* 04 */ | ||
880 | '131222', /* 05 */ | ||
881 | '122213', /* 06 */ | ||
882 | '122312', /* 07 */ | ||
883 | '132212', /* 08 */ | ||
884 | '221213', /* 09 */ | ||
885 | '221312', /* 10 */ | ||
886 | '231212', /* 11 */ | ||
887 | '112232', /* 12 */ | ||
888 | '122132', /* 13 */ | ||
889 | '122231', /* 14 */ | ||
890 | '113222', /* 15 */ | ||
891 | '123122', /* 16 */ | ||
892 | '123221', /* 17 */ | ||
893 | '223211', /* 18 */ | ||
894 | '221132', /* 19 */ | ||
895 | '221231', /* 20 */ | ||
896 | '213212', /* 21 */ | ||
897 | '223112', /* 22 */ | ||
898 | '312131', /* 23 */ | ||
899 | '311222', /* 24 */ | ||
900 | '321122', /* 25 */ | ||
901 | '321221', /* 26 */ | ||
902 | '312212', /* 27 */ | ||
903 | '322112', /* 28 */ | ||
904 | '322211', /* 29 */ | ||
905 | '212123', /* 30 */ | ||
906 | '212321', /* 31 */ | ||
907 | '232121', /* 32 */ | ||
908 | '111323', /* 33 */ | ||
909 | '131123', /* 34 */ | ||
910 | '131321', /* 35 */ | ||
911 | '112313', /* 36 */ | ||
912 | '132113', /* 37 */ | ||
913 | '132311', /* 38 */ | ||
914 | '211313', /* 39 */ | ||
915 | '231113', /* 40 */ | ||
916 | '231311', /* 41 */ | ||
917 | '112133', /* 42 */ | ||
918 | '112331', /* 43 */ | ||
919 | '132131', /* 44 */ | ||
920 | '113123', /* 45 */ | ||
921 | '113321', /* 46 */ | ||
922 | '133121', /* 47 */ | ||
923 | '313121', /* 48 */ | ||
924 | '211331', /* 49 */ | ||
925 | '231131', /* 50 */ | ||
926 | '213113', /* 51 */ | ||
927 | '213311', /* 52 */ | ||
928 | '213131', /* 53 */ | ||
929 | '311123', /* 54 */ | ||
930 | '311321', /* 55 */ | ||
931 | '331121', /* 56 */ | ||
932 | '312113', /* 57 */ | ||
933 | '312311', /* 58 */ | ||
934 | '332111', /* 59 */ | ||
935 | '314111', /* 60 */ | ||
936 | '221411', /* 61 */ | ||
937 | '431111', /* 62 */ | ||
938 | '111224', /* 63 */ | ||
939 | '111422', /* 64 */ | ||
940 | '121124', /* 65 */ | ||
941 | '121421', /* 66 */ | ||
942 | '141122', /* 67 */ | ||
943 | '141221', /* 68 */ | ||
944 | '112214', /* 69 */ | ||
945 | '112412', /* 70 */ | ||
946 | '122114', /* 71 */ | ||
947 | '122411', /* 72 */ | ||
948 | '142112', /* 73 */ | ||
949 | '142211', /* 74 */ | ||
950 | '241211', /* 75 */ | ||
951 | '221114', /* 76 */ | ||
952 | '413111', /* 77 */ | ||
953 | '241112', /* 78 */ | ||
954 | '134111', /* 79 */ | ||
955 | '111242', /* 80 */ | ||
956 | '121142', /* 81 */ | ||
957 | '121241', /* 82 */ | ||
958 | '114212', /* 83 */ | ||
959 | '124112', /* 84 */ | ||
960 | '124211', /* 85 */ | ||
961 | '411212', /* 86 */ | ||
962 | '421112', /* 87 */ | ||
963 | '421211', /* 88 */ | ||
964 | '212141', /* 89 */ | ||
965 | '214121', /* 90 */ | ||
966 | '412121', /* 91 */ | ||
967 | '111143', /* 92 */ | ||
968 | '111341', /* 93 */ | ||
969 | '131141', /* 94 */ | ||
970 | '114113', /* 95 */ | ||
971 | '114311', /* 96 */ | ||
972 | '411113', /* 97 */ | ||
973 | '411311', /* 98 */ | ||
974 | '113141', /* 99 */ | ||
975 | '114131', /* 100 */ | ||
976 | '311141', /* 101 */ | ||
977 | '411131', /* 102 */ | ||
978 | '211412', /* 103 START A */ | ||
979 | '211214', /* 104 START B */ | ||
980 | '211232', /* 105 START C */ | ||
981 | '233111', /* STOP */ | ||
982 | '200000' /* END */ | ||
983 | ); | ||
984 | $keys = ''; | ||
985 | switch(strtoupper($type)) { | ||
986 | case 'A': { | ||
987 | $startid = 103; | ||
988 | $keys = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_'; | ||
989 | for ($i = 0; $i < 32; ++$i) { | ||
990 | $keys .= chr($i); | ||
991 | } | ||
992 | break; | ||
993 | } | ||
994 | case 'B': { | ||
995 | $startid = 104; | ||
996 | $keys = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'.chr(127); | ||
997 | break; | ||
998 | } | ||
999 | case 'C': { | ||
1000 | $startid = 105; | ||
1001 | $keys = ''; | ||
1002 | if ((strlen($code) % 2) != 0) { | ||
1003 | // The length of barcode value must be even ($code). You must pad the number with zeros | ||
1004 | return false; | ||
1005 | } | ||
1006 | for ($i = 0; $i <= 99; ++$i) { | ||
1007 | $keys .= chr($i); | ||
1008 | } | ||
1009 | $new_code = ''; | ||
1010 | $hclen = (strlen($code) / 2); | ||
1011 | for ($i = 0; $i < $hclen; ++$i) { | ||
1012 | $new_code .= chr(intval($code{(2 * $i)}.$code{(2 * $i + 1)})); | ||
1013 | } | ||
1014 | $code = $new_code; | ||
1015 | break; | ||
1016 | } | ||
1017 | default: { | ||
1018 | return false; | ||
1019 | } | ||
1020 | } | ||
1021 | |||
1022 | // calculate check character | ||
1023 | $sum = $startid; | ||
1024 | if ($ean) { $code = chr(102) . $code; } // Add FNC 1 - which identifies it as EAN-128 | ||
1025 | $clen = strlen($code); | ||
1026 | for ($i = 0; $i < $clen; ++$i) { | ||
1027 | if ($ean && $i==0) { $sum += 102; } | ||
1028 | else { $sum += (strpos($keys, $code[$i]) * ($i+1)); } | ||
1029 | } | ||
1030 | $check = ($sum % 103); | ||
1031 | $checkdigit = $check ; | ||
1032 | // add start, check and stop codes | ||
1033 | $code = chr($startid).$code.chr($check).chr(106).chr(107); | ||
1034 | $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); | ||
1035 | $k = 0; | ||
1036 | $len = strlen($code); | ||
1037 | for ($i = 0; $i < $len; ++$i) { | ||
1038 | $ck = strpos($keys, $code[$i]); | ||
1039 | if (($i == 0) || ($ean && $i==1) | ($i > ($len-4))) { | ||
1040 | $char_num = ord($code[$i]); | ||
1041 | $seq = $chr[$char_num]; | ||
1042 | } elseif(($ck >= 0) AND isset($chr[$ck])) { | ||
1043 | $seq = $chr[$ck]; | ||
1044 | } else { | ||
1045 | // invalid character | ||
1046 | return false; | ||
1047 | } | ||
1048 | for ($j = 0; $j < 6; ++$j) { | ||
1049 | if (($j % 2) == 0) { | ||
1050 | $t = true; // bar | ||
1051 | } else { | ||
1052 | $t = false; // space | ||
1053 | } | ||
1054 | $w = $seq[$j]; | ||
1055 | $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); | ||
1056 | $bararray['maxw'] += $w; | ||
1057 | ++$k; | ||
1058 | } | ||
1059 | } | ||
1060 | $bararray['checkdigit'] = $checkdigit; | ||
1061 | return $bararray; | ||
1062 | } | ||
1063 | |||
1064 | /** | ||
1065 | * EAN13 and UPC-A barcodes. | ||
1066 | * EAN13: European Article Numbering international retail product code | ||
1067 | * UPC-A: Universal product code seen on almost all retail products in the USA and Canada | ||
1068 | * UPC-E: Short version of UPC symbol | ||
1069 | */ | ||
1070 | protected function barcode_eanupc($code, $len=13) { | ||
1071 | $upce = false; | ||
1072 | $checkdigit = false; | ||
1073 | if ($len == 6) { | ||
1074 | $len = 12; // UPC-A | ||
1075 | $upce = true; // UPC-E mode | ||
1076 | } | ||
1077 | $data_len = $len - 1; | ||
1078 | //Padding | ||
1079 | $code = str_pad($code, $data_len, '0', STR_PAD_LEFT); | ||
1080 | $code_len = strlen($code); | ||
1081 | // calculate check digit | ||
1082 | $sum_a = 0; | ||
1083 | for ($i = 1; $i < $data_len; $i+=2) { | ||
1084 | $sum_a += $code[$i]; | ||
1085 | } | ||
1086 | if ($len > 12) { | ||
1087 | $sum_a *= 3; | ||
1088 | } | ||
1089 | $sum_b = 0; | ||
1090 | for ($i = 0; $i < $data_len; $i+=2) { | ||
1091 | $sum_b += ($code[$i]); | ||
1092 | } | ||
1093 | if ($len < 13) { | ||
1094 | $sum_b *= 3; | ||
1095 | } | ||
1096 | $r = ($sum_a + $sum_b) % 10; | ||
1097 | if($r > 0) { | ||
1098 | $r = (10 - $r); | ||
1099 | } | ||
1100 | if ($code_len == $data_len) { | ||
1101 | // add check digit | ||
1102 | $code .= $r; | ||
1103 | $checkdigit = $r; | ||
1104 | } elseif ($r !== intval($code[$data_len])) { | ||
1105 | // wrong checkdigit | ||
1106 | return false; | ||
1107 | } | ||
1108 | if ($len == 12) { | ||
1109 | // UPC-A | ||
1110 | $code = '0'.$code; | ||
1111 | ++$len; | ||
1112 | } | ||
1113 | if ($upce) { | ||
1114 | // convert UPC-A to UPC-E | ||
1115 | $tmp = substr($code, 4, 3); | ||
1116 | $prod_code = intval(substr($code,7,5)); // product code | ||
1117 | $invalid_upce = false; | ||
1118 | if (($tmp == '000') OR ($tmp == '100') OR ($tmp == '200')) { | ||
1119 | // manufacturer code ends in 000, 100, or 200 | ||
1120 | $upce_code = substr($code, 2, 2).substr($code, 9, 3).substr($code, 4, 1); | ||
1121 | if ($prod_code > 999) { $invalid_upce = true; } | ||
1122 | } else { | ||
1123 | $tmp = substr($code, 5, 2); | ||
1124 | if ($tmp == '00') { | ||
1125 | // manufacturer code ends in 00 | ||
1126 | $upce_code = substr($code, 2, 3).substr($code, 10, 2).'3'; | ||
1127 | if ($prod_code > 99) { $invalid_upce = true; } | ||
1128 | } else { | ||
1129 | $tmp = substr($code, 6, 1); | ||
1130 | if ($tmp == '0') { | ||
1131 | // manufacturer code ends in 0 | ||
1132 | $upce_code = substr($code, 2, 4).substr($code, 11, 1).'4'; | ||
1133 | if ($prod_code > 9) { $invalid_upce = true; } | ||
1134 | } else { | ||
1135 | // manufacturer code does not end in zero | ||
1136 | $upce_code = substr($code, 2, 5).substr($code, 11, 1); | ||
1137 | if ($prod_code > 9) { $invalid_upce = true; } | ||
1138 | } | ||
1139 | } | ||
1140 | } | ||
1141 | if ($invalid_upce) { die("Error - UPC-A cannot produce a valid UPC-E barcode"); } // Error generating a UPCE code | ||
1142 | } | ||
1143 | //Convert digits to bars | ||
1144 | $codes = array( | ||
1145 | 'A'=>array( // left odd parity | ||
1146 | '0'=>'0001101', | ||
1147 | '1'=>'0011001', | ||
1148 | '2'=>'0010011', | ||
1149 | '3'=>'0111101', | ||
1150 | '4'=>'0100011', | ||
1151 | '5'=>'0110001', | ||
1152 | '6'=>'0101111', | ||
1153 | '7'=>'0111011', | ||
1154 | '8'=>'0110111', | ||
1155 | '9'=>'0001011'), | ||
1156 | 'B'=>array( // left even parity | ||
1157 | '0'=>'0100111', | ||
1158 | '1'=>'0110011', | ||
1159 | '2'=>'0011011', | ||
1160 | '3'=>'0100001', | ||
1161 | '4'=>'0011101', | ||
1162 | '5'=>'0111001', | ||
1163 | '6'=>'0000101', | ||
1164 | '7'=>'0010001', | ||
1165 | '8'=>'0001001', | ||
1166 | '9'=>'0010111'), | ||
1167 | 'C'=>array( // right | ||
1168 | '0'=>'1110010', | ||
1169 | '1'=>'1100110', | ||
1170 | '2'=>'1101100', | ||
1171 | '3'=>'1000010', | ||
1172 | '4'=>'1011100', | ||
1173 | '5'=>'1001110', | ||
1174 | '6'=>'1010000', | ||
1175 | '7'=>'1000100', | ||
1176 | '8'=>'1001000', | ||
1177 | '9'=>'1110100') | ||
1178 | ); | ||
1179 | $parities = array( | ||
1180 | '0'=>array('A','A','A','A','A','A'), | ||
1181 | '1'=>array('A','A','B','A','B','B'), | ||
1182 | '2'=>array('A','A','B','B','A','B'), | ||
1183 | '3'=>array('A','A','B','B','B','A'), | ||
1184 | '4'=>array('A','B','A','A','B','B'), | ||
1185 | '5'=>array('A','B','B','A','A','B'), | ||
1186 | '6'=>array('A','B','B','B','A','A'), | ||
1187 | '7'=>array('A','B','A','B','A','B'), | ||
1188 | '8'=>array('A','B','A','B','B','A'), | ||
1189 | '9'=>array('A','B','B','A','B','A') | ||
1190 | ); | ||
1191 | $upce_parities = array(); | ||
1192 | $upce_parities[0] = array( | ||
1193 | '0'=>array('B','B','B','A','A','A'), | ||
1194 | '1'=>array('B','B','A','B','A','A'), | ||
1195 | '2'=>array('B','B','A','A','B','A'), | ||
1196 | '3'=>array('B','B','A','A','A','B'), | ||
1197 | '4'=>array('B','A','B','B','A','A'), | ||
1198 | '5'=>array('B','A','A','B','B','A'), | ||
1199 | '6'=>array('B','A','A','A','B','B'), | ||
1200 | '7'=>array('B','A','B','A','B','A'), | ||
1201 | '8'=>array('B','A','B','A','A','B'), | ||
1202 | '9'=>array('B','A','A','B','A','B') | ||
1203 | ); | ||
1204 | $upce_parities[1] = array( | ||
1205 | '0'=>array('A','A','A','B','B','B'), | ||
1206 | '1'=>array('A','A','B','A','B','B'), | ||
1207 | '2'=>array('A','A','B','B','A','B'), | ||
1208 | '3'=>array('A','A','B','B','B','A'), | ||
1209 | '4'=>array('A','B','A','A','B','B'), | ||
1210 | '5'=>array('A','B','B','A','A','B'), | ||
1211 | '6'=>array('A','B','B','B','A','A'), | ||
1212 | '7'=>array('A','B','A','B','A','B'), | ||
1213 | '8'=>array('A','B','A','B','B','A'), | ||
1214 | '9'=>array('A','B','B','A','B','A') | ||
1215 | ); | ||
1216 | $k = 0; | ||
1217 | $seq = '101'; // left guard bar | ||
1218 | if ($upce) { | ||
1219 | $bararray = array('code' => $upce_code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); | ||
1220 | $p = $upce_parities[$code{1}][$r]; | ||
1221 | for ($i = 0; $i < 6; ++$i) { | ||
1222 | $seq .= $codes[$p[$i]][$upce_code[$i]]; | ||
1223 | } | ||
1224 | $seq .= '010101'; // right guard bar | ||
1225 | } else { | ||
1226 | $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); | ||
1227 | $half_len = ceil($len / 2); | ||
1228 | if ($len == 8) { | ||
1229 | for ($i = 0; $i < $half_len; ++$i) { | ||
1230 | $seq .= $codes['A'][$code[$i]]; | ||
1231 | } | ||
1232 | } else { | ||
1233 | $p = $parities[$code{0}]; | ||
1234 | for ($i = 1; $i < $half_len; ++$i) { | ||
1235 | $seq .= $codes[$p[$i-1]][$code[$i]]; | ||
1236 | } | ||
1237 | } | ||
1238 | $seq .= '01010'; // center guard bar | ||
1239 | for ($i = $half_len; $i < $len; ++$i) { | ||
1240 | $seq .= $codes['C'][$code[$i]]; | ||
1241 | } | ||
1242 | $seq .= '101'; // right guard bar | ||
1243 | } | ||
1244 | $clen = strlen($seq); | ||
1245 | $w = 0; | ||
1246 | for ($i = 0; $i < $clen; ++$i) { | ||
1247 | $w += 1; | ||
1248 | if (($i == ($clen - 1)) OR (($i < ($clen - 1)) AND ($seq[$i] != $seq[($i+1)]))) { | ||
1249 | if ($seq[$i] == '1') { | ||
1250 | $t = true; // bar | ||
1251 | } else { | ||
1252 | $t = false; // space | ||
1253 | } | ||
1254 | $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); | ||
1255 | $bararray['maxw'] += $w; | ||
1256 | ++$k; | ||
1257 | $w = 0; | ||
1258 | } | ||
1259 | } | ||
1260 | $bararray['checkdigit'] = $checkdigit; | ||
1261 | return $bararray; | ||
1262 | } | ||
1263 | |||
1264 | /** | ||
1265 | * UPC-Based Extentions | ||
1266 | * 2-Digit Ext.: Used to indicate magazines and newspaper issue numbers | ||
1267 | * 5-Digit Ext.: Used to mark suggested retail price of books | ||
1268 | */ | ||
1269 | protected function barcode_eanext($code, $len=5) { | ||
1270 | //Padding | ||
1271 | $code = str_pad($code, $len, '0', STR_PAD_LEFT); | ||
1272 | // calculate check digit | ||
1273 | if ($len == 2) { | ||
1274 | $r = $code % 4; | ||
1275 | } elseif ($len == 5) { | ||
1276 | $r = (3 * ($code{0} + $code{2} + $code{4})) + (9 * ($code{1} + $code{3})); | ||
1277 | $r %= 10; | ||
1278 | } else { | ||
1279 | return false; | ||
1280 | } | ||
1281 | //Convert digits to bars | ||
1282 | $codes = array( | ||
1283 | 'A'=>array( // left odd parity | ||
1284 | '0'=>'0001101', | ||
1285 | '1'=>'0011001', | ||
1286 | '2'=>'0010011', | ||
1287 | '3'=>'0111101', | ||
1288 | '4'=>'0100011', | ||
1289 | '5'=>'0110001', | ||
1290 | '6'=>'0101111', | ||
1291 | '7'=>'0111011', | ||
1292 | '8'=>'0110111', | ||
1293 | '9'=>'0001011'), | ||
1294 | 'B'=>array( // left even parity | ||
1295 | '0'=>'0100111', | ||
1296 | '1'=>'0110011', | ||
1297 | '2'=>'0011011', | ||
1298 | '3'=>'0100001', | ||
1299 | '4'=>'0011101', | ||
1300 | '5'=>'0111001', | ||
1301 | '6'=>'0000101', | ||
1302 | '7'=>'0010001', | ||
1303 | '8'=>'0001001', | ||
1304 | '9'=>'0010111') | ||
1305 | ); | ||
1306 | $parities = array(); | ||
1307 | $parities[2] = array( | ||
1308 | '0'=>array('A','A'), | ||
1309 | '1'=>array('A','B'), | ||
1310 | '2'=>array('B','A'), | ||
1311 | '3'=>array('B','B') | ||
1312 | ); | ||
1313 | $parities[5] = array( | ||
1314 | '0'=>array('B','B','A','A','A'), | ||
1315 | '1'=>array('B','A','B','A','A'), | ||
1316 | '2'=>array('B','A','A','B','A'), | ||
1317 | '3'=>array('B','A','A','A','B'), | ||
1318 | '4'=>array('A','B','B','A','A'), | ||
1319 | '5'=>array('A','A','B','B','A'), | ||
1320 | '6'=>array('A','A','A','B','B'), | ||
1321 | '7'=>array('A','B','A','B','A'), | ||
1322 | '8'=>array('A','B','A','A','B'), | ||
1323 | '9'=>array('A','A','B','A','B') | ||
1324 | ); | ||
1325 | $p = $parities[$len][$r]; | ||
1326 | $seq = '1011'; // left guard bar | ||
1327 | $seq .= $codes[$p[0]][$code{0}]; | ||
1328 | for ($i = 1; $i < $len; ++$i) { | ||
1329 | $seq .= '01'; // separator | ||
1330 | $seq .= $codes[$p[$i]][$code[$i]]; | ||
1331 | } | ||
1332 | $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); | ||
1333 | return $this->binseq_to_array($seq, $bararray); | ||
1334 | } | ||
1335 | |||
1336 | /** | ||
1337 | * POSTNET and PLANET barcodes. | ||
1338 | * Used by U.S. Postal Service for automated mail sorting | ||
1339 | */ | ||
1340 | protected function barcode_postnet($code, $planet=false) { | ||
1341 | // bar lenght | ||
1342 | if ($planet) { | ||
1343 | $barlen = Array( | ||
1344 | 0 => Array(1,1,2,2,2), | ||
1345 | 1 => Array(2,2,2,1,1), | ||
1346 | 2 => Array(2,2,1,2,1), | ||
1347 | 3 => Array(2,2,1,1,2), | ||
1348 | 4 => Array(2,1,2,2,1), | ||
1349 | 5 => Array(2,1,2,1,2), | ||
1350 | 6 => Array(2,1,1,2,2), | ||
1351 | 7 => Array(1,2,2,2,1), | ||
1352 | 8 => Array(1,2,2,1,2), | ||
1353 | 9 => Array(1,2,1,2,2) | ||
1354 | ); | ||
1355 | } else { | ||
1356 | $barlen = Array( | ||
1357 | 0 => Array(2,2,1,1,1), | ||
1358 | 1 => Array(1,1,1,2,2), | ||
1359 | 2 => Array(1,1,2,1,2), | ||
1360 | 3 => Array(1,1,2,2,1), | ||
1361 | 4 => Array(1,2,1,1,2), | ||
1362 | 5 => Array(1,2,1,2,1), | ||
1363 | 6 => Array(1,2,2,1,1), | ||
1364 | 7 => Array(2,1,1,1,2), | ||
1365 | 8 => Array(2,1,1,2,1), | ||
1366 | 9 => Array(2,1,2,1,1) | ||
1367 | ); | ||
1368 | } | ||
1369 | $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 5, 'bcode' => array()); | ||
1370 | $k = 0; | ||
1371 | $code = str_replace('-', '', $code); | ||
1372 | $code = str_replace(' ', '', $code); | ||
1373 | $len = strlen($code); | ||
1374 | // calculate checksum | ||
1375 | $sum = 0; | ||
1376 | for ($i = 0; $i < $len; ++$i) { | ||
1377 | $sum += intval($code[$i]); | ||
1378 | } | ||
1379 | $chkd = ($sum % 10); | ||
1380 | if($chkd > 0) { | ||
1381 | $chkd = (10 - $chkd); | ||
1382 | } | ||
1383 | $code .= $chkd; | ||
1384 | $checkdigit = $chkd; | ||
1385 | $len = strlen($code); | ||
1386 | // start bar | ||
1387 | $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 5, 'p' => 0); | ||
1388 | $bararray['bcode'][$k++] = array('t' => 0, 'w' => $this->gapwidth , 'h' => 5, 'p' => 0); | ||
1389 | $bararray['maxw'] += (1 + $this->gapwidth ); | ||
1390 | for ($i = 0; $i < $len; ++$i) { | ||
1391 | for ($j = 0; $j < 5; ++$j) { | ||
1392 | $bh = $barlen[$code[$i]][$j]; | ||
1393 | if ($bh == 2) { | ||
1394 | $h = 5; | ||
1395 | $p = 0; | ||
1396 | } | ||
1397 | else { | ||
1398 | $h = 2; | ||
1399 | $p = 3; | ||
1400 | } | ||
1401 | $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p); | ||
1402 | $bararray['bcode'][$k++] = array('t' => 0, 'w' => $this->gapwidth , 'h' => 2, 'p' => 0); | ||
1403 | $bararray['maxw'] += (1 + $this->gapwidth ); | ||
1404 | } | ||
1405 | } | ||
1406 | // end bar | ||
1407 | $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 5, 'p' => 0); | ||
1408 | $bararray['maxw'] += 1; | ||
1409 | $bararray['checkdigit'] = $checkdigit; | ||
1410 | return $bararray; | ||
1411 | } | ||
1412 | |||
1413 | /** | ||
1414 | * RM4SCC - CBC - KIX | ||
1415 | * RM4SCC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code) - KIX (Klant index - Customer index) | ||
1416 | * RM4SCC is the name of the barcode symbology used by the Royal Mail for its Cleanmail service. | ||
1417 | */ | ||
1418 | protected function barcode_rm4scc($code, $kix=false) { | ||
1419 | $notkix = !$kix; | ||
1420 | // bar mode | ||
1421 | // 1 = pos 1, length 2 | ||
1422 | // 2 = pos 1, length 3 | ||
1423 | // 3 = pos 2, length 1 | ||
1424 | // 4 = pos 2, length 2 | ||
1425 | $barmode = array( | ||
1426 | '0' => array(3,3,2,2), | ||
1427 | '1' => array(3,4,1,2), | ||
1428 | '2' => array(3,4,2,1), | ||
1429 | '3' => array(4,3,1,2), | ||
1430 | '4' => array(4,3,2,1), | ||
1431 | '5' => array(4,4,1,1), | ||
1432 | '6' => array(3,1,4,2), | ||
1433 | '7' => array(3,2,3,2), | ||
1434 | '8' => array(3,2,4,1), | ||
1435 | '9' => array(4,1,3,2), | ||
1436 | 'A' => array(4,1,4,1), | ||
1437 | 'B' => array(4,2,3,1), | ||
1438 | 'C' => array(3,1,2,4), | ||
1439 | 'D' => array(3,2,1,4), | ||
1440 | 'E' => array(3,2,2,3), | ||
1441 | 'F' => array(4,1,1,4), | ||
1442 | 'G' => array(4,1,2,3), | ||
1443 | 'H' => array(4,2,1,3), | ||
1444 | 'I' => array(1,3,4,2), | ||
1445 | 'J' => array(1,4,3,2), | ||
1446 | 'K' => array(1,4,4,1), | ||
1447 | 'L' => array(2,3,3,2), | ||
1448 | 'M' => array(2,3,4,1), | ||
1449 | 'N' => array(2,4,3,1), | ||
1450 | 'O' => array(1,3,2,4), | ||
1451 | 'P' => array(1,4,1,4), | ||
1452 | 'Q' => array(1,4,2,3), | ||
1453 | 'R' => array(2,3,1,4), | ||
1454 | 'S' => array(2,3,2,3), | ||
1455 | 'T' => array(2,4,1,3), | ||
1456 | 'U' => array(1,1,4,4), | ||
1457 | 'V' => array(1,2,3,4), | ||
1458 | 'W' => array(1,2,4,3), | ||
1459 | 'X' => array(2,1,3,4), | ||
1460 | 'Y' => array(2,1,4,3), | ||
1461 | 'Z' => array(2,2,3,3) | ||
1462 | ); | ||
1463 | $code = strtoupper($code); | ||
1464 | $len = strlen($code); | ||
1465 | $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => $this->daft['F'], 'bcode' => array()); | ||
1466 | if ($notkix) { | ||
1467 | // table for checksum calculation (row,col) | ||
1468 | $checktable = array( | ||
1469 | '0' => array(1,1), | ||
1470 | '1' => array(1,2), | ||
1471 | '2' => array(1,3), | ||
1472 | '3' => array(1,4), | ||
1473 | '4' => array(1,5), | ||
1474 | '5' => array(1,0), | ||
1475 | '6' => array(2,1), | ||
1476 | '7' => array(2,2), | ||
1477 | '8' => array(2,3), | ||
1478 | '9' => array(2,4), | ||
1479 | 'A' => array(2,5), | ||
1480 | 'B' => array(2,0), | ||
1481 | 'C' => array(3,1), | ||
1482 | 'D' => array(3,2), | ||
1483 | 'E' => array(3,3), | ||
1484 | 'F' => array(3,4), | ||
1485 | 'G' => array(3,5), | ||
1486 | 'H' => array(3,0), | ||
1487 | 'I' => array(4,1), | ||
1488 | 'J' => array(4,2), | ||
1489 | 'K' => array(4,3), | ||
1490 | 'L' => array(4,4), | ||
1491 | 'M' => array(4,5), | ||
1492 | 'N' => array(4,0), | ||
1493 | 'O' => array(5,1), | ||
1494 | 'P' => array(5,2), | ||
1495 | 'Q' => array(5,3), | ||
1496 | 'R' => array(5,4), | ||
1497 | 'S' => array(5,5), | ||
1498 | 'T' => array(5,0), | ||
1499 | 'U' => array(0,1), | ||
1500 | 'V' => array(0,2), | ||
1501 | 'W' => array(0,3), | ||
1502 | 'X' => array(0,4), | ||
1503 | 'Y' => array(0,5), | ||
1504 | 'Z' => array(0,0) | ||
1505 | ); | ||
1506 | $row = 0; | ||
1507 | $col = 0; | ||
1508 | for ($i = 0; $i < $len; ++$i) { | ||
1509 | $row += $checktable[$code[$i]][0]; | ||
1510 | $col += $checktable[$code[$i]][1]; | ||
1511 | } | ||
1512 | $row %= 6; | ||
1513 | $col %= 6; | ||
1514 | $chk = array_keys($checktable, array($row,$col)); | ||
1515 | $code .= $chk[0]; | ||
1516 | $bararray['checkdigit'] = $chk[0]; | ||
1517 | ++$len; | ||
1518 | } | ||
1519 | $k = 0; | ||
1520 | if ($notkix) { | ||
1521 | // start bar | ||
1522 | $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $this->daft['A'] , 'p' => 0); | ||
1523 | $bararray['bcode'][$k++] = array('t' => 0, 'w' => $this->gapwidth , 'h' => $this->daft['A'] , 'p' => 0); | ||
1524 | $bararray['maxw'] += (1 + $this->gapwidth) ; | ||
1525 | } | ||
1526 | for ($i = 0; $i < $len; ++$i) { | ||
1527 | for ($j = 0; $j < 4; ++$j) { | ||
1528 | switch ($barmode[$code[$i]][$j]) { | ||
1529 | case 1: { | ||
1530 | // ascender (A) | ||
1531 | $p = 0; | ||
1532 | $h = $this->daft['A']; | ||
1533 | break; | ||
1534 | } | ||
1535 | case 2: { | ||
1536 | // full bar (F) | ||
1537 | $p = 0; | ||
1538 | $h = $this->daft['F']; | ||
1539 | break; | ||
1540 | } | ||
1541 | case 3: { | ||
1542 | // tracker (T) | ||
1543 | $p = ($this->daft['F'] - $this->daft['T'])/2; | ||
1544 | $h = $this->daft['T']; | ||
1545 | break; | ||
1546 | } | ||
1547 | case 4: { | ||
1548 | // descender (D) | ||
1549 | $p = $this->daft['F'] - $this->daft['D']; | ||
1550 | $h = $this->daft['D']; | ||
1551 | break; | ||
1552 | } | ||
1553 | } | ||
1554 | |||
1555 | $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p); | ||
1556 | $bararray['bcode'][$k++] = array('t' => 0, 'w' => $this->gapwidth, 'h' => 2, 'p' => 0); | ||
1557 | $bararray['maxw'] += (1 + $this->gapwidth) ; | ||
1558 | } | ||
1559 | } | ||
1560 | if ($notkix) { | ||
1561 | // stop bar | ||
1562 | $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $this->daft['F'], 'p' => 0); | ||
1563 | $bararray['maxw'] += 1; | ||
1564 | } | ||
1565 | return $bararray; | ||
1566 | } | ||
1567 | |||
1568 | /** | ||
1569 | * CODABAR barcodes. | ||
1570 | * Older code often used in library systems, sometimes in blood banks | ||
1571 | */ | ||
1572 | protected function barcode_codabar($code) { | ||
1573 | $chr = array( | ||
1574 | '0' => '11111221', | ||
1575 | '1' => '11112211', | ||
1576 | '2' => '11121121', | ||
1577 | '3' => '22111111', | ||
1578 | '4' => '11211211', | ||
1579 | '5' => '21111211', | ||
1580 | '6' => '12111121', | ||
1581 | '7' => '12112111', | ||
1582 | '8' => '12211111', | ||
1583 | '9' => '21121111', | ||
1584 | '-' => '11122111', | ||
1585 | '$' => '11221111', | ||
1586 | ':' => '21112121', | ||
1587 | '/' => '21211121', | ||
1588 | '.' => '21212111', | ||
1589 | '+' => '11222221', | ||
1590 | 'A' => '11221211', | ||
1591 | 'B' => '12121121', | ||
1592 | 'C' => '11121221', | ||
1593 | 'D' => '11122211' | ||
1594 | ); | ||
1595 | $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); | ||
1596 | $k = 0; | ||
1597 | $w = 0; | ||
1598 | $seq = ''; | ||
1599 | $code = strtoupper($code); | ||
1600 | $len = strlen($code); | ||
1601 | for ($i = 0; $i < $len; ++$i) { | ||
1602 | if (!isset($chr[$code[$i]])) { | ||
1603 | return false; | ||
1604 | } | ||
1605 | $seq = $chr[$code[$i]]; | ||
1606 | for ($j = 0; $j < 8; ++$j) { | ||
1607 | if (($j % 2) == 0) { | ||
1608 | $t = true; // bar | ||
1609 | } else { | ||
1610 | $t = false; // space | ||
1611 | } | ||
1612 | $x = $seq[$j]; | ||
1613 | if ($x == 2) { $w = $this->print_ratio; } | ||
1614 | else { $w = 1; } | ||
1615 | $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); | ||
1616 | $bararray['maxw'] += $w; | ||
1617 | ++$k; | ||
1618 | } | ||
1619 | } | ||
1620 | return $bararray; | ||
1621 | } | ||
1622 | |||
1623 | /** | ||
1624 | * CODE11 barcodes. | ||
1625 | * Used primarily for labeling telecommunications equipment | ||
1626 | */ | ||
1627 | protected function barcode_code11($code) { | ||
1628 | $chr = array( | ||
1629 | '0' => '111121', | ||
1630 | '1' => '211121', | ||
1631 | '2' => '121121', | ||
1632 | '3' => '221111', | ||
1633 | '4' => '112121', | ||
1634 | '5' => '212111', | ||
1635 | '6' => '122111', | ||
1636 | '7' => '111221', | ||
1637 | '8' => '211211', | ||
1638 | '9' => '211111', | ||
1639 | '-' => '112111', | ||
1640 | 'S' => '112211' | ||
1641 | ); | ||
1642 | |||
1643 | $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array()); | ||
1644 | $k = 0; | ||
1645 | $w = 0; | ||
1646 | $seq = ''; | ||
1647 | $len = strlen($code); | ||
1648 | // calculate check digit C | ||
1649 | $p = 1; | ||
1650 | $check = 0; | ||
1651 | for ($i = ($len - 1); $i >= 0; --$i) { | ||
1652 | $digit = $code[$i]; | ||
1653 | if ($digit == '-') { | ||
1654 | $dval = 10; | ||
1655 | } else { | ||
1656 | $dval = intval($digit); | ||
1657 | } | ||
1658 | $check += ($dval * $p); | ||
1659 | ++$p; | ||
1660 | if ($p > 10) { | ||
1661 | $p = 1; | ||
1662 | } | ||
1663 | } | ||
1664 | $check %= 11; | ||
1665 | if ($check == 10) { | ||
1666 | $check = '-'; | ||
1667 | } | ||
1668 | $code .= $check; | ||
1669 | $checkdigit = $check; | ||
1670 | if ($len > 10) { | ||
1671 | // calculate check digit K | ||
1672 | $p = 1; | ||
1673 | $check = 0; | ||
1674 | for ($i = $len; $i >= 0; --$i) { | ||
1675 | $digit = $code[$i]; | ||
1676 | if ($digit == '-') { | ||
1677 | $dval = 10; | ||
1678 | } else { | ||
1679 | $dval = intval($digit); | ||
1680 | } | ||
1681 | $check += ($dval * $p); | ||
1682 | ++$p; | ||
1683 | if ($p > 9) { | ||
1684 | $p = 1; | ||
1685 | } | ||
1686 | } | ||
1687 | $check %= 11; | ||
1688 | $code .= $check; | ||
1689 | $checkdigit .= $check; | ||
1690 | ++$len; | ||
1691 | } | ||
1692 | $code = 'S'.$code.'S'; | ||
1693 | $len += 3; | ||
1694 | for ($i = 0; $i < $len; ++$i) { | ||
1695 | if (!isset($chr[$code[$i]])) { | ||
1696 | return false; | ||
1697 | } | ||
1698 | $seq = $chr[$code[$i]]; | ||
1699 | for ($j = 0; $j < 6; ++$j) { | ||
1700 | if (($j % 2) == 0) { | ||
1701 | $t = true; // bar | ||
1702 | } else { | ||
1703 | $t = false; // space | ||
1704 | } | ||
1705 | $x = $seq[$j]; | ||
1706 | if ($x == 2) { $w = $this->print_ratio; } | ||
1707 | else { $w = 1; } | ||
1708 | $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0); | ||
1709 | $bararray['maxw'] += $w; | ||
1710 | ++$k; | ||
1711 | } | ||
1712 | } | ||
1713 | $bararray['checkdigit'] = $checkdigit; | ||
1714 | return $bararray; | ||
1715 | } | ||
1716 | |||
1717 | |||
1718 | /** | ||
1719 | * IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200 | ||
1720 | * (requires PHP bcmath extension) | ||
1721 | * Intelligent Mail barcode is a 65-bar code for use on mail in the United States. | ||
1722 | * 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 000-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> | ||
1723 | */ | ||
1724 | protected function barcode_imb($code) { | ||
1725 | $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); | ||
1726 | $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); | ||
1727 | $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); | ||
1728 | $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); | ||
1729 | $code_arr = explode('-', $code); | ||
1730 | $tracking_number = $code_arr[0]; | ||
1731 | if (isset($code_arr[1])) { | ||
1732 | $routing_code = $code_arr[1]; | ||
1733 | } else { | ||
1734 | $routing_code = ''; | ||
1735 | } | ||
1736 | // Conversion of Routing Code | ||
1737 | switch (strlen($routing_code)) { | ||
1738 | case 0: { | ||
1739 | $binary_code = 0; | ||
1740 | break; | ||
1741 | } | ||
1742 | case 5: { | ||
1743 | $binary_code = bcadd($routing_code, '1'); | ||
1744 | break; | ||
1745 | } | ||
1746 | case 9: { | ||
1747 | $binary_code = bcadd($routing_code, '100001'); | ||
1748 | break; | ||
1749 | } | ||
1750 | case 11: { | ||
1751 | $binary_code = bcadd($routing_code, '1000100001'); | ||
1752 | break; | ||
1753 | } | ||
1754 | default: { | ||
1755 | return false; | ||
1756 | break; | ||
1757 | } | ||
1758 | } | ||
1759 | $binary_code = bcmul($binary_code, 10); | ||
1760 | $binary_code = bcadd($binary_code, $tracking_number{0}); | ||
1761 | $binary_code = bcmul($binary_code, 5); | ||
1762 | $binary_code = bcadd($binary_code, $tracking_number{1}); | ||
1763 | $binary_code .= substr($tracking_number, 2, 18); | ||
1764 | // convert to hexadecimal | ||
1765 | $binary_code = $this->dec_to_hex($binary_code); | ||
1766 | // pad to get 13 bytes | ||
1767 | $binary_code = str_pad($binary_code, 26, '0', STR_PAD_LEFT); | ||
1768 | // convert string to array of bytes | ||
1769 | $binary_code_arr = chunk_split($binary_code, 2, "\r"); | ||
1770 | $binary_code_arr = substr($binary_code_arr, 0, -1); | ||
1771 | $binary_code_arr = explode("\r", $binary_code_arr); | ||
1772 | // calculate frame check sequence | ||
1773 | $fcs = $this->imb_crc11fcs($binary_code_arr); | ||
1774 | // exclude first 2 bits from first byte | ||
1775 | $first_byte = sprintf('%2s', dechex((hexdec($binary_code_arr[0]) << 2) >> 2)); | ||
1776 | $binary_code_102bit = $first_byte.substr($binary_code, 2); | ||
1777 | // convert binary data to codewords | ||
1778 | $codewords = array(); | ||
1779 | $data = $this->hex_to_dec($binary_code_102bit); | ||
1780 | $codewords[0] = bcmod($data, 636) * 2; | ||
1781 | $data = bcdiv($data, 636); | ||
1782 | for ($i = 1; $i < 9; ++$i) { | ||
1783 | $codewords[$i] = bcmod($data, 1365); | ||
1784 | $data = bcdiv($data, 1365); | ||
1785 | } | ||
1786 | $codewords[9] = $data; | ||
1787 | if (($fcs >> 10) == 1) { | ||
1788 | $codewords[9] += 659; | ||
1789 | } | ||
1790 | // generate lookup tables | ||
1791 | $table2of13 = $this->imb_tables(2, 78); | ||
1792 | $table5of13 = $this->imb_tables(5, 1287); | ||
1793 | // convert codewords to characters | ||
1794 | $characters = array(); | ||
1795 | $bitmask = 512; | ||
1796 | foreach($codewords as $k => $val) { | ||
1797 | if ($val <= 1286) { | ||
1798 | $chrcode = $table5of13[$val]; | ||
1799 | } else { | ||
1800 | $chrcode = $table2of13[($val - 1287)]; | ||
1801 | } | ||
1802 | if (($fcs & $bitmask) > 0) { | ||
1803 | // bitwise invert | ||
1804 | $chrcode = ((~$chrcode) & 8191); | ||
1805 | } | ||
1806 | $characters[] = $chrcode; | ||
1807 | $bitmask /= 2; | ||
1808 | } | ||
1809 | $characters = array_reverse($characters); | ||
1810 | // build bars | ||
1811 | $k = 0; | ||
1812 | $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => $this->daft['F'], 'bcode' => array()); | ||
1813 | for ($i = 0; $i < 65; ++$i) { | ||
1814 | $asc = (($characters[$asc_chr[$i]] & pow(2, $asc_pos[$i])) > 0); | ||
1815 | $dsc = (($characters[$dsc_chr[$i]] & pow(2, $dsc_pos[$i])) > 0); | ||
1816 | if ($asc AND $dsc) { | ||
1817 | // full bar (F) | ||
1818 | $p = 0; | ||
1819 | $h = $this->daft['F']; | ||
1820 | } elseif ($asc) { | ||
1821 | // ascender (A) | ||
1822 | $p = 0; | ||
1823 | $h = $this->daft['A']; | ||
1824 | } elseif ($dsc) { | ||
1825 | // descender (D) | ||
1826 | $p = $this->daft['F'] - $this->daft['D']; | ||
1827 | $h = $this->daft['D']; | ||
1828 | } else { | ||
1829 | // tracker (T) | ||
1830 | $p = ($this->daft['F'] - $this->daft['T'])/2; | ||
1831 | $h = $this->daft['T']; | ||
1832 | } | ||
1833 | $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p); | ||
1834 | // Gap | ||
1835 | $bararray['bcode'][$k++] = array('t' => 0, 'w' => $this->gapwidth , 'h' => 1, 'p' => 0); | ||
1836 | $bararray['maxw'] += (1 + $this->gapwidth ); | ||
1837 | } | ||
1838 | unset($bararray['bcode'][($k - 1)]); | ||
1839 | $bararray['maxw'] -= $this->gapwidth ; | ||
1840 | return $bararray; | ||
1841 | } | ||
1842 | |||
1843 | /** | ||
1844 | * Convert large integer number to hexadecimal representation. | ||
1845 | * (requires PHP bcmath extension) | ||
1846 | */ | ||
1847 | public function dec_to_hex($number) { | ||
1848 | $i = 0; | ||
1849 | $hex = array(); | ||
1850 | if($number == 0) { | ||
1851 | return '00'; | ||
1852 | } | ||
1853 | while($number > 0) { | ||
1854 | if($number == 0) { | ||
1855 | array_push($hex, '0'); | ||
1856 | } else { | ||
1857 | array_push($hex, strtoupper(dechex(bcmod($number, '16')))); | ||
1858 | $number = bcdiv($number, '16', 0); | ||
1859 | } | ||
1860 | } | ||
1861 | $hex = array_reverse($hex); | ||
1862 | return implode($hex); | ||
1863 | } | ||
1864 | |||
1865 | /** | ||
1866 | * Convert large hexadecimal number to decimal representation (string). | ||
1867 | * (requires PHP bcmath extension) | ||
1868 | */ | ||
1869 | public function hex_to_dec($hex) { | ||
1870 | $dec = 0; | ||
1871 | $bitval = 1; | ||
1872 | $len = strlen($hex); | ||
1873 | for($pos = ($len - 1); $pos >= 0; --$pos) { | ||
1874 | $dec = bcadd($dec, bcmul(hexdec($hex[$pos]), $bitval)); | ||
1875 | $bitval = bcmul($bitval, 16); | ||
1876 | } | ||
1877 | return $dec; | ||
1878 | } | ||
1879 | |||
1880 | /** | ||
1881 | * Intelligent Mail Barcode calculation of Frame Check Sequence | ||
1882 | */ | ||
1883 | protected function imb_crc11fcs($code_arr) { | ||
1884 | $genpoly = 0x0F35; // generator polynomial | ||
1885 | $fcs = 0x07FF; // Frame Check Sequence | ||
1886 | // do most significant byte skipping the 2 most significant bits | ||
1887 | $data = hexdec($code_arr[0]) << 5; | ||
1888 | for ($bit = 2; $bit < 8; ++$bit) { | ||
1889 | if (($fcs ^ $data) & 0x400) { | ||
1890 | $fcs = ($fcs << 1) ^ $genpoly; | ||
1891 | } else { | ||
1892 | $fcs = ($fcs << 1); | ||
1893 | } | ||
1894 | $fcs &= 0x7FF; | ||
1895 | $data <<= 1; | ||
1896 | } | ||
1897 | // do rest of bytes | ||
1898 | for ($byte = 1; $byte < 13; ++$byte) { | ||
1899 | $data = hexdec($code_arr[$byte]) << 3; | ||
1900 | for ($bit = 0; $bit < 8; ++$bit) { | ||
1901 | if (($fcs ^ $data) & 0x400) { | ||
1902 | $fcs = ($fcs << 1) ^ $genpoly; | ||
1903 | } else { | ||
1904 | $fcs = ($fcs << 1); | ||
1905 | } | ||
1906 | $fcs &= 0x7FF; | ||
1907 | $data <<= 1; | ||
1908 | } | ||
1909 | } | ||
1910 | return $fcs; | ||
1911 | } | ||
1912 | |||
1913 | /** | ||
1914 | * Reverse unsigned short value | ||
1915 | */ | ||
1916 | protected function imb_reverse_us($num) { | ||
1917 | $rev = 0; | ||
1918 | for ($i = 0; $i < 16; ++$i) { | ||
1919 | $rev <<= 1; | ||
1920 | $rev |= ($num & 1); | ||
1921 | $num >>= 1; | ||
1922 | } | ||
1923 | return $rev; | ||
1924 | } | ||
1925 | |||
1926 | /** | ||
1927 | * generate Nof13 tables used for Intelligent Mail Barcode | ||
1928 | */ | ||
1929 | protected function imb_tables($n, $size) { | ||
1930 | $table = array(); | ||
1931 | $lli = 0; // LUT lower index | ||
1932 | $lui = $size - 1; // LUT upper index | ||
1933 | for ($count = 0; $count < 8192; ++$count) { | ||
1934 | $bit_count = 0; | ||
1935 | for ($bit_index = 0; $bit_index < 13; ++$bit_index) { | ||
1936 | $bit_count += intval(($count & (1 << $bit_index)) != 0); | ||
1937 | } | ||
1938 | // if we don't have the right number of bits on, go on to the next value | ||
1939 | if ($bit_count == $n) { | ||
1940 | $reverse = ($this->imb_reverse_us($count) >> 3); | ||
1941 | // if the reverse is less than count, we have already visited this pair before | ||
1942 | if ($reverse >= $count) { | ||
1943 | // If count is symmetric, place it at the first free slot from the end of the list. | ||
1944 | // 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 | ||
1945 | if ($reverse == $count) { | ||
1946 | $table[$lui] = $count; | ||
1947 | --$lui; | ||
1948 | } else { | ||
1949 | $table[$lli] = $count; | ||
1950 | ++$lli; | ||
1951 | $table[$lli] = $reverse; | ||
1952 | ++$lli; | ||
1953 | } | ||
1954 | } | ||
1955 | } | ||
1956 | } | ||
1957 | return $table; | ||
1958 | } | ||
1959 | |||
1960 | } // end of class | ||
1961 | |||
1962 | //============================================================+ | ||
1963 | // END OF FILE | ||
1964 | //============================================================+ | ||
1965 | ?> \ No newline at end of file | ||
diff --git a/inc/3rdparty/libraries/mpdf/classes/bmp.php b/inc/3rdparty/libraries/mpdf/classes/bmp.php new file mode 100644 index 00000000..896ced89 --- /dev/null +++ b/inc/3rdparty/libraries/mpdf/classes/bmp.php | |||
@@ -0,0 +1,248 @@ | |||
1 | <?php | ||
2 | |||
3 | class bmp { | ||
4 | |||
5 | var $mpdf = null; | ||
6 | |||
7 | function bmp(&$mpdf) { | ||
8 | $this->mpdf = $mpdf; | ||
9 | } | ||
10 | |||
11 | |||
12 | function _getBMPimage($data, $file) { | ||
13 | $info = array(); | ||
14 | // Adapted from script by Valentin Schmidt | ||
15 | // http://staff.dasdeck.de/valentin/fpdf/fpdf_bmp/ | ||
16 | $bfOffBits=$this->_fourbytes2int_le(substr($data,10,4)); | ||
17 | $width=$this->_fourbytes2int_le(substr($data,18,4)); | ||
18 | $height=$this->_fourbytes2int_le(substr($data,22,4)); | ||
19 | $flip = ($height<0); | ||
20 | if ($flip) $height =-$height; | ||
21 | $biBitCount=$this->_twobytes2int_le(substr($data,28,2)); | ||
22 | $biCompression=$this->_fourbytes2int_le(substr($data,30,4)); | ||
23 | $info = array('w'=>$width, 'h'=>$height); | ||
24 | if ($biBitCount<16){ | ||
25 | $info['cs'] = 'Indexed'; | ||
26 | $info['bpc'] = $biBitCount; | ||
27 | $palStr = substr($data,54,($bfOffBits-54)); | ||
28 | $pal = ''; | ||
29 | $cnt = strlen($palStr)/4; | ||
30 | for ($i=0;$i<$cnt;$i++){ | ||
31 | $n = 4*$i; | ||
32 | $pal .= $palStr[$n+2].$palStr[$n+1].$palStr[$n]; | ||
33 | } | ||
34 | $info['pal'] = $pal; | ||
35 | } | ||
36 | else{ | ||
37 | $info['cs'] = 'DeviceRGB'; | ||
38 | $info['bpc'] = 8; | ||
39 | } | ||
40 | |||
41 | if ($this->mpdf->restrictColorSpace==1 || $this->mpdf->PDFX || $this->mpdf->restrictColorSpace==3) { | ||
42 | if (($this->mpdf->PDFA && !$this->mpdf->PDFAauto) || ($this->mpdf->PDFX && !$this->mpdf->PDFXauto)) { $this->mpdf->PDFAXwarnings[] = "Image cannot be converted to suitable colour space for PDFA or PDFX file - ".$file." - (Image replaced by 'no-image'.)"; } | ||
43 | return array('error' => "BMP Image cannot be converted to suitable colour space - ".$file." - (Image replaced by 'no-image'.)"); | ||
44 | } | ||
45 | |||
46 | $biXPelsPerMeter=$this->_fourbytes2int_le(substr($data,38,4)); // horizontal pixels per meter, usually set to zero | ||
47 | //$biYPelsPerMeter=$this->_fourbytes2int_le(substr($data,42,4)); // vertical pixels per meter, usually set to zero | ||
48 | $biXPelsPerMeter=round($biXPelsPerMeter/1000 *25.4); | ||
49 | //$biYPelsPerMeter=round($biYPelsPerMeter/1000 *25.4); | ||
50 | $info['set-dpi'] = $biXPelsPerMeter; | ||
51 | |||
52 | switch ($biCompression){ | ||
53 | case 0: | ||
54 | $str = substr($data,$bfOffBits); | ||
55 | break; | ||
56 | case 1: # BI_RLE8 | ||
57 | $str = $this->rle8_decode(substr($data,$bfOffBits), $width); | ||
58 | break; | ||
59 | case 2: # BI_RLE4 | ||
60 | $str = $this->rle4_decode(substr($data,$bfOffBits), $width); | ||
61 | break; | ||
62 | } | ||
63 | $bmpdata = ''; | ||
64 | $padCnt = (4-ceil(($width/(8/$biBitCount)))%4)%4; | ||
65 | switch ($biBitCount){ | ||
66 | case 1: | ||
67 | case 4: | ||
68 | case 8: | ||
69 | $w = floor($width/(8/$biBitCount)) + ($width%(8/$biBitCount)?1:0); | ||
70 | $w_row = $w + $padCnt; | ||
71 | if ($flip){ | ||
72 | for ($y=0;$y<$height;$y++){ | ||
73 | $y0 = $y*$w_row; | ||
74 | for ($x=0;$x<$w;$x++) | ||
75 | $bmpdata .= $str[$y0+$x]; | ||
76 | } | ||
77 | }else{ | ||
78 | for ($y=$height-1;$y>=0;$y--){ | ||
79 | $y0 = $y*$w_row; | ||
80 | for ($x=0;$x<$w;$x++) | ||
81 | $bmpdata .= $str[$y0+$x]; | ||
82 | } | ||
83 | } | ||
84 | break; | ||
85 | |||
86 | case 16: | ||
87 | $w_row = $width*2 + $padCnt; | ||
88 | if ($flip){ | ||
89 | for ($y=0;$y<$height;$y++){ | ||
90 | $y0 = $y*$w_row; | ||
91 | for ($x=0;$x<$width;$x++){ | ||
92 | $n = (ord( $str[$y0 + 2*$x + 1])*256 + ord( $str[$y0 + 2*$x])); | ||
93 | $b = ($n & 31)<<3; $g = ($n & 992)>>2; $r = ($n & 31744)>>7128; | ||
94 | $bmpdata .= chr($r) . chr($g) . chr($b); | ||
95 | } | ||
96 | } | ||
97 | }else{ | ||
98 | for ($y=$height-1;$y>=0;$y--){ | ||
99 | $y0 = $y*$w_row; | ||
100 | for ($x=0;$x<$width;$x++){ | ||
101 | $n = (ord( $str[$y0 + 2*$x + 1])*256 + ord( $str[$y0 + 2*$x])); | ||
102 | $b = ($n & 31)<<3; $g = ($n & 992)>>2; $r = ($n & 31744)>>7; | ||
103 | $bmpdata .= chr($r) . chr($g) . chr($b); | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | break; | ||
108 | |||
109 | case 24: | ||
110 | case 32: | ||
111 | $byteCnt = $biBitCount/8; | ||
112 | $w_row = $width*$byteCnt + $padCnt; | ||
113 | |||
114 | if ($flip){ | ||
115 | for ($y=0;$y<$height;$y++){ | ||
116 | $y0 = $y*$w_row; | ||
117 | for ($x=0;$x<$width;$x++){ | ||
118 | $i = $y0 + $x*$byteCnt ; # + 1 | ||
119 | $bmpdata .= $str[$i+2].$str[$i+1].$str[$i]; | ||
120 | } | ||
121 | } | ||
122 | }else{ | ||
123 | for ($y=$height-1;$y>=0;$y--){ | ||
124 | $y0 = $y*$w_row; | ||
125 | for ($x=0;$x<$width;$x++){ | ||
126 | $i = $y0 + $x*$byteCnt ; # + 1 | ||
127 | $bmpdata .= $str[$i+2].$str[$i+1].$str[$i]; | ||
128 | } | ||
129 | } | ||
130 | } | ||
131 | break; | ||
132 | |||
133 | default: | ||
134 | return array('error' => 'Error parsing BMP image - Unsupported image biBitCount'); | ||
135 | } | ||
136 | if ($this->mpdf->compress) { | ||
137 | $bmpdata=gzcompress($bmpdata); | ||
138 | $info['f']='FlateDecode'; | ||
139 | } | ||
140 | $info['data']=$bmpdata; | ||
141 | $info['type']='bmp'; | ||
142 | return $info; | ||
143 | } | ||
144 | |||
145 | function _fourbytes2int_le($s) { | ||
146 | //Read a 4-byte integer from string | ||
147 | return (ord($s[3])<<24) + (ord($s[2])<<16) + (ord($s[1])<<8) + ord($s[0]); | ||
148 | } | ||
149 | |||
150 | function _twobytes2int_le($s) { | ||
151 | //Read a 2-byte integer from string | ||
152 | return (ord(substr($s, 1, 1))<<8) + ord(substr($s, 0, 1)); | ||
153 | } | ||
154 | |||
155 | |||
156 | # Decoder for RLE8 compression in windows bitmaps | ||
157 | # see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_6x0u.asp | ||
158 | function rle8_decode ($str, $width){ | ||
159 | $lineWidth = $width + (3 - ($width-1) % 4); | ||
160 | $out = ''; | ||
161 | $cnt = strlen($str); | ||
162 | for ($i=0;$i<$cnt;$i++){ | ||
163 | $o = ord($str[$i]); | ||
164 | switch ($o){ | ||
165 | case 0: # ESCAPE | ||
166 | $i++; | ||
167 | switch (ord($str[$i])){ | ||
168 | case 0: # NEW LINE | ||
169 | $padCnt = $lineWidth - strlen($out)%$lineWidth; | ||
170 | if ($padCnt<$lineWidth) $out .= str_repeat(chr(0), $padCnt); # pad line | ||
171 | break; | ||
172 | case 1: # END OF FILE | ||
173 | $padCnt = $lineWidth - strlen($out)%$lineWidth; | ||
174 | if ($padCnt<$lineWidth) $out .= str_repeat(chr(0), $padCnt); # pad line | ||
175 | break 3; | ||
176 | case 2: # DELTA | ||
177 | $i += 2; | ||
178 | break; | ||
179 | default: # ABSOLUTE MODE | ||
180 | $num = ord($str[$i]); | ||
181 | for ($j=0;$j<$num;$j++) | ||
182 | $out .= $str[++$i]; | ||
183 | if ($num % 2) $i++; | ||
184 | } | ||
185 | break; | ||
186 | default: | ||
187 | $out .= str_repeat($str[++$i], $o); | ||
188 | } | ||
189 | } | ||
190 | return $out; | ||
191 | } | ||
192 | |||
193 | # Decoder for RLE4 compression in windows bitmaps | ||
194 | # see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_6x0u.asp | ||
195 | function rle4_decode ($str, $width){ | ||
196 | $w = floor($width/2) + ($width % 2); | ||
197 | $lineWidth = $w + (3 - ( ($width-1) / 2) % 4); | ||
198 | $pixels = array(); | ||
199 | $cnt = strlen($str); | ||
200 | for ($i=0;$i<$cnt;$i++){ | ||
201 | $o = ord($str[$i]); | ||
202 | switch ($o){ | ||
203 | case 0: # ESCAPE | ||
204 | $i++; | ||
205 | switch (ord($str[$i])){ | ||
206 | case 0: # NEW LINE | ||
207 | while (count($pixels)%$lineWidth!=0) | ||
208 | $pixels[]=0; | ||
209 | break; | ||
210 | case 1: # END OF FILE | ||
211 | while (count($pixels)%$lineWidth!=0) | ||
212 | $pixels[]=0; | ||
213 | break 3; | ||
214 | case 2: # DELTA | ||
215 | $i += 2; | ||
216 | break; | ||
217 | default: # ABSOLUTE MODE | ||
218 | $num = ord($str[$i]); | ||
219 | for ($j=0;$j<$num;$j++){ | ||
220 | if ($j%2==0){ | ||
221 | $c = ord($str[++$i]); | ||
222 | $pixels[] = ($c & 240)>>4; | ||
223 | } else | ||
224 | $pixels[] = $c & 15; | ||
225 | } | ||
226 | if ($num % 2) $i++; | ||
227 | } | ||
228 | break; | ||
229 | default: | ||
230 | $c = ord($str[++$i]); | ||
231 | for ($j=0;$j<$o;$j++) | ||
232 | $pixels[] = ($j%2==0 ? ($c & 240)>>4 : $c & 15); | ||
233 | } | ||
234 | } | ||
235 | |||
236 | $out = ''; | ||
237 | if (count($pixels)%2) $pixels[]=0; | ||
238 | $cnt = count($pixels)/2; | ||
239 | for ($i=0;$i<$cnt;$i++) | ||
240 | $out .= chr(16*$pixels[2*$i] + $pixels[2*$i+1]); | ||
241 | return $out; | ||
242 | } | ||
243 | |||
244 | |||
245 | |||
246 | } | ||
247 | |||
248 | ?> \ No newline at end of file | ||
diff --git a/inc/3rdparty/libraries/mpdf/classes/cssmgr.php b/inc/3rdparty/libraries/mpdf/classes/cssmgr.php new file mode 100644 index 00000000..9bbbed9c --- /dev/null +++ b/inc/3rdparty/libraries/mpdf/classes/cssmgr.php | |||
@@ -0,0 +1,1566 @@ | |||
1 | <?php | ||
2 | |||
3 | class cssmgr { | ||
4 | |||
5 | var $mpdf = null; | ||
6 | |||
7 | var $tablecascadeCSS; | ||
8 | var $listcascadeCSS; | ||
9 | var $cascadeCSS; | ||
10 | var $CSS; | ||
11 | var $tbCSSlvl; | ||
12 | var $listCSSlvl; | ||
13 | |||
14 | |||
15 | function cssmgr(&$mpdf) { | ||
16 | $this->mpdf = $mpdf; | ||
17 | $this->tablecascadeCSS = array(); | ||
18 | $this->listcascadeCSS = array(); | ||
19 | $this->CSS=array(); | ||
20 | $this->cascadeCSS = array(); | ||
21 | $this->tbCSSlvl = 0; | ||
22 | $this->listCSSlvl = 0; | ||
23 | } | ||
24 | |||
25 | |||
26 | function ReadDefaultCSS($CSSstr) { | ||
27 | $CSS = array(); | ||
28 | $CSSstr = preg_replace('|/\*.*?\*/|s',' ',$CSSstr); | ||
29 | $CSSstr = preg_replace('/[\s\n\r\t\f]/s',' ',$CSSstr); | ||
30 | $CSSstr = preg_replace('/(<\!\-\-|\-\->)/s',' ',$CSSstr); | ||
31 | if ($CSSstr ) { | ||
32 | preg_match_all('/(.*?)\{(.*?)\}/',$CSSstr,$styles); | ||
33 | for($i=0; $i < count($styles[1]) ; $i++) { | ||
34 | $stylestr= trim($styles[2][$i]); | ||
35 | $stylearr = explode(';',$stylestr); | ||
36 | foreach($stylearr AS $sta) { | ||
37 | if (trim($sta)) { | ||
38 | // Changed to allow style="background: url('http://www.bpm1.com/bg.jpg')" | ||
39 | list($property,$value) = explode(':',$sta,2); | ||
40 | $property = trim($property); | ||
41 | $value = preg_replace('/\s*!important/i','',$value); | ||
42 | $value = trim($value); | ||
43 | if ($property && ($value || $value==='0')) { | ||
44 | $classproperties[strtoupper($property)] = $value; | ||
45 | } | ||
46 | } | ||
47 | } | ||
48 | $classproperties = $this->fixCSS($classproperties); | ||
49 | $tagstr = strtoupper(trim($styles[1][$i])); | ||
50 | $tagarr = explode(',',$tagstr); | ||
51 | foreach($tagarr AS $tg) { | ||
52 | $tags = preg_split('/\s+/',trim($tg)); | ||
53 | $level = count($tags); | ||
54 | if ($level == 1) { // e.g. p or .class or #id or p.class or p#id | ||
55 | $t = trim($tags[0]); | ||
56 | if ($t) { | ||
57 | $tag = ''; | ||
58 | if (preg_match('/^('.$this->mpdf->allowedCSStags.')$/',$t)) { $tag= $t; } | ||
59 | if ($this->CSS[$tag] && $tag) { $CSS[$tag] = $this->array_merge_recursive_unique($CSS[$tag], $classproperties); } | ||
60 | else if ($tag) { $CSS[$tag] = $classproperties; } | ||
61 | } | ||
62 | } | ||
63 | } | ||
64 | $properties = array(); | ||
65 | $values = array(); | ||
66 | $classproperties = array(); | ||
67 | } | ||
68 | |||
69 | } // end of if | ||
70 | return $CSS; | ||
71 | } | ||
72 | |||
73 | |||
74 | |||
75 | function ReadCSS($html) { | ||
76 | preg_match_all('/<style[^>]*media=["\']([^"\'>]*)["\'].*?<\/style>/is',$html,$m); | ||
77 | for($i=0; $i<count($m[0]); $i++) { | ||
78 | if ($this->mpdf->CSSselectMedia && !preg_match('/('.trim($this->mpdf->CSSselectMedia).'|all)/i',$m[1][$i])) { | ||
79 | $html = preg_replace('/'.preg_quote($m[0][$i],'/').'/','',$html); | ||
80 | } | ||
81 | } | ||
82 | preg_match_all('/<link[^>]*media=["\']([^"\'>]*)["\'].*?>/is',$html,$m); | ||
83 | for($i=0; $i<count($m[0]); $i++) { | ||
84 | if ($this->mpdf->CSSselectMedia && !preg_match('/('.trim($this->mpdf->CSSselectMedia).'|all)/i',$m[1][$i])) { | ||
85 | $html = preg_replace('/'.preg_quote($m[0][$i],'/').'/','',$html); | ||
86 | } | ||
87 | } | ||
88 | |||
89 | // mPDF 5.5.02 | ||
90 | // Remove Comment tags <!-- ... --> inside CSS as <style> in HTML document | ||
91 | // Remove Comment tags /* ... */ inside CSS as <style> in HTML document | ||
92 | // But first, we replace upper and mixed case closing style tag with lower | ||
93 | // case so we can use str_replace later. | ||
94 | preg_replace('/<\/style>/i', '</style>', $html); | ||
95 | preg_match_all('/<style.*?>(.*?)<\/style>/si',$html,$m); | ||
96 | if (count($m[1])) { | ||
97 | for($i=0;$i<count($m[1]);$i++) { | ||
98 | // Remove comment tags | ||
99 | $sub = preg_replace('/(<\!\-\-|\-\->)/s',' ',$m[1][$i]); | ||
100 | $sub = '>'.preg_replace('|/\*.*?\*/|s',' ',$sub).'</style>'; | ||
101 | $html = str_replace('>'.$m[1][$i].'</style>', $sub, $html); | ||
102 | } | ||
103 | } | ||
104 | |||
105 | |||
106 | $html = preg_replace('/<!--mpdf/i','',$html); | ||
107 | $html = preg_replace('/mpdf-->/i','',$html); | ||
108 | $html = preg_replace('/<\!\-\-.*?\-\->/s',' ',$html); | ||
109 | |||
110 | $match = 0; // no match for instance | ||
111 | $regexp = ''; // This helps debugging: showing what is the REAL string being processed | ||
112 | $CSSext = array(); | ||
113 | |||
114 | //CSS inside external files | ||
115 | $regexp = '/<link[^>]*rel=["\']stylesheet["\'][^>]*href=["\']([^>"\']*)["\'].*?>/si'; | ||
116 | $x = preg_match_all($regexp,$html,$cxt); | ||
117 | if ($x) { | ||
118 | $match += $x; | ||
119 | $CSSext = $cxt[1]; | ||
120 | } | ||
121 | |||
122 | $regexp = '/<link[^>]*href=["\']([^>"\']*)["\'][^>]*?rel=["\']stylesheet["\'].*?>/si'; | ||
123 | $x = preg_match_all($regexp,$html,$cxt); | ||
124 | if ($x) { | ||
125 | $match += $x; | ||
126 | $CSSext = array_merge($CSSext,$cxt[1]); | ||
127 | } | ||
128 | |||
129 | // look for @import stylesheets | ||
130 | //$regexp = '/@import url\([\'\"]{0,1}([^\)]*?\.css)[\'\"]{0,1}\)/si'; | ||
131 | $regexp = '/@import url\([\'\"]{0,1}([^\)]*?\.css(\?\S+)?)[\'\"]{0,1}\)/si'; | ||
132 | $x = preg_match_all($regexp,$html,$cxt); | ||
133 | if ($x) { | ||
134 | $match += $x; | ||
135 | $CSSext = array_merge($CSSext,$cxt[1]); | ||
136 | } | ||
137 | |||
138 | // look for @import without the url() | ||
139 | //$regexp = '/@import [\'\"]{0,1}([^;]*?\.css)[\'\"]{0,1}/si'; | ||
140 | $regexp = '/@import [\'\"]{0,1}([^;]*?\.css(\?\S+)?)[\'\"]{0,1}/si'; | ||
141 | $x = preg_match_all($regexp,$html,$cxt); | ||
142 | if ($x) { | ||
143 | $match += $x; | ||
144 | $CSSext = array_merge($CSSext,$cxt[1]); | ||
145 | } | ||
146 | |||
147 | $ind = 0; | ||
148 | $CSSstr = ''; | ||
149 | |||
150 | if (!is_array($this->cascadeCSS)) $this->cascadeCSS = array(); | ||
151 | |||
152 | while($match){ | ||
153 | $path = $CSSext[$ind]; | ||
154 | $this->mpdf->GetFullPath($path); | ||
155 | $CSSextblock = $this->mpdf->_get_file($path); | ||
156 | if ($CSSextblock) { | ||
157 | // look for embedded @import stylesheets in other stylesheets | ||
158 | // and fix url paths (including background-images) relative to stylesheet | ||
159 | //$regexpem = '/@import url\([\'\"]{0,1}(.*?\.css)[\'\"]{0,1}\)/si'; | ||
160 | $regexpem = '/@import url\([\'\"]{0,1}(.*?\.css(\?\S+)?)[\'\"]{0,1}\)/si'; | ||
161 | $xem = preg_match_all($regexpem,$CSSextblock,$cxtem); | ||
162 | $cssBasePath = preg_replace('/\/[^\/]*$/','',$path) . '/'; | ||
163 | if ($xem) { | ||
164 | foreach($cxtem[1] AS $cxtembedded) { | ||
165 | // path is relative to original stlyesheet!! | ||
166 | $this->mpdf->GetFullPath($cxtembedded, $cssBasePath ); | ||
167 | $match++; | ||
168 | $CSSext[] = $cxtembedded; | ||
169 | } | ||
170 | } | ||
171 | $regexpem = '/(background[^;]*url\s*\(\s*[\'\"]{0,1})([^\)\'\"]*)([\'\"]{0,1}\s*\))/si'; | ||
172 | $xem = preg_match_all($regexpem,$CSSextblock,$cxtem); | ||
173 | if ($xem) { | ||
174 | for ($i=0;$i<count($cxtem[0]);$i++) { | ||
175 | // path is relative to original stlyesheet!! | ||
176 | $embedded = $cxtem[2][$i]; | ||
177 | if (!preg_match('/^data:image/i', $embedded)) { // mPDF 5.5.13 | ||
178 | $this->mpdf->GetFullPath($embedded, $cssBasePath ); | ||
179 | $CSSextblock = preg_replace('/'.preg_quote($cxtem[0][$i],'/').'/', ($cxtem[1][$i].$embedded.$cxtem[3][$i]), $CSSextblock); | ||
180 | } | ||
181 | } | ||
182 | } | ||
183 | $CSSstr .= ' '.$CSSextblock; | ||
184 | } | ||
185 | $match--; | ||
186 | $ind++; | ||
187 | } //end of match | ||
188 | |||
189 | $match = 0; // reset value, if needed | ||
190 | // CSS as <style> in HTML document | ||
191 | $regexp = '/<style.*?>(.*?)<\/style>/si'; | ||
192 | $match = preg_match_all($regexp,$html,$CSSblock); | ||
193 | if ($match) { | ||
194 | $tmpCSSstr = implode(' ',$CSSblock[1]); | ||
195 | $regexpem = '/(background[^;]*url\s*\(\s*[\'\"]{0,1})([^\)\'\"]*)([\'\"]{0,1}\s*\))/si'; | ||
196 | $xem = preg_match_all($regexpem,$tmpCSSstr ,$cxtem); | ||
197 | if ($xem) { | ||
198 | for ($i=0;$i<count($cxtem[0]);$i++) { | ||
199 | $embedded = $cxtem[2][$i]; | ||
200 | if (!preg_match('/^data:image/i', $embedded)) { // mPDF 5.5.13 | ||
201 | $this->mpdf->GetFullPath($embedded); | ||
202 | $tmpCSSstr = preg_replace('/'.preg_quote($cxtem[0][$i],'/').'/', ($cxtem[1][$i].$embedded.$cxtem[3][$i]), $tmpCSSstr ); | ||
203 | } | ||
204 | } | ||
205 | } | ||
206 | $CSSstr .= ' '.$tmpCSSstr; | ||
207 | } | ||
208 | // Remove comments | ||
209 | $CSSstr = preg_replace('|/\*.*?\*/|s',' ',$CSSstr); | ||
210 | $CSSstr = preg_replace('/[\s\n\r\t\f]/s',' ',$CSSstr); | ||
211 | |||
212 | if (preg_match('/@media/',$CSSstr)) { | ||
213 | preg_match_all('/@media(.*?)\{(([^\{\}]*\{[^\{\}]*\})+)\s*\}/is',$CSSstr,$m); | ||
214 | for($i=0; $i<count($m[0]); $i++) { | ||
215 | if ($this->mpdf->CSSselectMedia && !preg_match('/('.trim($this->mpdf->CSSselectMedia).'|all)/i',$m[1][$i])) { | ||
216 | $CSSstr = preg_replace('/'.preg_quote($m[0][$i],'/').'/','',$CSSstr); | ||
217 | } | ||
218 | else { | ||
219 | $CSSstr = preg_replace('/'.preg_quote($m[0][$i],'/').'/',' '.$m[2][$i].' ',$CSSstr); | ||
220 | } | ||
221 | } | ||
222 | } | ||
223 | |||
224 | // mPDF 5.5.13 | ||
225 | // Replace any background: url(data:image... with temporary image file reference | ||
226 | preg_match_all("/(url\(data:image\/(jpeg|gif|png);base64,(.*)\))/si", $CSSstr, $idata); | ||
227 | if (count($idata[0])) { | ||
228 | for($i=0;$i<count($idata[0]);$i++) { | ||
229 | $file = _MPDF_TEMP_PATH.'_tempCSSidata'.RAND(1,10000).'_'.$i.'.'.$idata[2][$i]; | ||
230 | //Save to local file | ||
231 | file_put_contents($file, base64_decode($idata[3][$i])); | ||
232 | // $this->mpdf->GetFullPath($file); // ? is this needed - NO mPDF 5.6.03 | ||
233 | $CSSstr = str_replace($idata[0][$i], 'url("'.$file.'")', $CSSstr); // mPDF 5.5.17 | ||
234 | } | ||
235 | } | ||
236 | |||
237 | $CSSstr = preg_replace('/(<\!\-\-|\-\->)/s',' ',$CSSstr); | ||
238 | if ($CSSstr ) { | ||
239 | preg_match_all('/(.*?)\{(.*?)\}/',$CSSstr,$styles); | ||
240 | for($i=0; $i < count($styles[1]) ; $i++) { | ||
241 | // SET array e.g. $classproperties['COLOR'] = '#ffffff'; | ||
242 | $stylestr= trim($styles[2][$i]); | ||
243 | $stylearr = explode(';',$stylestr); | ||
244 | foreach($stylearr AS $sta) { | ||
245 | if (trim($sta)) { | ||
246 | // Changed to allow style="background: url('http://www.bpm1.com/bg.jpg')" | ||
247 | list($property,$value) = explode(':',$sta,2); | ||
248 | $property = trim($property); | ||
249 | $value = preg_replace('/\s*!important/i','',$value); | ||
250 | $value = trim($value); | ||
251 | if ($property && ($value || $value==='0')) { | ||
252 | // Ignores -webkit-gradient so doesn't override -moz- | ||
253 | if ((strtoupper($property)=='BACKGROUND-IMAGE' || strtoupper($property)=='BACKGROUND') && preg_match('/-webkit-gradient/i',$value)) { | ||
254 | continue; | ||
255 | } | ||
256 | $classproperties[strtoupper($property)] = $value; | ||
257 | } | ||
258 | } | ||
259 | } | ||
260 | $classproperties = $this->fixCSS($classproperties); | ||
261 | $tagstr = strtoupper(trim($styles[1][$i])); | ||
262 | $tagarr = explode(',',$tagstr); | ||
263 | $pageselectors = false; // used to turn on $this->mpdf->mirrorMargins | ||
264 | foreach($tagarr AS $tg) { | ||
265 | $tags = preg_split('/\s+/',trim($tg)); | ||
266 | $level = count($tags); | ||
267 | $t = ''; | ||
268 | $t2 = ''; | ||
269 | $t3 = ''; | ||
270 | if (trim($tags[0])=='@PAGE') { | ||
271 | if (isset($tags[0])) { $t = trim($tags[0]); } | ||
272 | if (isset($tags[1])) { $t2 = trim($tags[1]); } | ||
273 | if (isset($tags[2])) { $t3 = trim($tags[2]); } | ||
274 | $tag = ''; | ||
275 | if ($level==1) { $tag = $t; } | ||
276 | else if ($level==2 && preg_match('/^[:](.*)$/',$t2,$m)) { | ||
277 | $tag = $t.'>>PSEUDO>>'.$m[1]; | ||
278 | if ($m[1]=='LEFT' || $m[1]=='RIGHT') { $pageselectors = true; } // used to turn on $this->mpdf->mirrorMargins | ||
279 | } | ||
280 | else if ($level==2) { $tag = $t.'>>NAMED>>'.$t2; } | ||
281 | else if ($level==3 && preg_match('/^[:](.*)$/',$t3,$m)) { | ||
282 | $tag = $t.'>>NAMED>>'.$t2.'>>PSEUDO>>'.$m[1]; | ||
283 | if ($m[1]=='LEFT' || $m[1]=='RIGHT') { $pageselectors = true; } // used to turn on $this->mpdf->mirrorMargins | ||
284 | } | ||
285 | if (isset($this->CSS[$tag]) && $tag) { $this->CSS[$tag] = $this->array_merge_recursive_unique($this->CSS[$tag], $classproperties); } | ||
286 | else if ($tag) { $this->CSS[$tag] = $classproperties; } | ||
287 | } | ||
288 | |||
289 | else if ($level == 1) { // e.g. p or .class or #id or p.class or p#id | ||
290 | if (isset($tags[0])) { $t = trim($tags[0]); } | ||
291 | if ($t) { | ||
292 | $tag = ''; | ||
293 | if (preg_match('/^[.](.*)$/',$t,$m)) { $tag = 'CLASS>>'.$m[1]; } | ||
294 | else if (preg_match('/^[#](.*)$/',$t,$m)) { $tag = 'ID>>'.$m[1]; } | ||
295 | else if (preg_match('/^('.$this->mpdf->allowedCSStags.')[.](.*)$/',$t,$m)) { $tag = $m[1].'>>CLASS>>'.$m[2]; } | ||
296 | else if (preg_match('/^('.$this->mpdf->allowedCSStags.')\s*:NTH-CHILD\((.*)\)$/',$t,$m)) { $tag = $m[1].'>>SELECTORNTHCHILD>>'.$m[2]; } | ||
297 | else if (preg_match('/^('.$this->mpdf->allowedCSStags.')[#](.*)$/',$t,$m)) { $tag = $m[1].'>>ID>>'.$m[2]; } | ||
298 | else if (preg_match('/^('.$this->mpdf->allowedCSStags.')$/',$t)) { $tag= $t; } | ||
299 | if (isset($this->CSS[$tag]) && $tag) { $this->CSS[$tag] = $this->array_merge_recursive_unique($this->CSS[$tag], $classproperties); } | ||
300 | else if ($tag) { $this->CSS[$tag] = $classproperties; } | ||
301 | } | ||
302 | } | ||
303 | else { | ||
304 | $tmp = array(); | ||
305 | for($n=0;$n<$level;$n++) { | ||
306 | if (isset($tags[$n])) { $t = trim($tags[$n]); } | ||
307 | else { $t = ''; } | ||
308 | if ($t) { | ||
309 | $tag = ''; | ||
310 | if (preg_match('/^[.](.*)$/',$t,$m)) { $tag = 'CLASS>>'.$m[1]; } | ||
311 | else if (preg_match('/^[#](.*)$/',$t,$m)) { $tag = 'ID>>'.$m[1]; } | ||
312 | else if (preg_match('/^('.$this->mpdf->allowedCSStags.')[.](.*)$/',$t,$m)) { $tag = $m[1].'>>CLASS>>'.$m[2]; } | ||
313 | else if (preg_match('/^('.$this->mpdf->allowedCSStags.')\s*:NTH-CHILD\((.*)\)$/',$t,$m)) { $tag = $m[1].'>>SELECTORNTHCHILD>>'.$m[2]; } | ||
314 | else if (preg_match('/^('.$this->mpdf->allowedCSStags.')[#](.*)$/',$t,$m)) { $tag = $m[1].'>>ID>>'.$m[2]; } | ||
315 | else if (preg_match('/^('.$this->mpdf->allowedCSStags.')$/',$t)) { $tag= $t; } | ||
316 | |||
317 | if ($tag) $tmp[] = $tag; | ||
318 | else { break; } | ||
319 | } | ||
320 | } | ||
321 | |||
322 | if ($tag) { | ||
323 | $x = &$this->cascadeCSS; | ||
324 | foreach($tmp AS $tp) { $x = &$x[$tp]; } | ||
325 | $x = $this->array_merge_recursive_unique($x, $classproperties); | ||
326 | $x['depth'] = $level; | ||
327 | } | ||
328 | } | ||
329 | } | ||
330 | if ($pageselectors) { $this->mpdf->mirrorMargins = true; } | ||
331 | $properties = array(); | ||
332 | $values = array(); | ||
333 | $classproperties = array(); | ||
334 | } | ||
335 | } // end of if | ||
336 | //Remove CSS (tags and content), if any | ||
337 | $regexp = '/<style.*?>(.*?)<\/style>/si'; // it can be <style> or <style type="txt/css"> | ||
338 | $html = preg_replace($regexp,'',$html); | ||
339 | //print_r($this->CSS); exit; | ||
340 | //print_r($this->cascadeCSS); exit; | ||
341 | return $html; | ||
342 | } | ||
343 | |||
344 | |||
345 | |||
346 | function readInlineCSS($html) { | ||
347 | //Fix incomplete CSS code | ||
348 | $size = strlen($html)-1; | ||
349 | if (substr($html,$size,1) != ';') $html .= ';'; | ||
350 | //Make CSS[Name-of-the-class] = array(key => value) | ||
351 | $regexp = '|\\s*?(\\S+?):(.+?);|i'; | ||
352 | preg_match_all( $regexp, $html, $styleinfo); | ||
353 | $properties = $styleinfo[1]; | ||
354 | $values = $styleinfo[2]; | ||
355 | //Array-properties and Array-values must have the SAME SIZE! | ||
356 | $classproperties = array(); | ||
357 | for($i = 0; $i < count($properties) ; $i++) { | ||
358 | // Ignores -webkit-gradient so doesn't override -moz- | ||
359 | if ((strtoupper($properties[$i])=='BACKGROUND-IMAGE' || strtoupper($properties[$i])=='BACKGROUND') && preg_match('/-webkit-gradient/i',$values[$i])) { | ||
360 | continue; | ||
361 | } | ||
362 | $classproperties[strtoupper($properties[$i])] = trim($values[$i]); | ||
363 | } | ||
364 | return $this->fixCSS($classproperties); | ||
365 | } | ||
366 | |||
367 | |||
368 | |||
369 | function _fix_borderStr($bd) { | ||
370 | preg_match_all("/\((.*?)\)/", $bd, $m); | ||
371 | if (count($m[1])) { | ||
372 | for($i=0;$i<count($m[1]);$i++) { | ||
373 | $sub = preg_replace("/ /", "", $m[1][$i]); | ||
374 | $bd = preg_replace('/'.preg_quote($m[1][$i], '/').'/si', $sub, $bd); | ||
375 | } | ||
376 | } | ||
377 | |||
378 | $prop = preg_split('/\s+/',trim($bd)); | ||
379 | $w = 'medium'; | ||
380 | $c = '#000000'; | ||
381 | $s = 'none'; | ||
382 | |||
383 | if ( count($prop) == 1 ) { | ||
384 | // solid | ||
385 | if (in_array($prop[0],$this->mpdf->borderstyles) || $prop[0] == 'none' || $prop[0] == 'hidden' ) { $s = $prop[0]; } | ||
386 | // #000000 | ||
387 | else if (is_array($this->mpdf->ConvertColor($prop[0]))) { $c = $prop[0]; } | ||
388 | // 1px | ||
389 | else { $w = $prop[0]; } | ||
390 | } | ||
391 | else if (count($prop) == 2 ) { | ||
392 | // 1px solid | ||
393 | if (in_array($prop[1],$this->mpdf->borderstyles) || $prop[1] == 'none' || $prop[1] == 'hidden' ) { $w = $prop[0]; $s = $prop[1]; } | ||
394 | // solid #000000 | ||
395 | else if (in_array($prop[0],$this->mpdf->borderstyles) || $prop[0] == 'none' || $prop[0] == 'hidden' ) { $s = $prop[0]; $c = $prop[1]; } | ||
396 | // 1px #000000 | ||
397 | else { $w = $prop[0]; $c = $prop[1]; } | ||
398 | } | ||
399 | else if ( count($prop) == 3 ) { | ||
400 | // Change #000000 1px solid to 1px solid #000000 (proper) | ||
401 | if (substr($prop[0],0,1) == '#') { $c = $prop[0]; $w = $prop[1]; $s = $prop[2]; } | ||
402 | // Change solid #000000 1px to 1px solid #000000 (proper) | ||
403 | else if (substr($prop[0],1,1) == '#') { $s = $prop[0]; $c = $prop[1]; $w = $prop[2]; } | ||
404 | // Change solid 1px #000000 to 1px solid #000000 (proper) | ||
405 | else if (in_array($prop[0],$this->mpdf->borderstyles) || $prop[0] == 'none' || $prop[0] == 'hidden' ) { | ||
406 | $s = $prop[0]; $w = $prop[1]; $c = $prop[2]; | ||
407 | } | ||
408 | else { $w = $prop[0]; $s = $prop[1]; $c = $prop[2]; } | ||
409 | } | ||
410 | else { return ''; } | ||
411 | $s = strtolower($s); | ||
412 | return $w.' '.$s.' '.$c; | ||
413 | } | ||
414 | |||
415 | |||
416 | |||
417 | function fixCSS($prop) { | ||
418 | if (!is_array($prop) || (count($prop)==0)) return array(); | ||
419 | $newprop = array(); | ||
420 | foreach($prop AS $k => $v) { | ||
421 | if ($k != 'BACKGROUND-IMAGE' && $k != 'BACKGROUND' && $k != 'ODD-HEADER-NAME' && $k != 'EVEN-HEADER-NAME' && $k != 'ODD-FOOTER-NAME' && $k != 'EVEN-FOOTER-NAME' && $k != 'HEADER' && $k != 'FOOTER') { | ||
422 | $v = strtolower($v); | ||
423 | } | ||
424 | |||
425 | if ($k == 'FONT') { | ||
426 | $s = trim($v); | ||
427 | preg_match_all('/\"(.*?)\"/',$s,$ff); | ||
428 | if (count($ff[1])) { | ||
429 | foreach($ff[1] AS $ffp) { | ||
430 | $w = preg_split('/\s+/',$ffp); | ||
431 | $s = preg_replace('/\"'.$ffp.'\"/',$w[0],$s); | ||
432 | } | ||
433 | } | ||
434 | preg_match_all('/\'(.*?)\'/',$s,$ff); | ||
435 | if (count($ff[1])) { | ||
436 | foreach($ff[1] AS $ffp) { | ||
437 | $w = preg_split('/\s+/',$ffp); | ||
438 | $s = preg_replace('/\''.$ffp.'\'/',$w[0],$s); | ||
439 | } | ||
440 | } | ||
441 | $s = preg_replace('/\s*,\s*/',',',$s); | ||
442 | $bits = preg_split('/\s+/',$s); | ||
443 | if (count($bits)>1) { | ||
444 | $k = 'FONT-FAMILY'; $v = $bits[(count($bits)-1)]; | ||
445 | $fs = $bits[(count($bits)-2)]; | ||
446 | if (preg_match('/(.*?)\/(.*)/',$fs, $fsp)) { | ||
447 | $newprop['FONT-SIZE'] = $fsp[1]; | ||
448 | $newprop['LINE-HEIGHT'] = $fsp[2]; | ||
449 | } | ||
450 | else { $newprop['FONT-SIZE'] = $fs; } | ||
451 | if (preg_match('/(italic|oblique)/i',$s)) { $newprop['FONT-STYLE'] = 'italic'; } | ||
452 | else { $newprop['FONT-STYLE'] = 'normal'; } | ||
453 | if (preg_match('/bold/i',$s)) { $newprop['FONT-WEIGHT'] = 'bold'; } | ||
454 | else { $newprop['FONT-WEIGHT'] = 'normal'; } | ||
455 | if (preg_match('/small-caps/i',$s)) { $newprop['TEXT-TRANSFORM'] = 'uppercase'; } | ||
456 | } | ||
457 | } | ||
458 | if ($k == 'FONT-FAMILY') { | ||
459 | $aux_fontlist = explode(",",$v); | ||
460 | $found = 0; | ||
461 | foreach($aux_fontlist AS $f) { | ||
462 | $fonttype = trim($f); | ||
463 | $fonttype = preg_replace('/["\']*(.*?)["\']*/','\\1',$fonttype); | ||
464 | $fonttype = preg_replace('/ /','',$fonttype); | ||
465 | $v = strtolower(trim($fonttype)); | ||
466 | if (isset($this->mpdf->fonttrans[$v]) && $this->mpdf->fonttrans[$v]) { $v = $this->mpdf->fonttrans[$v]; } | ||
467 | if ((!$this->mpdf->onlyCoreFonts && in_array($v,$this->mpdf->available_unifonts)) || | ||
468 | in_array($v,array('ccourier','ctimes','chelvetica')) || | ||
469 | ($this->mpdf->onlyCoreFonts && in_array($v,array('courier','times','helvetica','arial'))) || | ||
470 | in_array($v, array('sjis','uhc','big5','gb'))) { | ||
471 | $newprop[$k] = $v; | ||
472 | $found = 1; | ||
473 | break; | ||
474 | } | ||
475 | } | ||
476 | if (!$found) { | ||
477 | foreach($aux_fontlist AS $f) { | ||
478 | $fonttype = trim($f); | ||
479 | $fonttype = preg_replace('/["\']*(.*?)["\']*/','\\1',$fonttype); | ||
480 | $fonttype = preg_replace('/ /','',$fonttype); | ||
481 | $v = strtolower(trim($fonttype)); | ||
482 | if (isset($this->mpdf->fonttrans[$v]) && $this->mpdf->fonttrans[$v]) { $v = $this->mpdf->fonttrans[$v]; } | ||
483 | if (in_array($v,$this->mpdf->sans_fonts) || in_array($v,$this->mpdf->serif_fonts) || in_array($v,$this->mpdf->mono_fonts) ) { | ||
484 | $newprop[$k] = $v; | ||
485 | break; | ||
486 | } | ||
487 | } | ||
488 | } | ||
489 | } | ||
490 | else if ($k == 'MARGIN') { | ||
491 | $tmp = $this->expand24($v); | ||
492 | $newprop['MARGIN-TOP'] = $tmp['T']; | ||
493 | $newprop['MARGIN-RIGHT'] = $tmp['R']; | ||
494 | $newprop['MARGIN-BOTTOM'] = $tmp['B']; | ||
495 | $newprop['MARGIN-LEFT'] = $tmp['L']; | ||
496 | } | ||
497 | /*-- BORDER-RADIUS --*/ | ||
498 | else if ($k == 'BORDER-RADIUS' || $k == 'BORDER-TOP-LEFT-RADIUS' || $k == 'BORDER-TOP-RIGHT-RADIUS' || $k == 'BORDER-BOTTOM-LEFT-RADIUS' || $k == 'BORDER-BOTTOM-RIGHT-RADIUS') { | ||
499 | $tmp = $this->border_radius_expand($v,$k); | ||
500 | if (isset($tmp['TL-H'])) $newprop['BORDER-TOP-LEFT-RADIUS-H'] = $tmp['TL-H']; | ||
501 | if (isset($tmp['TL-V'])) $newprop['BORDER-TOP-LEFT-RADIUS-V'] = $tmp['TL-V']; | ||
502 | if (isset($tmp['TR-H'])) $newprop['BORDER-TOP-RIGHT-RADIUS-H'] = $tmp['TR-H']; | ||
503 | if (isset($tmp['TR-V'])) $newprop['BORDER-TOP-RIGHT-RADIUS-V'] = $tmp['TR-V']; | ||
504 | if (isset($tmp['BL-H'])) $newprop['BORDER-BOTTOM-LEFT-RADIUS-H'] = $tmp['BL-H']; | ||
505 | if (isset($tmp['BL-V'])) $newprop['BORDER-BOTTOM-LEFT-RADIUS-V'] = $tmp['BL-V']; | ||
506 | if (isset($tmp['BR-H'])) $newprop['BORDER-BOTTOM-RIGHT-RADIUS-H'] = $tmp['BR-H']; | ||
507 | if (isset($tmp['BR-V'])) $newprop['BORDER-BOTTOM-RIGHT-RADIUS-V'] = $tmp['BR-V']; | ||
508 | } | ||
509 | /*-- END BORDER-RADIUS --*/ | ||
510 | else if ($k == 'PADDING') { | ||
511 | $tmp = $this->expand24($v); | ||
512 | $newprop['PADDING-TOP'] = $tmp['T']; | ||
513 | $newprop['PADDING-RIGHT'] = $tmp['R']; | ||
514 | $newprop['PADDING-BOTTOM'] = $tmp['B']; | ||
515 | $newprop['PADDING-LEFT'] = $tmp['L']; | ||
516 | } | ||
517 | else if ($k == 'BORDER') { | ||
518 | if ($v == '1') { $v = '1px solid #000000'; } | ||
519 | else { $v = $this->_fix_borderStr($v); } | ||
520 | $newprop['BORDER-TOP'] = $v; | ||
521 | $newprop['BORDER-RIGHT'] = $v; | ||
522 | $newprop['BORDER-BOTTOM'] = $v; | ||
523 | $newprop['BORDER-LEFT'] = $v; | ||
524 | } | ||
525 | else if ($k == 'BORDER-TOP') { | ||
526 | $newprop['BORDER-TOP'] = $this->_fix_borderStr($v); | ||
527 | } | ||
528 | else if ($k == 'BORDER-RIGHT') { | ||
529 | $newprop['BORDER-RIGHT'] = $this->_fix_borderStr($v); | ||
530 | } | ||
531 | else if ($k == 'BORDER-BOTTOM') { | ||
532 | $newprop['BORDER-BOTTOM'] = $this->_fix_borderStr($v); | ||
533 | } | ||
534 | else if ($k == 'BORDER-LEFT') { | ||
535 | $newprop['BORDER-LEFT'] = $this->_fix_borderStr($v); | ||
536 | } | ||
537 | else if ($k == 'BORDER-STYLE') { | ||
538 | $e = $this->expand24($v); | ||
539 | $newprop['BORDER-TOP-STYLE'] = $e['T']; | ||
540 | $newprop['BORDER-RIGHT-STYLE'] = $e['R']; | ||
541 | $newprop['BORDER-BOTTOM-STYLE'] = $e['B']; | ||
542 | $newprop['BORDER-LEFT-STYLE'] = $e['L']; | ||
543 | } | ||
544 | else if ($k == 'BORDER-WIDTH') { | ||
545 | $e = $this->expand24($v); | ||
546 | $newprop['BORDER-TOP-WIDTH'] = $e['T']; | ||
547 | $newprop['BORDER-RIGHT-WIDTH'] = $e['R']; | ||
548 | $newprop['BORDER-BOTTOM-WIDTH'] = $e['B']; | ||
549 | $newprop['BORDER-LEFT-WIDTH'] = $e['L']; | ||
550 | } | ||
551 | else if ($k == 'BORDER-COLOR') { | ||
552 | $e = $this->expand24($v); | ||
553 | $newprop['BORDER-TOP-COLOR'] = $e['T']; | ||
554 | $newprop['BORDER-RIGHT-COLOR'] = $e['R']; | ||
555 | $newprop['BORDER-BOTTOM-COLOR'] = $e['B']; | ||
556 | $newprop['BORDER-LEFT-COLOR'] = $e['L']; | ||
557 | } | ||
558 | |||
559 | else if ($k == 'BORDER-SPACING') { | ||
560 | $prop = preg_split('/\s+/',trim($v)); | ||
561 | if (count($prop) == 1 ) { | ||
562 | $newprop['BORDER-SPACING-H'] = $prop[0]; | ||
563 | $newprop['BORDER-SPACING-V'] = $prop[0]; | ||
564 | } | ||
565 | else if (count($prop) == 2 ) { | ||
566 | $newprop['BORDER-SPACING-H'] = $prop[0]; | ||
567 | $newprop['BORDER-SPACING-V'] = $prop[1]; | ||
568 | } | ||
569 | } | ||
570 | else if ($k == 'TEXT-OUTLINE') { // mPDF 5.6.07 | ||
571 | $prop = preg_split('/\s+/',trim($v)); | ||
572 | if (trim(strtolower($v)) == 'none' ) { | ||
573 | $newprop['TEXT-OUTLINE'] = 'none'; | ||
574 | } | ||
575 | else if (count($prop) == 2 ) { | ||
576 | $newprop['TEXT-OUTLINE-WIDTH'] = $prop[0]; | ||
577 | $newprop['TEXT-OUTLINE-COLOR'] = $prop[1]; | ||
578 | } | ||
579 | else if (count($prop) == 3 ) { | ||
580 | $newprop['TEXT-OUTLINE-WIDTH'] = $prop[0]; | ||
581 | $newprop['TEXT-OUTLINE-COLOR'] = $prop[2]; | ||
582 | } | ||
583 | } | ||
584 | else if ($k == 'SIZE') { | ||
585 | $prop = preg_split('/\s+/',trim($v)); | ||
586 | if (preg_match('/(auto|portrait|landscape)/',$prop[0])) { | ||
587 | $newprop['SIZE'] = strtoupper($prop[0]); | ||
588 | } | ||
589 | else if (count($prop) == 1 ) { | ||
590 | $newprop['SIZE']['W'] = $this->mpdf->ConvertSize($prop[0]); | ||
591 | $newprop['SIZE']['H'] = $this->mpdf->ConvertSize($prop[0]); | ||
592 | } | ||
593 | else if (count($prop) == 2 ) { | ||
594 | $newprop['SIZE']['W'] = $this->mpdf->ConvertSize($prop[0]); | ||
595 | $newprop['SIZE']['H'] = $this->mpdf->ConvertSize($prop[1]); | ||
596 | } | ||
597 | } | ||
598 | else if ($k == 'SHEET-SIZE') { | ||
599 | $prop = preg_split('/\s+/',trim($v)); | ||
600 | if (count($prop) == 2 ) { | ||
601 | $newprop['SHEET-SIZE'] = array($this->mpdf->ConvertSize($prop[0]), $this->mpdf->ConvertSize($prop[1])); | ||
602 | } | ||
603 | else { | ||
604 | if(preg_match('/([0-9a-zA-Z]*)-L/i',$v,$m)) { // e.g. A4-L = A$ landscape | ||
605 | $ft = $this->mpdf->_getPageFormat($m[1]); | ||
606 | $format = array($ft[1],$ft[0]); | ||
607 | } | ||
608 | else { $format = $this->mpdf->_getPageFormat($v); } | ||
609 | if ($format) { $newprop['SHEET-SIZE'] = array($format[0]/_MPDFK, $format[1]/_MPDFK); } | ||
610 | } | ||
611 | } | ||
612 | else if ($k == 'BACKGROUND') { | ||
613 | $bg = $this->parseCSSbackground($v); | ||
614 | if ($bg['c']) { $newprop['BACKGROUND-COLOR'] = $bg['c']; } | ||
615 | else { $newprop['BACKGROUND-COLOR'] = 'transparent'; } | ||
616 | /*-- BACKGROUNDS --*/ | ||
617 | if ($bg['i']) { | ||
618 | $newprop['BACKGROUND-IMAGE'] = $bg['i']; | ||
619 | if ($bg['r']) { $newprop['BACKGROUND-REPEAT'] = $bg['r']; } | ||
620 | if ($bg['p']) { $newprop['BACKGROUND-POSITION'] = $bg['p']; } | ||
621 | } | ||
622 | else { $newprop['BACKGROUND-IMAGE'] = ''; } | ||
623 | /*-- END BACKGROUNDS --*/ | ||
624 | } | ||
625 | /*-- BACKGROUNDS --*/ | ||
626 | else if ($k == 'BACKGROUND-IMAGE') { | ||
627 | if (preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient\(.*\)/i',$v,$m)) { | ||
628 | $newprop['BACKGROUND-IMAGE'] = $m[0]; | ||
629 | continue; | ||
630 | } | ||
631 | if (preg_match('/url\([\'\"]{0,1}(.*?)[\'\"]{0,1}\)/i',$v,$m)) { | ||
632 | $newprop['BACKGROUND-IMAGE'] = $m[1]; | ||
633 | } | ||
634 | |||
635 | else if (strtolower($v)=='none') { $newprop['BACKGROUND-IMAGE'] = ''; } | ||
636 | |||
637 | } | ||
638 | else if ($k == 'BACKGROUND-REPEAT') { | ||
639 | if (preg_match('/(repeat-x|repeat-y|no-repeat|repeat)/i',$v,$m)) { | ||
640 | $newprop['BACKGROUND-REPEAT'] = strtolower($m[1]); | ||
641 | } | ||
642 | } | ||
643 | else if ($k == 'BACKGROUND-POSITION') { | ||
644 | $s = $v; | ||
645 | $bits = preg_split('/\s+/',trim($s)); | ||
646 | // These should be Position x1 or x2 | ||
647 | if (count($bits)==1) { | ||
648 | if (preg_match('/bottom/',$bits[0])) { $bg['p'] = '50% 100%'; } | ||
649 | else if (preg_match('/top/',$bits[0])) { $bg['p'] = '50% 0%'; } | ||
650 | else { $bg['p'] = $bits[0] . ' 50%'; } | ||
651 | } | ||
652 | else if (count($bits)==2) { | ||
653 | // Can be either right center or center right | ||
654 | if (preg_match('/(top|bottom)/',$bits[0]) || preg_match('/(left|right)/',$bits[1])) { | ||
655 | $bg['p'] = $bits[1] . ' '.$bits[0]; | ||
656 | } | ||
657 | else { | ||
658 | $bg['p'] = $bits[0] . ' '.$bits[1]; | ||
659 | } | ||
660 | } | ||
661 | if ($bg['p']) { | ||
662 | $bg['p'] = preg_replace('/(left|top)/','0%',$bg['p']); | ||
663 | $bg['p'] = preg_replace('/(right|bottom)/','100%',$bg['p']); | ||
664 | $bg['p'] = preg_replace('/(center)/','50%',$bg['p']); | ||
665 | if (!preg_match('/[\-]{0,1}\d+(in|cm|mm|pt|pc|em|ex|px|%)* [\-]{0,1}\d+(in|cm|mm|pt|pc|em|ex|px|%)*/',$bg['p'])) { | ||
666 | $bg['p'] = false; | ||
667 | } | ||
668 | } | ||
669 | if ($bg['p']) { $newprop['BACKGROUND-POSITION'] = $bg['p']; } | ||
670 | } | ||
671 | /*-- END BACKGROUNDS --*/ | ||
672 | else if ($k == 'IMAGE-ORIENTATION') { | ||
673 | if (preg_match('/([\-]*[0-9\.]+)(deg|grad|rad)/i',$v,$m)) { | ||
674 | $angle = $m[1] + 0; | ||
675 | if (strtolower($m[2])=='deg') { $angle = $angle; } | ||
676 | else if (strtolower($m[2])=='grad') { $angle *= (360/400); } | ||
677 | else if (strtolower($m[2])=='rad') { $angle = rad2deg($angle); } | ||
678 | while($angle < 0) { $angle += 360; } | ||
679 | $angle = ($angle % 360); | ||
680 | $angle /= 90; | ||
681 | $angle = round($angle) * 90; | ||
682 | $newprop['IMAGE-ORIENTATION'] = $angle; | ||
683 | } | ||
684 | } | ||
685 | // mPDF 5.6.13 | ||
686 | else if ($k == 'TEXT-ALIGN') { | ||
687 | if (preg_match('/["\'](.){1}["\']/i',$v,$m)) { | ||
688 | $d = array_search($m[1],$this->mpdf->decimal_align); | ||
689 | if ($d !== false) { $newprop['TEXT-ALIGN'] = $d; } | ||
690 | if (preg_match('/(center|left|right)/i',$v,$m)) { $newprop['TEXT-ALIGN'] .= strtoupper(substr($m[1],0,1)); } | ||
691 | else { $newprop['TEXT-ALIGN'] .= 'R'; } // default = R | ||
692 | } | ||
693 | else if (preg_match('/["\'](\\\[a-fA-F0-9]{1,6})["\']/i',$v,$m)) { | ||
694 | $utf8 = codeHex2utf(substr($m[1],1,6)); | ||
695 | $d = array_search($utf8,$this->mpdf->decimal_align); | ||
696 | if ($d !== false) { $newprop['TEXT-ALIGN'] = $d; } | ||
697 | if (preg_match('/(center|left|right)/i',$v,$m)) { $newprop['TEXT-ALIGN'] .= strtoupper(substr($m[1],0,1)); } | ||
698 | else { $newprop['TEXT-ALIGN'] .= 'R'; } // default = R | ||
699 | } | ||
700 | else { $newprop[$k] = $v; } | ||
701 | } | ||
702 | |||
703 | else { | ||
704 | $newprop[$k] = $v; | ||
705 | } | ||
706 | } | ||
707 | |||
708 | return $newprop; | ||
709 | } | ||
710 | |||
711 | function setCSSboxshadow($v) { | ||
712 | $sh = array(); | ||
713 | $c = preg_match_all('/(rgba|rgb|device-cmyka|cmyka|device-cmyk|cmyk|hsla|hsl)\(.*?\)/',$v,$x); // mPDF 5.6.05 | ||
714 | for($i=0; $i<$c; $i++) { | ||
715 | $col = preg_replace('/,/','*',$x[0][$i]); | ||
716 | $v = preg_replace('/'.preg_quote($x[0][$i],'/').'/',$col,$v); | ||
717 | } | ||
718 | $ss = explode(',',$v); | ||
719 | foreach ($ss AS $s) { | ||
720 | $new = array('inset'=>false, 'blur'=>0, 'spread'=>0); | ||
721 | if (preg_match('/inset/i',$s)) { $new['inset'] = true; $s = preg_replace('/\s*inset\s*/','',$s); } | ||
722 | $p = explode(' ',trim($s)); | ||
723 | if (isset($p[0])) { $new['x'] = $this->mpdf->ConvertSize(trim($p[0]),$this->mpdf->blk[$this->mpdf->blklvl-1]['inner_width'],$this->mpdf->FontSize,false); } | ||
724 | if (isset($p[1])) { $new['y'] = $this->mpdf->ConvertSize(trim($p[1]),$this->mpdf->blk[$this->mpdf->blklvl-1]['inner_width'],$this->mpdf->FontSize,false); } | ||
725 | if (isset($p[2])) { | ||
726 | if (preg_match('/^\s*[\.\-0-9]/',$p[2])) { | ||
727 | $new['blur'] = $this->mpdf->ConvertSize(trim($p[2]),$this->mpdf->blk[$this->mpdf->blklvl-1]['inner_width'],$this->mpdf->FontSize,false); | ||
728 | } | ||
729 | else { $new['col'] = $this->mpdf->ConvertColor(preg_replace('/\*/',',',$p[2])); } | ||
730 | if (isset($p[3])) { | ||
731 | if (preg_match('/^\s*[\.\-0-9]/',$p[3])) { | ||
732 | $new['spread'] = $this->mpdf->ConvertSize(trim($p[3]),$this->mpdf->blk[$this->mpdf->blklvl-1]['inner_width'],$this->mpdf->FontSize,false); | ||
733 | } | ||
734 | else { $new['col'] = $this->mpdf->ConvertColor(preg_replace('/\*/',',',$p[3])); } | ||
735 | if (isset($p[4])) { | ||
736 | $new['col'] = $this->mpdf->ConvertColor(preg_replace('/\*/',',',$p[4])); | ||
737 | } | ||
738 | } | ||
739 | } | ||
740 | if (!$new['col']) { $new['col'] = $this->mpdf->ConvertColor('#888888'); } | ||
741 | if (isset($new['y'])) { array_unshift($sh, $new); } | ||
742 | } | ||
743 | return $sh; | ||
744 | } | ||
745 | |||
746 | function setCSStextshadow($v) { | ||
747 | $sh = array(); | ||
748 | $c = preg_match_all('/(rgba|rgb|device-cmyka|cmyka|device-cmyk|cmyk|hsla|hsl)\(.*?\)/',$v,$x); // mPDF 5.6.05 | ||
749 | for($i=0; $i<$c; $i++) { | ||
750 | $col = preg_replace('/,/','*',$x[0][$i]); | ||
751 | $v = preg_replace('/'.preg_quote($x[0][$i],'/').'/',$col,$v); | ||
752 | } | ||
753 | $ss = explode(',',$v); | ||
754 | foreach ($ss AS $s) { | ||
755 | $new = array('blur'=>0); | ||
756 | $p = explode(' ',trim($s)); | ||
757 | if (isset($p[0])) { $new['x'] = $this->mpdf->ConvertSize(trim($p[0]),$this->mpdf->blk[$this->mpdf->blklvl-1]['inner_width'],$this->mpdf->FontSize,false); } | ||
758 | if (isset($p[1])) { $new['y'] = $this->mpdf->ConvertSize(trim($p[1]),$this->mpdf->blk[$this->mpdf->blklvl-1]['inner_width'],$this->mpdf->FontSize,false); } | ||
759 | if (isset($p[2])) { | ||
760 | if (preg_match('/^\s*[\.\-0-9]/',$p[2])) { | ||
761 | $new['blur'] = $this->mpdf->ConvertSize(trim($p[2]),$this->mpdf->blk[$this->mpdf->blklvl-1]['inner_width'],$this->mpdf->FontSize,false); | ||
762 | } | ||
763 | else { $new['col'] = $this->mpdf->ConvertColor(preg_replace('/\*/',',',$p[2])); } | ||
764 | if (isset($p[3])) { | ||
765 | $new['col'] = $this->mpdf->ConvertColor(preg_replace('/\*/',',',$p[3])); | ||
766 | } | ||
767 | } | ||
768 | if (!$new['col']) { $new['col'] = $this->mpdf->ConvertColor('#888888'); } | ||
769 | if (isset($new['y'])) { array_unshift($sh, $new); } | ||
770 | } | ||
771 | return $sh; | ||
772 | } | ||
773 | |||
774 | function parseCSSbackground($s) { | ||
775 | $bg = array('c'=>false, 'i'=>false, 'r'=>false, 'p'=>false, ); | ||
776 | /*-- BACKGROUNDS --*/ | ||
777 | if (preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient\(.*\)/i',$s,$m)) { | ||
778 | $bg['i'] = $m[0]; | ||
779 | } | ||
780 | else | ||
781 | /*-- END BACKGROUNDS --*/ | ||
782 | if (preg_match('/url\(/i',$s)) { | ||
783 | // If color, set and strip it off | ||
784 | // mPDF 5.6.05 | ||
785 | if (preg_match('/^\s*(#[0-9a-fA-F]{3,6}|(rgba|rgb|device-cmyka|cmyka|device-cmyk|cmyk|hsla|hsl|spot)\(.*?\)|[a-zA-Z]{3,})\s+(url\(.*)/i',$s,$m)) { | ||
786 | $bg['c'] = strtolower($m[1]); | ||
787 | $s = $m[3]; | ||
788 | } | ||
789 | /*-- BACKGROUNDS --*/ | ||
790 | if (preg_match('/url\([\'\"]{0,1}(.*?)[\'\"]{0,1}\)\s*(.*)/i',$s,$m)) { | ||
791 | $bg['i'] = $m[1]; | ||
792 | $s = strtolower($m[2]); | ||
793 | if (preg_match('/(repeat-x|repeat-y|no-repeat|repeat)/',$s,$m)) { | ||
794 | $bg['r'] = $m[1]; | ||
795 | } | ||
796 | // Remove repeat, attachment (discarded) and also any inherit | ||
797 | $s = preg_replace('/(repeat-x|repeat-y|no-repeat|repeat|scroll|fixed|inherit)/','',$s); | ||
798 | $bits = preg_split('/\s+/',trim($s)); | ||
799 | // These should be Position x1 or x2 | ||
800 | if (count($bits)==1) { | ||
801 | if (preg_match('/bottom/',$bits[0])) { $bg['p'] = '50% 100%'; } | ||
802 | else if (preg_match('/top/',$bits[0])) { $bg['p'] = '50% 0%'; } | ||
803 | else { $bg['p'] = $bits[0] . ' 50%'; } | ||
804 | } | ||
805 | else if (count($bits)==2) { | ||
806 | // Can be either right center or center right | ||
807 | if (preg_match('/(top|bottom)/',$bits[0]) || preg_match('/(left|right)/',$bits[1])) { | ||
808 | $bg['p'] = $bits[1] . ' '.$bits[0]; | ||
809 | } | ||
810 | else { | ||
811 | $bg['p'] = $bits[0] . ' '.$bits[1]; | ||
812 | } | ||
813 | } | ||
814 | if ($bg['p']) { | ||
815 | $bg['p'] = preg_replace('/(left|top)/','0%',$bg['p']); | ||
816 | $bg['p'] = preg_replace('/(right|bottom)/','100%',$bg['p']); | ||
817 | $bg['p'] = preg_replace('/(center)/','50%',$bg['p']); | ||
818 | if (!preg_match('/[\-]{0,1}\d+(in|cm|mm|pt|pc|em|ex|px|%)* [\-]{0,1}\d+(in|cm|mm|pt|pc|em|ex|px|%)*/',$bg['p'])) { | ||
819 | $bg['p'] = false; | ||
820 | } | ||
821 | } | ||
822 | } | ||
823 | /*-- END BACKGROUNDS --*/ | ||
824 | } | ||
825 | else if (preg_match('/^\s*(#[0-9a-fA-F]{3,6}|(rgba|rgb|device-cmyka|cmyka|device-cmyk|cmyk|hsla|hsl|spot)\(.*?\)|[a-zA-Z]{3,})/i',$s,$m)) { $bg['c'] = strtolower($m[1]); } // mPDF 5.6.05 | ||
826 | return ($bg); | ||
827 | } | ||
828 | |||
829 | |||
830 | function expand24($mp) { | ||
831 | $prop = preg_split('/\s+/',trim($mp)); | ||
832 | if (count($prop) == 1 ) { | ||
833 | return array('T' => $prop[0], 'R' => $prop[0], 'B' => $prop[0], 'L'=> $prop[0]); | ||
834 | } | ||
835 | if (count($prop) == 2 ) { | ||
836 | return array('T' => $prop[0], 'R' => $prop[1], 'B' => $prop[0], 'L'=> $prop[1]); | ||
837 | } | ||
838 | |||
839 | if (count($prop) == 3 ) { | ||
840 | return array('T' => $prop[0], 'R' => $prop[1], 'B' => $prop[2], 'L'=> $prop[1]); | ||
841 | } | ||
842 | if (count($prop) == 4 ) { | ||
843 | return array('T' => $prop[0], 'R' => $prop[1], 'B' => $prop[2], 'L'=> $prop[3]); | ||
844 | } | ||
845 | return array(); | ||
846 | } | ||
847 | |||
848 | /*-- BORDER-RADIUS --*/ | ||
849 | function border_radius_expand($val,$k) { | ||
850 | $b = array(); | ||
851 | if ($k == 'BORDER-RADIUS') { | ||
852 | $hv = explode('/',trim($val)); | ||
853 | $prop = preg_split('/\s+/',trim($hv[0])); | ||
854 | if (count($prop)==1) { | ||
855 | $b['TL-H'] = $b['TR-H'] = $b['BR-H'] = $b['BL-H'] = $prop[0]; | ||
856 | } | ||
857 | else if (count($prop)==2) { | ||
858 | $b['TL-H'] = $b['BR-H'] = $prop[0]; | ||
859 | $b['TR-H'] = $b['BL-H'] = $prop[1]; | ||
860 | } | ||
861 | else if (count($prop)==3) { | ||
862 | $b['TL-H'] = $prop[0]; | ||
863 | $b['TR-H'] = $b['BL-H'] = $prop[1]; | ||
864 | $b['BR-H'] = $prop[2]; | ||
865 | } | ||
866 | else if (count($prop)==4) { | ||
867 | $b['TL-H'] = $prop[0]; | ||
868 | $b['TR-H'] = $prop[1]; | ||
869 | $b['BR-H'] = $prop[2]; | ||
870 | $b['BL-H'] = $prop[3]; | ||
871 | } | ||
872 | if (count($hv)==2) { | ||
873 | $prop = preg_split('/\s+/',trim($hv[1])); | ||
874 | if (count($prop)==1) { | ||
875 | $b['TL-V'] = $b['TR-V'] = $b['BR-V'] = $b['BL-V'] = $prop[0]; | ||
876 | } | ||
877 | else if (count($prop)==2) { | ||
878 | $b['TL-V'] = $b['BR-V'] = $prop[0]; | ||
879 | $b['TR-V'] = $b['BL-V'] = $prop[1]; | ||
880 | } | ||
881 | else if (count($prop)==3) { | ||
882 | $b['TL-V'] = $prop[0]; | ||
883 | $b['TR-V'] = $b['BL-V'] = $prop[1]; | ||
884 | $b['BR-V'] = $prop[2]; | ||
885 | } | ||
886 | else if (count($prop)==4) { | ||
887 | $b['TL-V'] = $prop[0]; | ||
888 | $b['TR-V'] = $prop[1]; | ||
889 | $b['BR-V'] = $prop[2]; | ||
890 | $b['BL-V'] = $prop[3]; | ||
891 | } | ||
892 | } | ||
893 | else { | ||
894 | $b['TL-V'] = $b['TL-H']; | ||
895 | $b['TR-V'] = $b['TR-H']; | ||
896 | $b['BL-V'] = $b['BL-H']; | ||
897 | $b['BR-V'] = $b['BR-H']; | ||
898 | } | ||
899 | return $b; | ||
900 | } | ||
901 | |||
902 | // Parse 2 | ||
903 | $h = 0; | ||
904 | $v = 0; | ||
905 | $prop = preg_split('/\s+/',trim($val)); | ||
906 | if (count($prop)==1) { $h = $v = $val; } | ||
907 | else { $h = $prop[0]; $v = $prop[1]; } | ||
908 | if ($h==0 || $v==0) { $h = $v = 0; } | ||
909 | if ($k == 'BORDER-TOP-LEFT-RADIUS') { | ||
910 | $b['TL-H'] = $h; | ||
911 | $b['TL-V'] = $v; | ||
912 | } | ||
913 | else if ($k == 'BORDER-TOP-RIGHT-RADIUS') { | ||
914 | $b['TR-H'] = $h; | ||
915 | $b['TR-V'] = $v; | ||
916 | } | ||
917 | else if ($k == 'BORDER-BOTTOM-LEFT-RADIUS') { | ||
918 | $b['BL-H'] = $h; | ||
919 | $b['BL-V'] = $v; | ||
920 | } | ||
921 | else if ($k == 'BORDER-BOTTOM-RIGHT-RADIUS') { | ||
922 | $b['BR-H'] = $h; | ||
923 | $b['BR-V'] = $v; | ||
924 | } | ||
925 | return $b; | ||
926 | |||
927 | } | ||
928 | /*-- END BORDER-RADIUS --*/ | ||
929 | |||
930 | function _mergeCSS($p, &$t) { | ||
931 | // Save Cascading CSS e.g. "div.topic p" at this block level | ||
932 | if (isset($p) && $p) { | ||
933 | if ($t) { | ||
934 | $t = $this->array_merge_recursive_unique($t, $p); | ||
935 | } | ||
936 | else { $t = $p; } | ||
937 | } | ||
938 | } | ||
939 | |||
940 | // for CSS handling | ||
941 | function array_merge_recursive_unique($array1, $array2) { | ||
942 | $arrays = func_get_args(); | ||
943 | $narrays = count($arrays); | ||
944 | $ret = $arrays[0]; | ||
945 | for ($i = 1; $i < $narrays; $i ++) { | ||
946 | foreach ($arrays[$i] as $key => $value) { | ||
947 | if (((string) $key) === ((string) intval($key))) { // integer or string as integer key - append | ||
948 | $ret[] = $value; | ||
949 | } | ||
950 | else { // string key - merge | ||
951 | if (is_array($value) && isset($ret[$key])) { | ||
952 | $ret[$key] = $this->array_merge_recursive_unique($ret[$key], $value); | ||
953 | } | ||
954 | else { | ||
955 | $ret[$key] = $value; | ||
956 | } | ||
957 | } | ||
958 | } | ||
959 | } | ||
960 | return $ret; | ||
961 | } | ||
962 | |||
963 | |||
964 | |||
965 | function _mergeFullCSS($p, &$t, $tag, $classes, $id) { | ||
966 | $this->_mergeCSS($p[$tag], $t); | ||
967 | // STYLESHEET CLASS e.g. .smallone{} .redletter{} | ||
968 | foreach($classes AS $class) { | ||
969 | $this->_mergeCSS($p['CLASS>>'.$class], $t); | ||
970 | } | ||
971 | // STYLESHEET nth-child SELECTOR e.g. tr:nth-child(odd) td:nth-child(2n+1) | ||
972 | if ($tag=='TR' && isset($p) && $p) { | ||
973 | foreach($p AS $k=>$val) { | ||
974 | if (preg_match('/'.$tag.'>>SELECTORNTHCHILD>>(.*)/',$k, $m)) { | ||
975 | $select = false; | ||
976 | if ($tag=='TR') { | ||
977 | $row = $this->mpdf->row; | ||
978 | $thnr = (isset($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['is_thead']) ? count($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['is_thead']) : 0); | ||
979 | $tfnr = (isset($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['is_tfoot']) ? count($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['is_tfoot']) : 0); | ||
980 | if ($this->mpdf->tabletfoot) { $row -= $thnr; } | ||
981 | else if (!$this->mpdf->tablethead) { $row -= ($thnr + $tfnr); } | ||
982 | if ($m[1]=='ODD' && ($row % 2) == 0) { $select = true; } | ||
983 | else if ($m[1]=='EVEN' && ($row % 2) == 1) { $select = true; } | ||
984 | else if (preg_match('/(\d+)N\+(\d+)/',$m[1],$a)) { | ||
985 | if ((($row + 1) % $a[1]) == $a[2]) { $select = true; } | ||
986 | } | ||
987 | } | ||
988 | else if ($tag=='TD' || $tag=='TH') { | ||
989 | if ($m[1]=='ODD' && ($this->mpdf->col % 2) == 0) { $select = true; } | ||
990 | else if ($m[1]=='EVEN' && ($this->mpdf->col % 2) == 1) { $select = true; } | ||
991 | else if (preg_match('/(\d+)N\+(\d+)/',$m[1],$a)) { | ||
992 | if ((($this->mpdf->col + 1) % $a[1]) == $a[2]) { $select = true; } | ||
993 | } | ||
994 | } | ||
995 | if ($select) { | ||
996 | $this->_mergeCSS($p[$tag.'>>SELECTORNTHCHILD>>'.$m[1]], $t); | ||
997 | } | ||
998 | } | ||
999 | } | ||
1000 | } | ||
1001 | // STYLESHEET CLASS e.g. #smallone{} #redletter{} | ||
1002 | if (isset($id) && $id) { | ||
1003 | $this->_mergeCSS($p['ID>>'.$id], $t); | ||
1004 | } | ||
1005 | // STYLESHEET CLASS e.g. .smallone{} .redletter{} | ||
1006 | foreach($classes AS $class) { | ||
1007 | $this->_mergeCSS($p[$tag.'>>CLASS>>'.$class], $t); | ||
1008 | } | ||
1009 | // STYLESHEET CLASS e.g. #smallone{} #redletter{} | ||
1010 | if (isset($id)) { | ||
1011 | $this->_mergeCSS($p[$tag.'>>ID>>'.$id], $t); | ||
1012 | } | ||
1013 | } | ||
1014 | |||
1015 | function setBorderDominance($prop, $val) { | ||
1016 | if (isset($prop['BORDER-LEFT']) && $prop['BORDER-LEFT']) { $this->cell_border_dominance_L = $val; } | ||
1017 | if (isset($prop['BORDER-RIGHT']) && $prop['BORDER-RIGHT']) { $this->cell_border_dominance_R = $val; } | ||
1018 | if (isset($prop['BORDER-TOP']) && $prop['BORDER-TOP']) { $this->cell_border_dominance_T = $val; } | ||
1019 | if (isset($prop['BORDER-BOTTOM']) && $prop['BORDER-BOTTOM']) { $this->cell_border_dominance_B = $val; } | ||
1020 | } | ||
1021 | |||
1022 | function _set_mergedCSS(&$m, &$p, $d=true, $bd=false) { | ||
1023 | if (isset($m)) { | ||
1024 | if ((isset($m['depth']) && $m['depth']>1) || $d==false) { // include check for 'depth' | ||
1025 | if ($bd) { $this->setBorderDominance($m, $bd); } // *TABLES* | ||
1026 | if (is_array($m)) { | ||
1027 | $p = array_merge($p,$m); | ||
1028 | $this->_mergeBorders($p,$m); | ||
1029 | } | ||
1030 | } | ||
1031 | } | ||
1032 | } | ||
1033 | |||
1034 | |||
1035 | function _mergeBorders(&$b, &$a) { // Merges $a['BORDER-TOP-STYLE'] to $b['BORDER-TOP'] etc. | ||
1036 | foreach(array('TOP','RIGHT','BOTTOM','LEFT') AS $side) { | ||
1037 | foreach(array('STYLE','WIDTH','COLOR') AS $el) { | ||
1038 | if (isset($a['BORDER-'.$side.'-'.$el])) { // e.g. $b['BORDER-TOP-STYLE'] | ||
1039 | $s = trim($a['BORDER-'.$side.'-'.$el]); | ||
1040 | if (isset($b['BORDER-'.$side])) { // e.g. $b['BORDER-TOP'] | ||
1041 | $p = trim($b['BORDER-'.$side]); | ||
1042 | } | ||
1043 | else { $p = ''; } | ||
1044 | if ($el=='STYLE') { | ||
1045 | if ($p) { $b['BORDER-'.$side] = preg_replace('/(\S+)\s+(\S+)\s+(\S+)/', '\\1 '.$s.' \\3', $p); } | ||
1046 | else { $b['BORDER-'.$side] = '0px '.$s.' #000000'; } | ||
1047 | } | ||
1048 | else if ($el=='WIDTH') { | ||
1049 | if ($p) { $b['BORDER-'.$side] = preg_replace('/(\S+)\s+(\S+)\s+(\S+)/', $s.' \\2 \\3', $p); } | ||
1050 | else { $b['BORDER-'.$side] = $s.' none #000000'; } | ||
1051 | } | ||
1052 | else if ($el=='COLOR') { | ||
1053 | if ($p) { $b['BORDER-'.$side] = preg_replace('/(\S+)\s+(\S+)\s+(\S+)/', '\\1 \\2 '.$s, $p); } | ||
1054 | else { $b['BORDER-'.$side] = '0px none '.$s; } | ||
1055 | } | ||
1056 | } | ||
1057 | } | ||
1058 | } | ||
1059 | } | ||
1060 | |||
1061 | |||
1062 | function MergeCSS($inherit,$tag,$attr) { | ||
1063 | $p = array(); | ||
1064 | $zp = array(); | ||
1065 | |||
1066 | $classes = array(); | ||
1067 | if (isset($attr['CLASS'])) { | ||
1068 | $classes = preg_split('/\s+/',$attr['CLASS']); | ||
1069 | } | ||
1070 | if (!isset($attr['ID'])) { $attr['ID']=''; } | ||
1071 | //=============================================== | ||
1072 | /*-- TABLES --*/ | ||
1073 | // Set Inherited properties | ||
1074 | if ($inherit == 'TOPTABLE') { // $tag = TABLE | ||
1075 | //=============================================== | ||
1076 | // Save Cascading CSS e.g. "div.topic p" at this block level | ||
1077 | |||
1078 | if (isset($this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'])) { | ||
1079 | $this->tablecascadeCSS[0] = $this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS']; | ||
1080 | } | ||
1081 | else { | ||
1082 | $this->tablecascadeCSS[0] = $this->cascadeCSS; | ||
1083 | } | ||
1084 | } | ||
1085 | //=============================================== | ||
1086 | // Set Inherited properties | ||
1087 | if ($inherit == 'TOPTABLE' || $inherit == 'TABLE') { | ||
1088 | //Cascade everything from last level that is not an actual property, or defined by current tag/attributes | ||
1089 | if (isset($this->tablecascadeCSS[$this->tbCSSlvl-1]) && is_array($this->tablecascadeCSS[$this->tbCSSlvl-1])) { | ||
1090 | foreach($this->tablecascadeCSS[$this->tbCSSlvl-1] AS $k=>$v) { | ||
1091 | $this->tablecascadeCSS[$this->tbCSSlvl][$k] = $v; | ||
1092 | } | ||
1093 | } | ||
1094 | $this->_mergeFullCSS($this->cascadeCSS, $this->tablecascadeCSS[$this->tbCSSlvl], $tag, $classes, $attr['ID']); | ||
1095 | //=============================================== | ||
1096 | // Cascading forward CSS e.g. "table.topic td" for this table in $this->tablecascadeCSS | ||
1097 | //=============================================== | ||
1098 | // STYLESHEET TAG e.g. table | ||
1099 | $this->_mergeFullCSS($this->tablecascadeCSS[$this->tbCSSlvl-1], $this->tablecascadeCSS[$this->tbCSSlvl], $tag, $classes, $attr['ID']); | ||
1100 | //=============================================== | ||
1101 | } | ||
1102 | /*-- END TABLES --*/ | ||
1103 | //=============================================== | ||
1104 | /*-- LISTS --*/ | ||
1105 | // Set Inherited properties | ||
1106 | if ($inherit == 'TOPLIST') { // $tag = UL,OL | ||
1107 | //=============================================== | ||
1108 | // Save Cascading CSS e.g. "div.topic p" at this block level | ||
1109 | if (isset($this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'])) { | ||
1110 | $this->listcascadeCSS[0] = $this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS']; | ||
1111 | } | ||
1112 | else { | ||
1113 | $this->listcascadeCSS[0] = $this->cascadeCSS; | ||
1114 | } | ||
1115 | } | ||
1116 | //=============================================== | ||
1117 | // Set Inherited properties | ||
1118 | if ($inherit == 'TOPLIST' || $inherit == 'LIST') { | ||
1119 | //Cascade everything from last level that is not an actual property, or defined by current tag/attributes | ||
1120 | if (isset($this->listcascadeCSS[$this->listCSSlvl-1]) && is_array($this->listcascadeCSS[$this->listCSSlvl-1])) { | ||
1121 | foreach($this->listcascadeCSS[$this->listCSSlvl-1] AS $k=>$v) { | ||
1122 | $this->listcascadeCSS[$this->listCSSlvl][$k] = $v; | ||
1123 | } | ||
1124 | } | ||
1125 | $this->_mergeFullCSS($this->cascadeCSS, $this->listcascadeCSS[$this->listCSSlvl], $tag, $classes, $attr['ID']); | ||
1126 | //=============================================== | ||
1127 | // Cascading forward CSS e.g. "table.topic td" for this list in $this->listcascadeCSS | ||
1128 | //=============================================== | ||
1129 | // STYLESHEET TAG e.g. table | ||
1130 | $this->_mergeFullCSS($this->listcascadeCSS[$this->listCSSlvl-1], $this->listcascadeCSS[$this->listCSSlvl], $tag, $classes, $attr['ID']); | ||
1131 | //=============================================== | ||
1132 | } | ||
1133 | /*-- END LISTS --*/ | ||
1134 | //=============================================== | ||
1135 | // Set Inherited properties | ||
1136 | if ($inherit == 'BLOCK') { | ||
1137 | if (isset($this->mpdf->blk[$this->mpdf->blklvl-1]['cascadeCSS']) && is_array($this->mpdf->blk[$this->mpdf->blklvl-1]['cascadeCSS'])) { | ||
1138 | foreach($this->mpdf->blk[$this->mpdf->blklvl-1]['cascadeCSS'] AS $k=>$v) { | ||
1139 | $this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'][$k] = $v; | ||
1140 | |||
1141 | } | ||
1142 | } | ||
1143 | |||
1144 | //=============================================== | ||
1145 | // Save Cascading CSS e.g. "div.topic p" at this block level | ||
1146 | $this->_mergeFullCSS($this->cascadeCSS, $this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'], $tag, $classes, $attr['ID']); | ||
1147 | //=============================================== | ||
1148 | // Cascading forward CSS | ||
1149 | //=============================================== | ||
1150 | $this->_mergeFullCSS($this->mpdf->blk[$this->mpdf->blklvl-1]['cascadeCSS'], $this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'], $tag, $classes, $attr['ID']); | ||
1151 | //=============================================== | ||
1152 | // Block properties | ||
1153 | if (isset($this->mpdf->blk[$this->mpdf->blklvl-1]['margin_collapse']) && $this->mpdf->blk[$this->mpdf->blklvl-1]['margin_collapse']) { $p['MARGIN-COLLAPSE'] = 'COLLAPSE'; } // custom tag, but follows CSS principle that border-collapse is inherited | ||
1154 | if (isset($this->mpdf->blk[$this->mpdf->blklvl-1]['line_height']) && $this->mpdf->blk[$this->mpdf->blklvl-1]['line_height']) { $p['LINE-HEIGHT'] = $this->mpdf->blk[$this->mpdf->blklvl-1]['line_height']; } | ||
1155 | |||
1156 | if (isset($this->mpdf->blk[$this->mpdf->blklvl-1]['direction']) && $this->mpdf->blk[$this->mpdf->blklvl-1]['direction']) { $p['DIRECTION'] = $this->mpdf->blk[$this->mpdf->blklvl-1]['direction']; } | ||
1157 | |||
1158 | if (isset($this->mpdf->blk[$this->mpdf->blklvl-1]['align']) && $this->mpdf->blk[$this->mpdf->blklvl-1]['align']) { | ||
1159 | if ($this->mpdf->blk[$this->mpdf->blklvl-1]['align'] == 'L') { $p['TEXT-ALIGN'] = 'left'; } | ||
1160 | else if ($this->mpdf->blk[$this->mpdf->blklvl-1]['align'] == 'J') { $p['TEXT-ALIGN'] = 'justify'; } | ||
1161 | else if ($this->mpdf->blk[$this->mpdf->blklvl-1]['align'] == 'R') { $p['TEXT-ALIGN'] = 'right'; } | ||
1162 | else if ($this->mpdf->blk[$this->mpdf->blklvl-1]['align'] == 'C') { $p['TEXT-ALIGN'] = 'center'; } | ||
1163 | } | ||
1164 | if ($this->mpdf->ColActive || $this->mpdf->keep_block_together) { | ||
1165 | if (isset($this->mpdf->blk[$this->mpdf->blklvl-1]['bgcolor']) && $this->mpdf->blk[$this->mpdf->blklvl-1]['bgcolor']) { // Doesn't officially inherit, but default value is transparent (?=inherited) | ||
1166 | $cor = $this->mpdf->blk[$this->mpdf->blklvl-1]['bgcolorarray' ]; | ||
1167 | $p['BACKGROUND-COLOR'] = $this->mpdf->_colAtoString($cor); | ||
1168 | } | ||
1169 | } | ||
1170 | |||
1171 | if (isset($this->mpdf->blk[$this->mpdf->blklvl-1]['text_indent']) && ($this->mpdf->blk[$this->mpdf->blklvl-1]['text_indent'] || $this->mpdf->blk[$this->mpdf->blklvl-1]['text_indent']===0)) { $p['TEXT-INDENT'] = $this->mpdf->blk[$this->mpdf->blklvl-1]['text_indent']; } | ||
1172 | if (isset($this->mpdf->blk[$this->mpdf->blklvl-1]['InlineProperties'])) { | ||
1173 | $biilp = $this->mpdf->blk[$this->mpdf->blklvl-1]['InlineProperties']; | ||
1174 | } | ||
1175 | else { $biilp = null; } | ||
1176 | if (isset($biilp[ 'family' ]) && $biilp[ 'family' ]) { $p['FONT-FAMILY'] = $biilp[ 'family' ]; } | ||
1177 | if (isset($biilp[ 'I' ]) && $biilp[ 'I' ]) { $p['FONT-STYLE'] = 'italic'; } | ||
1178 | if (isset($biilp[ 'sizePt' ]) && $biilp[ 'sizePt' ]) { $p['FONT-SIZE'] = $biilp[ 'sizePt' ] . 'pt'; } | ||
1179 | if (isset($biilp[ 'B' ]) && $biilp[ 'B' ]) { $p['FONT-WEIGHT'] = 'bold'; } | ||
1180 | if (isset($biilp[ 'colorarray' ]) && $biilp[ 'colorarray' ]) { | ||
1181 | $cor = $biilp[ 'colorarray' ]; | ||
1182 | $p['COLOR'] = $this->mpdf->_colAtoString($cor); | ||
1183 | } | ||
1184 | if (isset($biilp[ 'fontkerning' ])) { | ||
1185 | if ($biilp[ 'fontkerning' ]) { $p['FONT-KERNING'] = 'normal'; } | ||
1186 | else { $p['FONT-KERNING'] = 'none'; } | ||
1187 | } | ||
1188 | if (isset($biilp[ 'lSpacingCSS' ]) && $biilp[ 'lSpacingCSS' ]) { $p['LETTER-SPACING'] = $biilp[ 'lSpacingCSS' ]; } | ||
1189 | if (isset($biilp[ 'wSpacingCSS' ]) && $biilp[ 'wSpacingCSS' ]) { $p['WORD-SPACING'] = $biilp[ 'wSpacingCSS' ]; } | ||
1190 | if (isset($biilp[ 'toupper' ]) && $biilp[ 'toupper' ]) { $p['TEXT-TRANSFORM'] = 'uppercase'; } | ||
1191 | else if (isset($biilp[ 'tolower' ]) && $biilp[ 'tolower' ]) { $p['TEXT-TRANSFORM'] = 'lowercase'; } | ||
1192 | else if (isset($biilp[ 'capitalize' ]) && $biilp[ 'capitalize' ]) { $p['TEXT-TRANSFORM'] = 'capitalize'; } | ||
1193 | // CSS says text-decoration is not inherited, but IE7 does?? | ||
1194 | if (isset($biilp[ 'underline' ]) && $biilp[ 'underline' ]) { $p['TEXT-DECORATION'] = 'underline'; } | ||
1195 | if (isset($biilp[ 'smCaps' ]) && $biilp[ 'smCaps' ]) { $p['FONT-VARIANT'] = 'small-caps'; } | ||
1196 | |||
1197 | } | ||
1198 | //=============================================== | ||
1199 | //=============================================== | ||
1200 | /*-- LISTS --*/ | ||
1201 | // Set Inherited properties | ||
1202 | if ($inherit == 'TOPLIST') { | ||
1203 | if ($this->listCSSlvl == 1) { | ||
1204 | $bilp = $this->mpdf->blk[$this->mpdf->blklvl]['InlineProperties']; | ||
1205 | if (isset($bilp[ 'family' ]) && $bilp[ 'family' ]) { $p['FONT-FAMILY'] = $bilp[ 'family' ]; } | ||
1206 | if (isset($bilp[ 'I' ]) && $bilp[ 'I' ]) { $p['FONT-STYLE'] = 'italic'; } | ||
1207 | if (isset($bilp[ 'sizePt' ]) && $bilp[ 'sizePt' ]) { $p['FONT-SIZE'] = $bilp[ 'sizePt' ] . 'pt'; } | ||
1208 | if (isset($bilp[ 'B' ]) && $bilp[ 'B' ]) { $p['FONT-WEIGHT'] = 'bold'; } | ||
1209 | if (isset($bilp[ 'colorarray' ]) && $bilp[ 'colorarray' ]) { | ||
1210 | $cor = $bilp[ 'colorarray' ]; | ||
1211 | $p['COLOR'] = $this->mpdf->_colAtoString($cor); | ||
1212 | } | ||
1213 | if (isset($bilp[ 'toupper' ]) && $bilp[ 'toupper' ]) { $p['TEXT-TRANSFORM'] = 'uppercase'; } | ||
1214 | else if (isset($bilp[ 'tolower' ]) && $bilp[ 'tolower' ]) { $p['TEXT-TRANSFORM'] = 'lowercase'; } | ||
1215 | else if (isset($bilp[ 'capitalize' ]) && $bilp[ 'capitalize' ]) { $p['TEXT-TRANSFORM'] = 'capitalize'; } | ||
1216 | if (isset($bilp[ 'fontkerning' ])) { | ||
1217 | if ($bilp[ 'fontkerning' ]) { $p['FONT-KERNING'] = 'normal'; } | ||
1218 | else { $p['FONT-KERNING'] = 'none'; } | ||
1219 | } | ||
1220 | if (isset($bilp[ 'lSpacingCSS' ]) && $bilp[ 'lSpacingCSS' ]) { $p['LETTER-SPACING'] = $bilp[ 'lSpacingCSS' ]; } | ||
1221 | if (isset($bilp[ 'wSpacingCSS' ]) && $bilp[ 'wSpacingCSS' ]) { $p['WORD-SPACING'] = $bilp[ 'wSpacingCSS' ]; } | ||
1222 | // CSS says text-decoration is not inherited, but IE7 does?? | ||
1223 | if (isset($bilp[ 'underline' ]) && $bilp[ 'underline' ]) { $p['TEXT-DECORATION'] = 'underline'; } | ||
1224 | if (isset($bilp[ 'smCaps' ]) && $bilp[ 'smCaps' ]) { $p['FONT-VARIANT'] = 'small-caps'; } | ||
1225 | if ($tag=='LI') { | ||
1226 | // Note to self - this should never work, as TOPLIST is not called when LI (see code removed in v5.3) | ||
1227 | $this->mpdf->Error("If you see this message, please report this as a bug to the mPDF Forum."); | ||
1228 | } | ||
1229 | } | ||
1230 | } | ||
1231 | /*-- END LISTS --*/ | ||
1232 | //=============================================== | ||
1233 | //=============================================== | ||
1234 | // DEFAULT for this TAG set in DefaultCSS | ||
1235 | if (isset($this->mpdf->defaultCSS[$tag])) { | ||
1236 | $zp = $this->fixCSS($this->mpdf->defaultCSS[$tag]); | ||
1237 | if (is_array($zp)) { // Default overwrites Inherited | ||
1238 | $p = array_merge($p,$zp); // !! Note other way round !! | ||
1239 | $this->_mergeBorders($p,$zp); | ||
1240 | } | ||
1241 | } | ||
1242 | //=============================================== | ||
1243 | /*-- TABLES --*/ | ||
1244 | // cellPadding overwrites TD/TH default but not specific CSS set on cell | ||
1245 | if (($tag=='TD' || $tag=='TH') && isset($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['cell_padding']) && ($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['cell_padding'] || $this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['cell_padding']===0)) { | ||
1246 | $p['PADDING-LEFT'] = $this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['cell_padding']; | ||
1247 | $p['PADDING-RIGHT'] = $this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['cell_padding']; | ||
1248 | $p['PADDING-TOP'] = $this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['cell_padding']; | ||
1249 | $p['PADDING-BOTTOM'] = $this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['cell_padding']; | ||
1250 | } | ||
1251 | /*-- END TABLES --*/ | ||
1252 | //=============================================== | ||
1253 | // STYLESHEET TAG e.g. h1 p div table | ||
1254 | if (isset($this->CSS[$tag]) && $this->CSS[$tag]) { | ||
1255 | $zp = $this->CSS[$tag]; | ||
1256 | if ($tag=='TD' || $tag=='TH') { $this->setBorderDominance($zp, 9); } // *TABLES* // *TABLES-ADVANCED-BORDERS* | ||
1257 | if (is_array($zp)) { | ||
1258 | $p = array_merge($p,$zp); | ||
1259 | $this->_mergeBorders($p,$zp); | ||
1260 | } | ||
1261 | } | ||
1262 | //=============================================== | ||
1263 | // STYLESHEET CLASS e.g. .smallone{} .redletter{} | ||
1264 | foreach($classes AS $class) { | ||
1265 | $zp = array(); | ||
1266 | if (isset($this->CSS['CLASS>>'.$class]) && $this->CSS['CLASS>>'.$class]) { $zp = $this->CSS['CLASS>>'.$class]; } | ||
1267 | if ($tag=='TD' || $tag=='TH') { $this->setBorderDominance($zp, 9); } // *TABLES* // *TABLES-ADVANCED-BORDERS* | ||
1268 | if (is_array($zp)) { | ||
1269 | $p = array_merge($p,$zp); | ||
1270 | $this->_mergeBorders($p,$zp); | ||
1271 | } | ||
1272 | } | ||
1273 | //=============================================== | ||
1274 | /*-- TABLES --*/ | ||
1275 | // STYLESHEET nth-child SELECTOR e.g. tr:nth-child(odd) td:nth-child(2n+1) | ||
1276 | if ($tag=='TR' || $tag=='TD' || $tag=='TH') { | ||
1277 | foreach($this->CSS AS $k=>$val) { | ||
1278 | if (preg_match('/'.$tag.'>>SELECTORNTHCHILD>>(.*)/',$k, $m)) { | ||
1279 | $select = false; | ||
1280 | if ($tag=='TR') { | ||
1281 | $row = $this->mpdf->row; | ||
1282 | $thnr = (isset($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['is_thead']) ? count($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['is_thead']) : 0); | ||
1283 | $tfnr = (isset($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['is_tfoot']) ? count($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['is_tfoot']) : 0); | ||
1284 | if ($this->mpdf->tabletfoot) { $row -= $thnr; } | ||
1285 | else if (!$this->mpdf->tablethead) { $row -= ($thnr + $tfnr); } | ||
1286 | if ($m[1]=='ODD' && ($row % 2) == 0) { $select = true; } | ||
1287 | else if ($m[1]=='EVEN' && ($row % 2) == 1) { $select = true; } | ||
1288 | else if (preg_match('/(\d+)N\+(\d+)/',$m[1],$a)) { | ||
1289 | if ((($row + 1) % $a[1]) == $a[2]) { $select = true; } | ||
1290 | } | ||
1291 | } | ||
1292 | else if ($tag=='TD' || $tag=='TH') { | ||
1293 | if ($m[1]=='ODD' && ($this->mpdf->col % 2) == 0) { $select = true; } | ||
1294 | else if ($m[1]=='EVEN' && ($this->mpdf->col % 2) == 1) { $select = true; } | ||
1295 | else if (preg_match('/(\d+)N\+(\d+)/',$m[1],$a)) { | ||
1296 | if ((($this->mpdf->col+1) % $a[1]) == $a[2]) { $select = true; } | ||
1297 | } | ||
1298 | } | ||
1299 | if ($select) { | ||
1300 | $zp = $this->CSS[$tag.'>>SELECTORNTHCHILD>>'.$m[1]]; | ||
1301 | if ($tag=='TD' || $tag=='TH') { $this->setBorderDominance($zp, 9); } | ||
1302 | if (is_array($zp)) { | ||
1303 | $p = array_merge($p,$zp); | ||
1304 | $this->_mergeBorders($p,$zp); | ||
1305 | } | ||
1306 | } | ||
1307 | } | ||
1308 | } | ||
1309 | } | ||
1310 | /*-- END TABLES --*/ | ||
1311 | //=============================================== | ||
1312 | // STYLESHEET ID e.g. #smallone{} #redletter{} | ||
1313 | if (isset($attr['ID']) && isset($this->CSS['ID>>'.$attr['ID']]) && $this->CSS['ID>>'.$attr['ID']]) { | ||
1314 | $zp = $this->CSS['ID>>'.$attr['ID']]; | ||
1315 | if ($tag=='TD' || $tag=='TH') { $this->setBorderDominance($zp, 9); } // *TABLES* // *TABLES-ADVANCED-BORDERS* | ||
1316 | if (is_array($zp)) { | ||
1317 | $p = array_merge($p,$zp); | ||
1318 | $this->_mergeBorders($p,$zp); | ||
1319 | } | ||
1320 | } | ||
1321 | //=============================================== | ||
1322 | // STYLESHEET CLASS e.g. p.smallone{} div.redletter{} | ||
1323 | foreach($classes AS $class) { | ||
1324 | $zp = array(); | ||
1325 | if (isset($this->CSS[$tag.'>>CLASS>>'.$class]) && $this->CSS[$tag.'>>CLASS>>'.$class]) { $zp = $this->CSS[$tag.'>>CLASS>>'.$class]; } | ||
1326 | if ($tag=='TD' || $tag=='TH') { $this->setBorderDominance($zp, 9); } // *TABLES* // *TABLES-ADVANCED-BORDERS* | ||
1327 | if (is_array($zp)) { | ||
1328 | $p = array_merge($p,$zp); | ||
1329 | $this->_mergeBorders($p,$zp); | ||
1330 | } | ||
1331 | } | ||
1332 | //=============================================== | ||
1333 | // STYLESHEET CLASS e.g. p#smallone{} div#redletter{} | ||
1334 | if (isset($attr['ID']) && isset($this->CSS[$tag.'>>ID>>'.$attr['ID']]) && $this->CSS[$tag.'>>ID>>'.$attr['ID']]) { | ||
1335 | $zp = $this->CSS[$tag.'>>ID>>'.$attr['ID']]; | ||
1336 | if ($tag=='TD' || $tag=='TH') { $this->setBorderDominance($zp, 9); } // *TABLES* // *TABLES-ADVANCED-BORDERS* | ||
1337 | if (is_array($zp)) { | ||
1338 | $p = array_merge($p,$zp); | ||
1339 | $this->_mergeBorders($p,$zp); | ||
1340 | } | ||
1341 | } | ||
1342 | //=============================================== | ||
1343 | // Cascaded e.g. div.class p only works for block level | ||
1344 | if ($inherit == 'BLOCK') { | ||
1345 | $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl-1]['cascadeCSS'][$tag], $p); | ||
1346 | foreach($classes AS $class) { | ||
1347 | $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl-1]['cascadeCSS']['CLASS>>'.$class], $p); | ||
1348 | } | ||
1349 | $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl-1]['cascadeCSS']['ID>>'.$attr['ID']], $p); | ||
1350 | foreach($classes AS $class) { | ||
1351 | $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl-1]['cascadeCSS'][$tag.'>>CLASS>>'.$class], $p); | ||
1352 | } | ||
1353 | $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl-1]['cascadeCSS'][$tag.'>>ID>>'.$attr['ID']], $p); | ||
1354 | } | ||
1355 | else if ($inherit == 'INLINE') { | ||
1356 | $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'][$tag], $p); | ||
1357 | foreach($classes AS $class) { | ||
1358 | $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS']['CLASS>>'.$class], $p); | ||
1359 | } | ||
1360 | $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS']['ID>>'.$attr['ID']], $p); | ||
1361 | foreach($classes AS $class) { | ||
1362 | $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'][$tag.'>>CLASS>>'.$class], $p); | ||
1363 | } | ||
1364 | $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'][$tag.'>>ID>>'.$attr['ID']], $p); | ||
1365 | } | ||
1366 | /*-- TABLES --*/ | ||
1367 | else if ($inherit == 'TOPTABLE' || $inherit == 'TABLE') { // NB looks at $this->tablecascadeCSS-1 for cascading CSS | ||
1368 | // false, 9 = don't check for 'depth' and do set border dominance | ||
1369 | $this->_set_mergedCSS($this->tablecascadeCSS[$this->tbCSSlvl-1][$tag], $p, false, 9); | ||
1370 | foreach($classes AS $class) { | ||
1371 | $this->_set_mergedCSS($this->tablecascadeCSS[$this->tbCSSlvl-1]['CLASS>>'.$class], $p, false, 9); | ||
1372 | } | ||
1373 | // STYLESHEET nth-child SELECTOR e.g. tr:nth-child(odd) td:nth-child(2n+1) | ||
1374 | if ($tag=='TR' || $tag=='TD' || $tag=='TH') { | ||
1375 | foreach($this->tablecascadeCSS[$this->tbCSSlvl-1] AS $k=>$val) { | ||
1376 | if (preg_match('/'.$tag.'>>SELECTORNTHCHILD>>(.*)/',$k, $m)) { | ||
1377 | $select = false; | ||
1378 | if ($tag=='TR') { | ||
1379 | $row = $this->mpdf->row; | ||
1380 | $thnr = (isset($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['is_thead']) ? count($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['is_thead']) : 0); | ||
1381 | $tfnr = (isset($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['is_tfoot']) ? count($this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['is_tfoot']) : 0); | ||
1382 | if ($this->mpdf->tabletfoot) { $row -= $thnr; } | ||
1383 | else if (!$this->mpdf->tablethead) { $row -= ($thnr + $tfnr); } | ||
1384 | if ($m[1]=='ODD' && ($row % 2) == 0) { $select = true; } | ||
1385 | else if ($m[1]=='EVEN' && ($row % 2) == 1) { $select = true; } | ||
1386 | else if (preg_match('/(\d+)N\+(\d+)/',$m[1],$a)) { | ||
1387 | if ((($row + 1) % $a[1]) == $a[2]) { $select = true; } | ||
1388 | } | ||
1389 | } | ||
1390 | else if ($tag=='TD' || $tag=='TH') { | ||
1391 | if ($m[1]=='ODD' && ($this->mpdf->col % 2) == 0) { $select = true; } | ||
1392 | else if ($m[1]=='EVEN' && ($this->mpdf->col % 2) == 1) { $select = true; } | ||
1393 | else if (preg_match('/(\d+)N\+(\d+)/',$m[1],$a)) { | ||
1394 | if ((($this->mpdf->col + 1) % $a[1]) == $a[2]) { $select = true; } | ||
1395 | } | ||
1396 | } | ||
1397 | if ($select) { | ||
1398 | $this->_set_mergedCSS($this->tablecascadeCSS[$this->tbCSSlvl-1][$tag.'>>SELECTORNTHCHILD>>'.$m[1]], $p, false, 9); | ||
1399 | } | ||
1400 | } | ||
1401 | } | ||
1402 | } | ||
1403 | $this->_set_mergedCSS($this->tablecascadeCSS[$this->tbCSSlvl-1]['ID>>'.$attr['ID']], $p, false, 9); | ||
1404 | foreach($classes AS $class) { | ||
1405 | $this->_set_mergedCSS($this->tablecascadeCSS[$this->tbCSSlvl-1][$tag.'>>CLASS>>'.$class], $p, false, 9); | ||
1406 | } | ||
1407 | $this->_set_mergedCSS($this->tablecascadeCSS[$this->tbCSSlvl-1][$tag.'>>ID>>'.$attr['ID']], $p, false, 9); | ||
1408 | } | ||
1409 | /*-- END TABLES --*/ | ||
1410 | //=============================================== | ||
1411 | /*-- LISTS --*/ | ||
1412 | else if ($inherit == 'TOPLIST' || $inherit == 'LIST') { // NB looks at $this->listcascadeCSS-1 for cascading CSS | ||
1413 | // false = don't check for 'depth' | ||
1414 | $this->_set_mergedCSS($this->listcascadeCSS[$this->listCSSlvl-1][$tag], $p, false); | ||
1415 | foreach($classes AS $class) { | ||
1416 | $this->_set_mergedCSS($this->listcascadeCSS[$this->listCSSlvl-1]['CLASS>>'.$class], $p, false); | ||
1417 | } | ||
1418 | $this->_set_mergedCSS($this->listcascadeCSS[$this->listCSSlvl-1]['ID>>'.$attr['ID']], $p, false); | ||
1419 | foreach($classes AS $class) { | ||
1420 | $this->_set_mergedCSS($this->listcascadeCSS[$this->listCSSlvl-1][$tag.'>>CLASS>>'.$class], $p, false); | ||
1421 | } | ||
1422 | $this->_set_mergedCSS($this->listcascadeCSS[$this->listCSSlvl-1][$tag.'>>ID>>'.$attr['ID']], $p, false); | ||
1423 | } | ||
1424 | /*-- END LISTS --*/ | ||
1425 | //=============================================== | ||
1426 | //=============================================== | ||
1427 | // INLINE STYLE e.g. style="CSS:property" | ||
1428 | if (isset($attr['STYLE'])) { | ||
1429 | $zp = $this->readInlineCSS($attr['STYLE']); | ||
1430 | if ($tag=='TD' || $tag=='TH') { $this->setBorderDominance($zp, 9); } // *TABLES* // *TABLES-ADVANCED-BORDERS* | ||
1431 | if (is_array($zp)) { | ||
1432 | $p = array_merge($p,$zp); | ||
1433 | $this->_mergeBorders($p,$zp); | ||
1434 | } | ||
1435 | } | ||
1436 | //=============================================== | ||
1437 | //=============================================== | ||
1438 | // INLINE ATTRIBUTES e.g. .. ALIGN="CENTER"> | ||
1439 | if (isset($attr['LANG']) and $attr['LANG']!='') { | ||
1440 | $p['LANG'] = $attr['LANG']; | ||
1441 | } | ||
1442 | if (isset($attr['COLOR']) and $attr['COLOR']!='') { | ||
1443 | $p['COLOR'] = $attr['COLOR']; | ||
1444 | } | ||
1445 | if ($tag != 'INPUT') { | ||
1446 | if (isset($attr['WIDTH']) and $attr['WIDTH']!='') { | ||
1447 | $p['WIDTH'] = $attr['WIDTH']; | ||
1448 | } | ||
1449 | if (isset($attr['HEIGHT']) and $attr['HEIGHT']!='') { | ||
1450 | $p['HEIGHT'] = $attr['HEIGHT']; | ||
1451 | } | ||
1452 | } | ||
1453 | if ($tag == 'FONT') { | ||
1454 | if (isset($attr['FACE'])) { | ||
1455 | $p['FONT-FAMILY'] = $attr['FACE']; | ||
1456 | } | ||
1457 | if (isset($attr['SIZE']) and $attr['SIZE']!='') { | ||
1458 | $s = ''; | ||
1459 | if ($attr['SIZE'] === '+1') { $s = '120%'; } | ||
1460 | else if ($attr['SIZE'] === '-1') { $s = '86%'; } | ||
1461 | else if ($attr['SIZE'] === '1') { $s = 'XX-SMALL'; } | ||
1462 | else if ($attr['SIZE'] == '2') { $s = 'X-SMALL'; } | ||
1463 | else if ($attr['SIZE'] == '3') { $s = 'SMALL'; } | ||
1464 | else if ($attr['SIZE'] == '4') { $s = 'MEDIUM'; } | ||
1465 | else if ($attr['SIZE'] == '5') { $s = 'LARGE'; } | ||
1466 | else if ($attr['SIZE'] == '6') { $s = 'X-LARGE'; } | ||
1467 | else if ($attr['SIZE'] == '7') { $s = 'XX-LARGE'; } | ||
1468 | if ($s) $p['FONT-SIZE'] = $s; | ||
1469 | } | ||
1470 | } | ||
1471 | if (isset($attr['VALIGN']) and $attr['VALIGN']!='') { | ||
1472 | $p['VERTICAL-ALIGN'] = $attr['VALIGN']; | ||
1473 | } | ||
1474 | if (isset($attr['VSPACE']) and $attr['VSPACE']!='') { | ||
1475 | $p['MARGIN-TOP'] = $attr['VSPACE']; | ||
1476 | $p['MARGIN-BOTTOM'] = $attr['VSPACE']; | ||
1477 | } | ||
1478 | if (isset($attr['HSPACE']) and $attr['HSPACE']!='') { | ||
1479 | $p['MARGIN-LEFT'] = $attr['HSPACE']; | ||
1480 | $p['MARGIN-RIGHT'] = $attr['HSPACE']; | ||
1481 | } | ||
1482 | //=============================================== | ||
1483 | return $p; | ||
1484 | } | ||
1485 | |||
1486 | function PreviewBlockCSS($tag,$attr) { | ||
1487 | // Looks ahead from current block level to a new level | ||
1488 | $p = array(); | ||
1489 | $zp = array(); | ||
1490 | $oldcascadeCSS = $this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS']; | ||
1491 | $classes = array(); | ||
1492 | if (isset($attr['CLASS'])) { $classes = preg_split('/\s+/',$attr['CLASS']); } | ||
1493 | //=============================================== | ||
1494 | // DEFAULT for this TAG set in DefaultCSS | ||
1495 | if (isset($this->mpdf->defaultCSS[$tag])) { | ||
1496 | $zp = $this->fixCSS($this->mpdf->defaultCSS[$tag]); | ||
1497 | if (is_array($zp)) { $p = array_merge($zp,$p); } // Inherited overwrites default | ||
1498 | } | ||
1499 | // STYLESHEET TAG e.g. h1 p div table | ||
1500 | if (isset($this->CSS[$tag])) { | ||
1501 | $zp = $this->CSS[$tag]; | ||
1502 | if (is_array($zp)) { $p = array_merge($p,$zp); } | ||
1503 | } | ||
1504 | // STYLESHEET CLASS e.g. .smallone{} .redletter{} | ||
1505 | foreach($classes AS $class) { | ||
1506 | $zp = array(); | ||
1507 | if (isset($this->CSS['CLASS>>'.$class])) { $zp = $this->CSS['CLASS>>'.$class]; } | ||
1508 | if (is_array($zp)) { $p = array_merge($p,$zp); } | ||
1509 | } | ||
1510 | // STYLESHEET ID e.g. #smallone{} #redletter{} | ||
1511 | if (isset($attr['ID']) && isset($this->CSS['ID>>'.$attr['ID']])) { | ||
1512 | $zp = $this->CSS['ID>>'.$attr['ID']]; | ||
1513 | if (is_array($zp)) { $p = array_merge($p,$zp); } | ||
1514 | } | ||
1515 | // STYLESHEET CLASS e.g. p.smallone{} div.redletter{} | ||
1516 | foreach($classes AS $class) { | ||
1517 | $zp = array(); | ||
1518 | if (isset($this->CSS[$tag.'>>CLASS>>'.$class])) { $zp = $this->CSS[$tag.'>>CLASS>>'.$class]; } | ||
1519 | if (is_array($zp)) { $p = array_merge($p,$zp); } | ||
1520 | } | ||
1521 | // STYLESHEET CLASS e.g. p#smallone{} div#redletter{} | ||
1522 | if (isset($attr['ID']) && isset($this->CSS[$tag.'>>ID>>'.$attr['ID']])) { | ||
1523 | $zp = $this->CSS[$tag.'>>ID>>'.$attr['ID']]; | ||
1524 | if (is_array($zp)) { $p = array_merge($p,$zp); } | ||
1525 | } | ||
1526 | //=============================================== | ||
1527 | // STYLESHEET TAG e.g. div h1 div p | ||
1528 | |||
1529 | $this->_set_mergedCSS($oldcascadeCSS[$tag], $p); | ||
1530 | // STYLESHEET CLASS e.g. .smallone{} .redletter{} | ||
1531 | foreach($classes AS $class) { | ||
1532 | |||
1533 | $this->_set_mergedCSS($oldcascadeCSS['CLASS>>'.$class], $p); | ||
1534 | } | ||
1535 | // STYLESHEET CLASS e.g. #smallone{} #redletter{} | ||
1536 | if (isset($attr['ID'])) { | ||
1537 | |||
1538 | $this->_set_mergedCSS($oldcascadeCSS['ID>>'.$attr['ID']], $p); | ||
1539 | } | ||
1540 | // STYLESHEET CLASS e.g. div.smallone{} p.redletter{} | ||
1541 | foreach($classes AS $class) { | ||
1542 | |||
1543 | $this->_set_mergedCSS($oldcascadeCSS[$tag.'>>CLASS>>'.$class], $p); | ||
1544 | } | ||
1545 | // STYLESHEET CLASS e.g. div#smallone{} p#redletter{} | ||
1546 | if (isset($attr['ID'])) { | ||
1547 | |||
1548 | $this->_set_mergedCSS($oldcascadeCSS[$tag.'>>ID>>'.$attr['ID']], $p); | ||
1549 | } | ||
1550 | //=============================================== | ||
1551 | // INLINE STYLE e.g. style="CSS:property" | ||
1552 | if (isset($attr['STYLE'])) { | ||
1553 | $zp = $this->readInlineCSS($attr['STYLE']); | ||
1554 | if (is_array($zp)) { $p = array_merge($p,$zp); } | ||
1555 | } | ||
1556 | //=============================================== | ||
1557 | return $p; | ||
1558 | } | ||
1559 | |||
1560 | |||
1561 | |||
1562 | |||
1563 | |||
1564 | } // end of class | ||
1565 | |||
1566 | ?> \ No newline at end of file | ||
diff --git a/inc/3rdparty/libraries/mpdf/classes/directw.php b/inc/3rdparty/libraries/mpdf/classes/directw.php new file mode 100644 index 00000000..dc317d26 --- /dev/null +++ b/inc/3rdparty/libraries/mpdf/classes/directw.php | |||
@@ -0,0 +1,408 @@ | |||
1 | <?php | ||
2 | |||
3 | class directw { | ||
4 | |||
5 | var $mpdf = null; | ||
6 | |||
7 | function directw(&$mpdf) { | ||
8 | $this->mpdf = $mpdf; | ||
9 | } | ||
10 | |||
11 | |||
12 | function Write($h,$txt,$currentx=0,$link='',$directionality='ltr',$align='') { | ||
13 | if (!$align) { | ||
14 | if ($directionality=='rtl') { $align = 'R'; } | ||
15 | else { $align = 'L'; } | ||
16 | } | ||
17 | if ($h == 0) { $this->mpdf->SetLineHeight(); $h = $this->mpdf->lineheight; } | ||
18 | //Output text in flowing mode | ||
19 | $w = $this->mpdf->w - $this->mpdf->rMargin - $this->mpdf->x; | ||
20 | |||
21 | $wmax = ($w - ($this->mpdf->cMarginL+$this->mpdf->cMarginR)); | ||
22 | $s=str_replace("\r",'',$txt); | ||
23 | if ($this->mpdf->usingCoreFont) { $nb=strlen($s); } | ||
24 | else { | ||
25 | $nb=mb_strlen($s, $this->mpdf->mb_enc ); | ||
26 | // handle single space character | ||
27 | if(($nb==1) && $s == " ") { | ||
28 | $this->mpdf->x += $this->mpdf->GetStringWidth($s); | ||
29 | return; | ||
30 | } | ||
31 | } | ||
32 | $sep=-1; | ||
33 | $i=0; | ||
34 | $j=0; | ||
35 | $l=0; | ||
36 | $nl=1; | ||
37 | if (!$this->mpdf->usingCoreFont) { | ||
38 | if (preg_match("/([".$this->mpdf->pregRTLchars."])/u", $txt)) { $this->mpdf->biDirectional = true; } // *RTL* | ||
39 | $checkCursive=false; | ||
40 | if ($this->mpdf->biDirectional) { $checkCursive=true; } // *RTL* | ||
41 | else if (isset($this->mpdf->CurrentFont['indic']) && $this->mpdf->CurrentFont['indic']) { $checkCursive=true; } // *INDIC* | ||
42 | while($i<$nb) { | ||
43 | //Get next character | ||
44 | $c = mb_substr($s,$i,1,$this->mpdf->mb_enc ); | ||
45 | if($c == "\n") { | ||
46 | // WORD SPACING | ||
47 | $this->mpdf->ResetSpacing(); | ||
48 | //Explicit line break | ||
49 | $tmp = rtrim(mb_substr($s,$j,$i-$j,$this->mpdf->mb_enc)); | ||
50 | if ($directionality == 'rtl' && $align == 'J') { $align = 'R'; } // *RTL* | ||
51 | $this->mpdf->magic_reverse_dir($tmp, true, $directionality); // *RTL* | ||
52 | $this->mpdf->Cell($w, $h, $tmp, 0, 2, $align, $fill, $link); | ||
53 | $i++; | ||
54 | $sep = -1; | ||
55 | $j = $i; | ||
56 | $l = 0; | ||
57 | if($nl == 1) { | ||
58 | if ($currentx != 0) $this->mpdf->x=$currentx; | ||
59 | else $this->mpdf->x=$this->mpdf->lMargin; | ||
60 | $w = $this->mpdf->w - $this->mpdf->rMargin - $this->mpdf->x; | ||
61 | $wmax = ($w - ($this->mpdf->cMarginL+$this->mpdf->cMarginR)); | ||
62 | } | ||
63 | $nl++; | ||
64 | continue; | ||
65 | } | ||
66 | if($c == " ") { $sep= $i; } | ||
67 | $l += $this->mpdf->GetCharWidthNonCore($c); // mPDF 5.3.04 | ||
68 | if($l > $wmax) { | ||
69 | //Automatic line break (word wrapping) | ||
70 | if($sep == -1) { | ||
71 | // WORD SPACING | ||
72 | $this->mpdf->ResetSpacing(); | ||
73 | if($this->mpdf->x > $this->mpdf->lMargin) { | ||
74 | //Move to next line | ||
75 | if ($currentx != 0) $this->mpdf->x=$currentx; | ||
76 | else $this->mpdf->x=$this->mpdf->lMargin; | ||
77 | $this->mpdf->y+=$h; | ||
78 | $w=$this->mpdf->w-$this->mpdf->rMargin-$this->mpdf->x; | ||
79 | $wmax = ($w - ($this->mpdf->cMarginL+$this->mpdf->cMarginR)); | ||
80 | $i++; | ||
81 | $nl++; | ||
82 | continue; | ||
83 | } | ||
84 | if($i==$j) { $i++; } | ||
85 | $tmp = rtrim(mb_substr($s,$j,$i-$j,$this->mpdf->mb_enc)); | ||
86 | if ($directionality == 'rtl' && $align == 'J') { $align = 'R'; } // *RTL* | ||
87 | $this->mpdf->magic_reverse_dir($tmp, true, $directionality); // *RTL* | ||
88 | $this->mpdf->Cell($w, $h, $tmp, 0, 2, $align, $fill, $link); | ||
89 | } | ||
90 | else { | ||
91 | $tmp = rtrim(mb_substr($s,$j,$sep-$j,$this->mpdf->mb_enc)); | ||
92 | if ($directionality == 'rtl' && $align == 'J') { $align = 'R'; } // *RTL* | ||
93 | $this->mpdf->magic_reverse_dir($tmp, true, $directionality); // *RTL* | ||
94 | |||
95 | if($align=='J') { | ||
96 | ////////////////////////////////////////// | ||
97 | // JUSTIFY J using Unicode fonts (Word spacing doesn't work) | ||
98 | // WORD SPACING | ||
99 | // Change NON_BREAKING SPACE to spaces so they are 'spaced' properly | ||
100 | $tmp = str_replace(chr(194).chr(160),chr(32),$tmp ); | ||
101 | $len_ligne = $this->mpdf->GetStringWidth($tmp ); | ||
102 | $nb_carac = mb_strlen( $tmp , $this->mpdf->mb_enc ) ; | ||
103 | $nb_spaces = mb_substr_count( $tmp ,' ', $this->mpdf->mb_enc ) ; | ||
104 | $inclCursive=false; | ||
105 | if ($checkCursive) { | ||
106 | if (preg_match("/([".$this->mpdf->pregRTLchars."])/u", $tmp)) { $inclCursive = true; } // *RTL* | ||
107 | if (preg_match("/([".$this->mpdf->pregHIchars.$this->mpdf->pregBNchars.$this->mpdf->pregPAchars."])/u", $tmp)) { $inclCursive = true; } // *INDIC* | ||
108 | } | ||
109 | list($charspacing,$ws) = $this->mpdf->GetJspacing($nb_carac,$nb_spaces,((($w-2) - $len_ligne) * _MPDFK),$inclCursive); | ||
110 | $this->mpdf->SetSpacing($charspacing,$ws); | ||
111 | ////////////////////////////////////////// | ||
112 | } | ||
113 | $this->mpdf->Cell($w, $h, $tmp, 0, 2, $align, $fill, $link); | ||
114 | $i=$sep+1; | ||
115 | } | ||
116 | $sep = -1; | ||
117 | $j = $i; | ||
118 | $l = 0; | ||
119 | if($nl==1) { | ||
120 | if ($currentx != 0) $this->mpdf->x=$currentx; | ||
121 | else $this->mpdf->x=$this->mpdf->lMargin; | ||
122 | $w=$this->mpdf->w-$this->mpdf->rMargin-$this->mpdf->x; | ||
123 | $wmax = ($w - ($this->mpdf->cMarginL+$this->mpdf->cMarginR)); | ||
124 | } | ||
125 | $nl++; | ||
126 | } | ||
127 | else { $i++; } | ||
128 | } | ||
129 | //Last chunk | ||
130 | // WORD SPACING | ||
131 | $this->mpdf->ResetSpacing(); | ||
132 | } | ||
133 | else { | ||
134 | while($i<$nb) { | ||
135 | //Get next character | ||
136 | $c=$s[$i]; | ||
137 | if($c == "\n") { | ||
138 | //Explicit line break | ||
139 | // WORD SPACING | ||
140 | $this->mpdf->ResetSpacing(); | ||
141 | $this->mpdf->Cell($w, $h, substr($s, $j, $i-$j), 0, 2, $align, $fill, $link); | ||
142 | $i++; | ||
143 | $sep = -1; | ||
144 | $j = $i; | ||
145 | $l = 0; | ||
146 | if($nl == 1) { | ||
147 | if ($currentx != 0) $this->mpdf->x=$currentx; | ||
148 | else $this->mpdf->x=$this->mpdf->lMargin; | ||
149 | $w = $this->mpdf->w - $this->mpdf->rMargin - $this->mpdf->x; | ||
150 | $wmax=$w-($this->mpdf->cMarginL+$this->mpdf->cMarginR); | ||
151 | } | ||
152 | $nl++; | ||
153 | continue; | ||
154 | } | ||
155 | if($c == " ") { $sep= $i; } | ||
156 | $l += $this->mpdf->GetCharWidthCore($c); // mPDF 5.3.04 | ||
157 | if($l > $wmax) { | ||
158 | //Automatic line break (word wrapping) | ||
159 | if($sep == -1) { | ||
160 | // WORD SPACING | ||
161 | $this->mpdf->ResetSpacing(); | ||
162 | if($this->mpdf->x > $this->mpdf->lMargin) { | ||
163 | //Move to next line | ||
164 | if ($currentx != 0) $this->mpdf->x=$currentx; | ||
165 | else $this->mpdf->x=$this->mpdf->lMargin; | ||
166 | $this->mpdf->y+=$h; | ||
167 | $w=$this->mpdf->w-$this->mpdf->rMargin-$this->mpdf->x; | ||
168 | $wmax=$w-($this->mpdf->cMarginL+$this->mpdf->cMarginR); | ||
169 | $i++; | ||
170 | $nl++; | ||
171 | continue; | ||
172 | } | ||
173 | if($i==$j) { $i++; } | ||
174 | $this->mpdf->Cell($w, $h, substr($s, $j, $i-$j), 0, 2, $align, $fill, $link); | ||
175 | } | ||
176 | else { | ||
177 | $tmp = substr($s, $j, $sep-$j); | ||
178 | if($align=='J') { | ||
179 | ////////////////////////////////////////// | ||
180 | // JUSTIFY J using Unicode fonts (Word spacing doesn't work) | ||
181 | // WORD SPACING | ||
182 | // Change NON_BREAKING SPACE to spaces so they are 'spaced' properly | ||
183 | $tmp = str_replace(chr(160),chr(32),$tmp ); | ||
184 | $len_ligne = $this->mpdf->GetStringWidth($tmp ); | ||
185 | $nb_carac = strlen( $tmp ) ; | ||
186 | $nb_spaces = substr_count( $tmp ,' ' ) ; | ||
187 | list($charspacing,$ws) = $this->mpdf->GetJspacing($nb_carac,$nb_spaces,((($w-2) - $len_ligne) * _MPDFK),$false); | ||
188 | $this->mpdf->SetSpacing($charspacing,$ws); | ||
189 | ////////////////////////////////////////// | ||
190 | } | ||
191 | $this->mpdf->Cell($w, $h, $tmp, 0, 2, $align, $fill, $link); | ||
192 | $i=$sep+1; | ||
193 | } | ||
194 | $sep = -1; | ||
195 | $j = $i; | ||
196 | $l = 0; | ||
197 | if($nl==1) { | ||
198 | if ($currentx != 0) $this->mpdf->x=$currentx; | ||
199 | else $this->mpdf->x=$this->mpdf->lMargin; | ||
200 | $w=$this->mpdf->w-$this->mpdf->rMargin-$this->mpdf->x; | ||
201 | $wmax=$w-($this->mpdf->cMarginL+$this->mpdf->cMarginR); | ||
202 | } | ||
203 | $nl++; | ||
204 | } | ||
205 | else { | ||
206 | $i++; | ||
207 | } | ||
208 | } | ||
209 | // WORD SPACING | ||
210 | $this->mpdf->ResetSpacing(); | ||
211 | } | ||
212 | //Last chunk | ||
213 | if($i!=$j) { | ||
214 | if ($currentx != 0) $this->mpdf->x=$currentx; | ||
215 | else $this->mpdf->x=$this->mpdf->lMargin; | ||
216 | if ($this->mpdf->usingCoreFont) { $tmp = substr($s,$j,$i-$j); } | ||
217 | else { | ||
218 | $tmp = mb_substr($s,$j,$i-$j,$this->mpdf->mb_enc); | ||
219 | if ($directionality == 'rtl' && $align == 'J') { $align = 'R'; } // *RTL* | ||
220 | $this->mpdf->magic_reverse_dir($tmp, true, $directionality); // *RTL* | ||
221 | } | ||
222 | $this->mpdf->Cell($w,$h,$tmp,0,0,$align,$fill,$link); | ||
223 | } | ||
224 | } | ||
225 | |||
226 | |||
227 | function CircularText($x, $y, $r, $text, $align='top', $fontfamily='', $fontsizePt=0, $fontstyle='', $kerning=120, $fontwidth=100, $divider='') { // mPDF 5.5.23 | ||
228 | if ($font || $fontstyle || $fontsizePt) $this->mpdf->SetFont($fontfamily,$fontstyle,$fontsizePt); | ||
229 | $kerning/=100; | ||
230 | $fontwidth/=100; | ||
231 | if($kerning==0) $this->mpdf->Error('Please use values unequal to zero for kerning (CircularText)'); | ||
232 | if($fontwidth==0) $this->mpdf->Error('Please use values unequal to zero for font width (CircularText)'); | ||
233 | $text=str_replace("\r",'',$text); | ||
234 | //circumference | ||
235 | $u=($r*2)*M_PI; | ||
236 | // mPDF 5.5.23 | ||
237 | $checking = true; | ||
238 | $autoset = false; | ||
239 | while($checking) { | ||
240 | $t=0; | ||
241 | $w = array(); | ||
242 | if ($this->mpdf->usingCoreFont) { | ||
243 | $nb=strlen($text); | ||
244 | for($i=0; $i<$nb; $i++){ | ||
245 | $w[$i]=$this->mpdf->GetStringWidth($text[$i]); | ||
246 | $w[$i]*=$kerning*$fontwidth; | ||
247 | $t+=$w[$i]; | ||
248 | } | ||
249 | } | ||
250 | else { | ||
251 | $nb=mb_strlen($text, $this->mpdf->mb_enc ); | ||
252 | $lastchar = ''; | ||
253 | $unicode = $this->mpdf->UTF8StringToArray($text); | ||
254 | for($i=0; $i<$nb; $i++){ | ||
255 | $c = mb_substr($text,$i,1,$this->mpdf->mb_enc ); | ||
256 | $w[$i]=$this->mpdf->GetStringWidth($c); | ||
257 | $w[$i]*=$kerning*$fontwidth; | ||
258 | $char = $unicode[$i]; | ||
259 | if ($this->mpdf->useKerning && $lastchar) { | ||
260 | if (isset($this->mpdf->CurrentFont['kerninfo'][$lastchar][$char])) { | ||
261 | $tk = $this->mpdf->CurrentFont['kerninfo'][$lastchar][$char] * ($this->mpdf->FontSize/ 1000) * $kerning * $fontwidth; | ||
262 | $w[$i] += $tk/2; | ||
263 | $w[$i-1] += $tk/2; | ||
264 | $t+=$tk; | ||
265 | } | ||
266 | } | ||
267 | $lastchar = $char; | ||
268 | $t+=$w[$i]; | ||
269 | } | ||
270 | } | ||
271 | if ($fontsizePt>=0 || $autoset) { $checking = false; } | ||
272 | else { | ||
273 | $t+=$this->mpdf->GetStringWidth(' '); | ||
274 | if ($divider) | ||
275 | $t+=$this->mpdf->GetStringWidth(' '); | ||
276 | if ($fontsizePt==-2) | ||
277 | $fontsizePt = $this->mpdf->FontSizePt * 0.5 * $u/$t; | ||
278 | else | ||
279 | $fontsizePt = $this->mpdf->FontSizePt * $u/$t; | ||
280 | $this->mpdf->SetFontSize($fontsizePt); | ||
281 | $autoset = true; | ||
282 | } | ||
283 | } | ||
284 | |||
285 | //total width of string in degrees | ||
286 | $d=($t/$u)*360; | ||
287 | |||
288 | $this->mpdf->StartTransform(); | ||
289 | // rotate matrix for the first letter to center the text | ||
290 | // (half of total degrees) | ||
291 | if($align=='top'){ | ||
292 | $this->mpdf->transformRotate(-$d/2, $x, $y); | ||
293 | } | ||
294 | else{ | ||
295 | $this->mpdf->transformRotate($d/2, $x, $y); | ||
296 | } | ||
297 | //run through the string | ||
298 | for($i=0; $i<$nb; $i++){ | ||
299 | if($align=='top'){ | ||
300 | //rotate matrix half of the width of current letter + half of the width of preceding letter | ||
301 | if($i==0){ | ||
302 | $this->mpdf->transformRotate((($w[$i]/2)/$u)*360, $x, $y); | ||
303 | } | ||
304 | else{ | ||
305 | $this->mpdf->transformRotate((($w[$i]/2+$w[$i-1]/2)/$u)*360, $x, $y); | ||
306 | } | ||
307 | if($fontwidth!=1){ | ||
308 | $this->mpdf->StartTransform(); | ||
309 | $this->mpdf->transformScale($fontwidth*100, 100, $x, $y); | ||
310 | } | ||
311 | $this->mpdf->SetXY($x-$w[$i]/2, $y-$r); | ||
312 | } | ||
313 | else{ | ||
314 | //rotate matrix half of the width of current letter + half of the width of preceding letter | ||
315 | if($i==0){ | ||
316 | $this->mpdf->transformRotate(-(($w[$i]/2)/$u)*360, $x, $y); | ||
317 | } | ||
318 | else{ | ||
319 | $this->mpdf->transformRotate(-(($w[$i]/2+$w[$i-1]/2)/$u)*360, $x, $y); | ||
320 | } | ||
321 | if($fontwidth!=1){ | ||
322 | $this->mpdf->StartTransform(); | ||
323 | $this->mpdf->transformScale($fontwidth*100, 100, $x, $y); | ||
324 | } | ||
325 | $this->mpdf->SetXY($x-$w[$i]/2, $y+$r-($this->mpdf->FontSize)); | ||
326 | } | ||
327 | if ($this->mpdf->usingCoreFont) { $c=$text[$i]; } | ||
328 | else { $c = mb_substr($text,$i,1,$this->mpdf->mb_enc ); } | ||
329 | $this->mpdf->Cell(($w[$i]),$this->mpdf->FontSize,$c,0,0,'C'); // mPDF 5.3.53 | ||
330 | if($fontwidth!=1){ | ||
331 | $this->mpdf->StopTransform(); | ||
332 | } | ||
333 | } | ||
334 | $this->mpdf->StopTransform(); | ||
335 | |||
336 | // mPDF 5.5.23 | ||
337 | if($align=='top' && $divider!=''){ | ||
338 | $wc=$this->mpdf->GetStringWidth($divider); | ||
339 | $wc*=$kerning*$fontwidth; | ||
340 | |||
341 | $this->mpdf->StartTransform(); | ||
342 | $this->mpdf->transformRotate(90, $x, $y); | ||
343 | $this->mpdf->SetXY($x-$wc/2, $y-$r); | ||
344 | $this->mpdf->Cell(($wc),$this->mpdf->FontSize,$divider,0,0,'C'); | ||
345 | $this->mpdf->StopTransform(); | ||
346 | |||
347 | $this->mpdf->StartTransform(); | ||
348 | $this->mpdf->transformRotate(-90, $x, $y); | ||
349 | $this->mpdf->SetXY($x-$wc/2, $y-$r); | ||
350 | $this->mpdf->Cell(($wc),$this->mpdf->FontSize,$divider,0,0,'C'); | ||
351 | $this->mpdf->StopTransform(); | ||
352 | } | ||
353 | } | ||
354 | |||
355 | function Shaded_box( $text,$font='',$fontstyle='B',$szfont='',$width='70%',$style='DF',$radius=2.5,$fill='#FFFFFF',$color='#000000',$pad=2 ) | ||
356 | { | ||
357 | // F (shading - no line),S (line, no shading),DF (both) | ||
358 | if (!$font) { $font= $this->mpdf->default_font; } | ||
359 | if (!$szfont) { $szfont = ($this->mpdf->default_font_size * 1.8); } | ||
360 | |||
361 | $text = $this->mpdf->purify_utf8_text($text); | ||
362 | if ($this->mpdf->text_input_as_HTML) { | ||
363 | $text = $this->mpdf->all_entities_to_utf8($text); | ||
364 | } | ||
365 | if ($this->mpdf->usingCoreFont) { $text = mb_convert_encoding($text,$this->mpdf->mb_enc,'UTF-8'); } | ||
366 | // DIRECTIONALITY | ||
367 | $this->mpdf->magic_reverse_dir($text, true, $this->mpdf->directionality); // *RTL* | ||
368 | // Font-specific ligature substitution for Indic fonts | ||
369 | if (isset($this->mpdf->CurrentFont['indic']) && $this->mpdf->CurrentFont['indic']) $this->mpdf->ConvertIndic($text); // *INDIC* | ||
370 | $text = ' '.$text.' '; | ||
371 | if (!$width) { $width = $this->mpdf->pgwidth; } else { $width=$this->mpdf->ConvertSize($width,$this->mpdf->pgwidth); } | ||
372 | $midpt = $this->mpdf->lMargin+($this->mpdf->pgwidth/2); | ||
373 | $r1 = $midpt-($width/2); //($this->mpdf->w / 2) - 40; | ||
374 | $r2 = $r1 + $width; //$r1 + 80; | ||
375 | $y1 = $this->mpdf->y; | ||
376 | |||
377 | |||
378 | $mid = ($r1 + $r2 ) / 2; | ||
379 | $loop = 0; | ||
380 | |||
381 | while ( $loop == 0 ) | ||
382 | { | ||
383 | $this->mpdf->SetFont( $font, $fontstyle, $szfont ); | ||
384 | $sz = $this->mpdf->GetStringWidth( $text ); | ||
385 | if ( ($r1+$sz) > $r2 ) | ||
386 | $szfont --; | ||
387 | else | ||
388 | $loop ++; | ||
389 | } | ||
390 | |||
391 | $y2 = $this->mpdf->FontSize+($pad*2); | ||
392 | |||
393 | $this->mpdf->SetLineWidth(0.1); | ||
394 | $fc = $this->mpdf->ConvertColor($fill); | ||
395 | $tc = $this->mpdf->ConvertColor($color); | ||
396 | $this->mpdf->SetFColor($fc); | ||
397 | $this->mpdf->SetTColor($tc); | ||
398 | $this->mpdf->RoundedRect($r1, $y1, ($r2 - $r1), $y2, $radius, $style); | ||
399 | $this->mpdf->SetX( $r1); | ||
400 | $this->mpdf->Cell($r2-$r1, $y2, $text, 0, 1, "C" ); | ||
401 | $this->mpdf->SetY($y1+$y2+2); // +2 = mm margin below shaded box | ||
402 | $this->mpdf->Reset(); | ||
403 | } | ||
404 | |||
405 | |||
406 | } | ||
407 | |||
408 | ?> \ No newline at end of file | ||
diff --git a/inc/3rdparty/libraries/mpdf/classes/form.php b/inc/3rdparty/libraries/mpdf/classes/form.php new file mode 100644 index 00000000..9367e717 --- /dev/null +++ b/inc/3rdparty/libraries/mpdf/classes/form.php | |||
@@ -0,0 +1,1498 @@ | |||
1 | <?php | ||
2 | |||
3 | class form { | ||
4 | |||
5 | var $mpdf = null; | ||
6 | |||
7 | var $forms; | ||
8 | var $formn; | ||
9 | |||
10 | //Active Forms | ||
11 | var $formSubmitNoValueFields; | ||
12 | var $formExportType; | ||
13 | var $formSelectDefaultOption; | ||
14 | var $formUseZapD; | ||
15 | /* Form Styles */ | ||
16 | var $form_border_color; | ||
17 | var $form_background_color; | ||
18 | var $form_border_width; | ||
19 | var $form_border_style; | ||
20 | var $form_button_border_color; | ||
21 | var $form_button_background_color; | ||
22 | var $form_button_border_width; | ||
23 | var $form_button_border_style; | ||
24 | var $form_radio_color; | ||
25 | var $form_radio_background_color; | ||
26 | |||
27 | var $form_element_spacing; | ||
28 | |||
29 | // Active forms | ||
30 | var $formMethod; | ||
31 | var $formAction; | ||
32 | var $form_fonts; | ||
33 | var $form_radio_groups; | ||
34 | var $form_checkboxes; | ||
35 | var $pdf_acro_array; | ||
36 | |||
37 | var $pdf_array_co; | ||
38 | var $array_form_button_js; | ||
39 | var $array_form_choice_js; | ||
40 | var $array_form_text_js; | ||
41 | |||
42 | /* Button Text */ | ||
43 | var $form_button_text; | ||
44 | var $form_button_text_over; | ||
45 | var $form_button_text_click; | ||
46 | var $form_button_icon; | ||
47 | |||
48 | |||
49 | // FORMS | ||
50 | var $textarea_lineheight; | ||
51 | |||
52 | function form(&$mpdf) { | ||
53 | $this->mpdf = $mpdf; | ||
54 | |||
55 | // ACTIVE FORMS | ||
56 | $this->formExportType = 'xfdf'; // 'xfdf' or 'html' | ||
57 | $this->formSubmitNoValueFields = true; // Whether to include blank fields when submitting data | ||
58 | $this->formSelectDefaultOption = true; // for Select drop down box; if no option is explicitly maked as selected, | ||
59 | // this determines whether to select 1st option (as per browser) | ||
60 | // - affects whether "required" attribute is relevant | ||
61 | $this->formUseZapD = true; // Determine whether to use ZapfDingbat icons for radio/checkboxes | ||
62 | |||
63 | // FORM STYLES | ||
64 | // These can alternatively use a 4 number string to represent CMYK colours | ||
65 | $this->form_border_color = '0.6 0.6 0.72'; // RGB | ||
66 | $this->form_background_color = '0.975 0.975 0.975'; // RGB | ||
67 | $this->form_border_width = '1'; // 0 doesn't seem to work as it should | ||
68 | $this->form_border_style = 'S'; // B - Bevelled; D - Double | ||
69 | $this->form_button_border_color = '0.2 0.2 0.55'; | ||
70 | $this->form_button_background_color = '0.941 0.941 0.941'; | ||
71 | $this->form_button_border_width = '1'; | ||
72 | $this->form_button_border_style = 'S'; | ||
73 | $this->form_radio_color = '0.0 0.0 0.4'; // radio and checkbox | ||
74 | $this->form_radio_background_color = '0.9 0.9 0.9'; | ||
75 | |||
76 | // FORMS | ||
77 | $this->textarea_lineheight = 1.25; | ||
78 | |||
79 | // FORM ELEMENT SPACING | ||
80 | $this->form_element_spacing['select']['outer']['h'] = 0.5; // Horizontal spacing around SELECT | ||
81 | $this->form_element_spacing['select']['outer']['v'] = 0.5; // Vertical spacing around SELECT | ||
82 | $this->form_element_spacing['select']['inner']['h'] = 0.7; // Horizontal padding around SELECT | ||
83 | $this->form_element_spacing['select']['inner']['v'] = 0.7; // Vertical padding around SELECT | ||
84 | $this->form_element_spacing['input']['outer']['h'] = 0.5; | ||
85 | $this->form_element_spacing['input']['outer']['v'] = 0.5; | ||
86 | $this->form_element_spacing['input']['inner']['h'] = 0.7; | ||
87 | $this->form_element_spacing['input']['inner']['v'] = 0.7; | ||
88 | $this->form_element_spacing['textarea']['outer']['h'] = 0.5; | ||
89 | $this->form_element_spacing['textarea']['outer']['v'] = 0.5; | ||
90 | $this->form_element_spacing['textarea']['inner']['h'] = 1; | ||
91 | $this->form_element_spacing['textarea']['inner']['v'] = 0.5; | ||
92 | $this->form_element_spacing['button']['outer']['h'] = 0.5; | ||
93 | $this->form_element_spacing['button']['outer']['v'] = 0.5; | ||
94 | $this->form_element_spacing['button']['inner']['h'] = 2; | ||
95 | $this->form_element_spacing['button']['inner']['v'] = 1; | ||
96 | |||
97 | // INITIALISE non-configurable | ||
98 | $this->formMethod = 'POST'; | ||
99 | $this->formAction = ''; | ||
100 | $this->form_fonts = array(); | ||
101 | $this->form_radio_groups = array(); | ||
102 | $this->form_checkboxes = false; | ||
103 | $this->forms = array(); | ||
104 | $this->pdf_array_co = ''; | ||
105 | |||
106 | |||
107 | } | ||
108 | |||
109 | |||
110 | function print_ob_text($objattr,$w,$h,$texto,$rtlalign,$k,$blockdir) { | ||
111 | // TEXT/PASSWORD INPUT | ||
112 | if ($this->mpdf->useActiveForms) { | ||
113 | // Flags: 1 - Readonly; 2 - Required; 3 - No export; 13 - textarea; 14 - Password | ||
114 | $flags = array(); | ||
115 | if ($objattr['disabled'] || $objattr['readonly']) { $flags[] = 1; } // readonly | ||
116 | if ($objattr['disabled']) { $flags[] = 3; } // no export | ||
117 | if ($objattr['disabled']) { $objattr['color'] = array(3,128,128,128); } // gray out disabled | ||
118 | if ($objattr['required']) { $flags[] = 2; } // required | ||
119 | if (!$objattr['spellcheck']) { $flags[] = 23; } // DoNotSpellCheck | ||
120 | if ($objattr['subtype']=='PASSWORD') { $flags[] = 14; } | ||
121 | $this->mpdf->SetTColor($objattr['color']); | ||
122 | $fieldalign = $rtlalign; | ||
123 | if ($objattr['text_align']) { $fieldalign = $objattr['text_align']; } | ||
124 | if ($objattr['subtype']=='PASSWORD') { $val = $objattr['value']; } | ||
125 | else { $val = $objattr['text']; } | ||
126 | // mPDF 5.3.25 | ||
127 | $js = array(); | ||
128 | if ($objattr['onCalculate']) { $js[] = array('C', $objattr['onCalculate']); } | ||
129 | if ($objattr['onValidate']) { $js[] = array('V', $objattr['onValidate']); } | ||
130 | if ($objattr['onFormat']) { $js[] = array('F', $objattr['onFormat']); } | ||
131 | if ($objattr['onKeystroke']) { $js[] = array('K', $objattr['onKeystroke']); } | ||
132 | $this->SetFormText( $w, $h, $objattr['fieldname'], $val, $val, $objattr['title'], $flags, $fieldalign, false, $objattr['maxlength'], $js, $objattr['background-col'], $objattr['border-col'] ); | ||
133 | $this->mpdf->SetTColor($this->mpdf->ConvertColor(0)); | ||
134 | } | ||
135 | else { | ||
136 | $w -= $this->form_element_spacing['input']['outer']['h']*2 /$k; | ||
137 | $h -= $this->form_element_spacing['input']['outer']['v']*2 /$k; | ||
138 | $this->mpdf->x += $this->form_element_spacing['input']['outer']['h'] /$k; | ||
139 | $this->mpdf->y += $this->form_element_spacing['input']['outer']['v'] /$k; | ||
140 | // Chop texto to max length $w-inner-padding | ||
141 | while ($this->mpdf->GetStringWidth($texto) > $w-($this->form_element_spacing['input']['inner']['h']*2)) { | ||
142 | $texto = mb_substr($texto,0,mb_strlen($texto,$this->mpdf->mb_enc)-1,$this->mpdf->mb_enc); | ||
143 | } | ||
144 | $save_linemaxfontsize = $this->mpdf->linemaxfontsize; | ||
145 | $this->mpdf->linemaxfontsize = $this->mpdf->FontSize; | ||
146 | $this->mpdf->SetLineWidth(0.2 /$k ); | ||
147 | $this->mpdf->magic_reverse_dir($texto, false, $blockdir); // *RTL* | ||
148 | if (isset($objattr['disabled']) && $objattr['disabled']) { | ||
149 | $this->mpdf->SetFColor($this->mpdf->ConvertColor(225)); | ||
150 | $this->mpdf->SetTColor($this->mpdf->ConvertColor(127)); | ||
151 | } | ||
152 | else if (isset($objattr['readonly']) && $objattr['readonly']) { | ||
153 | $this->mpdf->SetFColor($this->mpdf->ConvertColor(225)); | ||
154 | $this->mpdf->SetTColor($this->mpdf->ConvertColor(0)); | ||
155 | } | ||
156 | else { | ||
157 | $this->mpdf->SetFColor($this->mpdf->ConvertColor(250)); | ||
158 | $this->mpdf->SetTColor($this->mpdf->ConvertColor(0)); | ||
159 | } | ||
160 | $this->mpdf->Cell($w,$h,$texto,1,0,$rtlalign,1,'',0,$this->form_element_spacing['input']['inner']['h'] /$k ,$this->form_element_spacing['input']['inner']['h'] /$k , 'M'); | ||
161 | $this->mpdf->SetFColor($this->mpdf->ConvertColor(255)); | ||
162 | $this->mpdf->SetTColor($this->mpdf->ConvertColor(0)); | ||
163 | $this->mpdf->linemaxfontsize = $save_linemaxfontsize; | ||
164 | } | ||
165 | } | ||
166 | |||
167 | function print_ob_textarea($objattr,$w,$h,$texto,$rtlalign,$k,$blockdir) { | ||
168 | // TEXTAREA | ||
169 | if ($this->mpdf->useActiveForms) { | ||
170 | // Flags: 1 - Readonly; 2 - Required; 3 - No export; 13 - textarea; 14 - Password | ||
171 | $flags = array(); | ||
172 | $flags = array(13); // textarea | ||
173 | if ($objattr['disabled'] || $objattr['readonly']) { $flags[] = 1; } // readonly | ||
174 | if ($objattr['disabled']) { $flags[] = 3; } // no export | ||
175 | if ($objattr['disabled']) { $objattr['color'] = array(3,128,128,128); } // gray out disabled | ||
176 | if ($objattr['required']) { $flags[] = 2; } // required | ||
177 | if (!$objattr['spellcheck']) { $flags[] = 23; } // DoNotSpellCheck | ||
178 | if ($objattr['donotscroll']) { $flags[] = 24; } // DoNotScroll | ||
179 | $this->mpdf->SetTColor($objattr['color']); | ||
180 | $fieldalign = $rtlalign; | ||
181 | if ($texto == ' ') { $texto = ''; } // mPDF 5.3.24 | ||
182 | if ($objattr['text_align']) { $fieldalign = $objattr['text_align']; } | ||
183 | // mPDF 5.3.25 | ||
184 | $js = array(); | ||
185 | if ($objattr['onCalculate']) { $js[] = array('C', $objattr['onCalculate']); } | ||
186 | if ($objattr['onValidate']) { $js[] = array('V', $objattr['onValidate']); } | ||
187 | if ($objattr['onFormat']) { $js[] = array('F', $objattr['onFormat']); } | ||
188 | if ($objattr['onKeystroke']) { $js[] = array('K', $objattr['onKeystroke']); } | ||
189 | $this->SetFormText( $w, $h, $objattr['fieldname'], $texto, $texto, $objattr['title'], $flags, $fieldalign , false, -1, $js, $objattr['background-col'], $objattr['border-col'] ); | ||
190 | $this->mpdf->SetTColor($this->mpdf->ConvertColor(0)); | ||
191 | } | ||
192 | else { | ||
193 | $w -= $this->form_element_spacing['textarea']['outer']['h']*2 /$k ; | ||
194 | $h -= $this->form_element_spacing['textarea']['outer']['v']*2 /$k ; | ||
195 | $this->mpdf->x += $this->form_element_spacing['textarea']['outer']['h'] /$k ; | ||
196 | $this->mpdf->y += $this->form_element_spacing['textarea']['outer']['v'] /$k ; | ||
197 | $this->mpdf->SetLineWidth(0.2 /$k ); | ||
198 | if (isset($objattr['disabled']) && $objattr['disabled']) { | ||
199 | $this->mpdf->SetFColor($this->mpdf->ConvertColor(225)); | ||
200 | $this->mpdf->SetTColor($this->mpdf->ConvertColor(127)); | ||
201 | } | ||
202 | else if (isset($objattr['readonly']) && $objattr['readonly']) { | ||
203 | $this->mpdf->SetFColor($this->mpdf->ConvertColor(225)); | ||
204 | $this->mpdf->SetTColor($this->mpdf->ConvertColor(0)); | ||
205 | } | ||
206 | else { | ||
207 | $this->mpdf->SetFColor($this->mpdf->ConvertColor(250)); | ||
208 | $this->mpdf->SetTColor($this->mpdf->ConvertColor(0)); | ||
209 | } | ||
210 | $this->mpdf->Rect($this->mpdf->x,$this->mpdf->y,$w,$h,'DF'); | ||
211 | $w -= $this->form_element_spacing['textarea']['inner']['h']*2 /$k ; | ||
212 | $this->mpdf->x += $this->form_element_spacing['textarea']['inner']['h'] /$k ; | ||
213 | $this->mpdf->y += $this->form_element_spacing['textarea']['inner']['v'] /$k ; | ||
214 | $linesneeded = $this->mpdf->WordWrap($texto,$w); | ||
215 | if ($linesneeded > $objattr['rows']) { //Too many words inside textarea | ||
216 | $textoaux = explode("\n",$texto); | ||
217 | $texto = ''; | ||
218 | for($i=0;$i<$objattr['rows'];$i++) { | ||
219 | if ($i == ($objattr['rows']-1)) $texto .= $textoaux[$i]; | ||
220 | else $texto .= $textoaux[$i] . "\n"; | ||
221 | } | ||
222 | $texto = mb_substr($texto,0,mb_strlen($texto,$this->mpdf->mb_enc)-4,$this->mpdf->mb_enc) . "..."; | ||
223 | } | ||
224 | if ($texto != '') $this->mpdf->MultiCell($w,$this->mpdf->FontSize*$this->textarea_lineheight,$texto,0,'',0,'',$blockdir,true); | ||
225 | $this->mpdf->SetFColor($this->mpdf->ConvertColor(255)); | ||
226 | $this->mpdf->SetTColor($this->mpdf->ConvertColor(0)); | ||
227 | } | ||
228 | } | ||
229 | |||
230 | function print_ob_select($objattr,$w,$h,$texto,$rtlalign,$k,$blockdir) { | ||
231 | // SELECT | ||
232 | if ($this->mpdf->useActiveForms) { | ||
233 | // Flags: 1 - Readonly; 2 - Required; 3 - No export; 19 - edit (only if combo) | ||
234 | $flags = array(); | ||
235 | if ($objattr['disabled']) { $flags[] = 1; } // readonly | ||
236 | if ($objattr['disabled']) { $flags[] = 3; } // no export | ||
237 | if ($objattr['disabled']) { $objattr['color'] = array(3,128,128,128); } // gray out disabled | ||
238 | if ($objattr['required']) { $flags[] = 2; } // required | ||
239 | if ($objattr['multiple'] && $objattr['size']>1) { $flags[] = 22; } //flag 22 = multiselect (listbox) | ||
240 | if ($objattr['size']<2) { | ||
241 | $flags[] = 18; //flag 18 = combobox (else a listbox) | ||
242 | if ($objattr['editable']) { $flags[] = 19; } // editable | ||
243 | } | ||
244 | // only spellcheck if combo and editable | ||
245 | if (!$objattr['spellcheck'] || $objattr['size']>1 || !$objattr['editable']) { $flags[] = 23; } // DoNotSpellCheck | ||
246 | if ($objattr['subtype']=='PASSWORD') { $flags[] = 14; } | ||
247 | if ($objattr['onChange']) { $js = $objattr['onChange']; } | ||
248 | else { $js = ''; } // mPDF 5.3.37 | ||
249 | $data = array('VAL' => array(), 'OPT' => array(), 'SEL' => array(), ); | ||
250 | for($i=0; $i<count($objattr['items']); $i++) { | ||
251 | $item = $objattr['items'][$i]; | ||
252 | $data['VAL'][] = $item['exportValue']; | ||
253 | $data['OPT'][] = $item['content']; | ||
254 | if ($item['selected']) { $data['SEL'][] = $i; } | ||
255 | } | ||
256 | if (count($data['SEL'])==0 && $this->formSelectDefaultOption) {$data['SEL'][] = 0; } | ||
257 | $this->mpdf->SetTColor($objattr['color']); | ||
258 | $this->SetFormChoice( $w, $h, $objattr['fieldname'], $flags, $data, $rtlalign, $js ); | ||
259 | $this->mpdf->SetTColor($this->mpdf->ConvertColor(0)); | ||
260 | } | ||
261 | else { | ||
262 | $save_linemaxfontsize = $this->mpdf->linemaxfontsize; | ||
263 | $this->mpdf->linemaxfontsize = $this->mpdf->FontSize; | ||
264 | $this->mpdf->magic_reverse_dir($texto, false, $blockdir); // *RTL* | ||
265 | $this->mpdf->SetLineWidth(0.2 /$k ); | ||
266 | if (isset($objattr['disabled']) && $objattr['disabled']) { | ||
267 | $this->mpdf->SetFColor($this->mpdf->ConvertColor(225)); | ||
268 | $this->mpdf->SetTColor($this->mpdf->ConvertColor(127)); | ||
269 | } | ||
270 | else { | ||
271 | $this->mpdf->SetFColor($this->mpdf->ConvertColor(250)); | ||
272 | $this->mpdf->SetTColor($this->mpdf->ConvertColor(0)); | ||
273 | } | ||
274 | $w -= $this->form_element_spacing['select']['outer']['h']*2 /$k ; | ||
275 | $h -= $this->form_element_spacing['select']['outer']['v']*2 /$k ; | ||
276 | $this->mpdf->x += $this->form_element_spacing['select']['outer']['h'] /$k ; | ||
277 | $this->mpdf->y += $this->form_element_spacing['select']['outer']['v'] /$k ; | ||
278 | $this->mpdf->Cell($w-($this->mpdf->FontSize*1.4),$h,$texto,1,0,$rtlalign,1,'',0,$this->form_element_spacing['select']['inner']['h'] /$k,$this->form_element_spacing['select']['inner']['h'] /$k , 'M') ; | ||
279 | $this->mpdf->SetFColor($this->mpdf->ConvertColor(190)); | ||
280 | $save_font = $this->mpdf->FontFamily; | ||
281 | $save_currentfont = $this->mpdf->currentfontfamily; | ||
282 | if ($this->mpdf->PDFA || $this->mpdf->PDFX) { | ||
283 | if (($this->mpdf->PDFA && !$this->mpdf->PDFAauto) || ($this->mpdf->PDFX && !$this->mpdf->PDFXauto)) { $this->mpdf->PDFAXwarnings[] = "Core Adobe font Zapfdingbats cannot be embedded in mPDF - used in Form element: Select - which is required for PDFA1-b or PDFX/1-a. (Different character/font will be substituted.)"; } | ||
284 | $this->mpdf->SetFont('sans'); | ||
285 | if ($this->mpdf->_charDefined($this->mpdf->CurrentFont['cw'], 9660)) { $down = "\xe2\x96\xbc"; } | ||
286 | else { $down = '='; } | ||
287 | $this->mpdf->Cell(($this->mpdf->FontSize*1.4),$h,$down,1,0,'C',1,'',0,0,0, 'M') ; | ||
288 | } | ||
289 | else { | ||
290 | $this->mpdf->SetFont('czapfdingbats','',0); | ||
291 | $this->mpdf->Cell(($this->mpdf->FontSize*1.4),$h,chr(116),1,0,'C',1,'',0,0,0, 'M') ; | ||
292 | } | ||
293 | $this->mpdf->SetFont($save_font,'',0); | ||
294 | $this->mpdf->currentfontfamily = $save_currentfont; | ||
295 | $this->mpdf->linemaxfontsize = $save_linemaxfontsize; | ||
296 | $this->mpdf->SetFColor($this->mpdf->ConvertColor(255)); | ||
297 | $this->mpdf->SetTColor($this->mpdf->ConvertColor(0)); | ||
298 | } | ||
299 | } | ||
300 | |||
301 | function print_ob_imageinput($objattr,$w,$h,$texto,$rtlalign,$k,$blockdir) { | ||
302 | // INPUT/BUTTON as IMAGE | ||
303 | if ($this->mpdf->useActiveForms) { | ||
304 | // Flags: 1 - Readonly; 3 - No export; | ||
305 | $flags = array(); | ||
306 | if ($objattr['disabled']) { $flags[] = 1; } // readonly | ||
307 | if ($objattr['disabled']) { $flags[] = 3; } // no export | ||
308 | if ($objattr['onClick']) { $js = $objattr['onClick']; } | ||
309 | else { $js = ''; } | ||
310 | $this->SetJSButton( $w, $h, $objattr['fieldname'], $objattr['value'], $js, $objattr['ID'], $objattr['title'], $flags, $objattr['Indexed']); | ||
311 | } | ||
312 | else { | ||
313 | $this->mpdf->y = $objattr['INNER-Y']; | ||
314 | $this->mpdf->_out( sprintf("q %.3F 0 0 %.3F %.3F %.3F cm /I%d Do Q",$objattr['INNER-WIDTH'] *_MPDFK,$objattr['INNER-HEIGHT'] *_MPDFK,$objattr['INNER-X'] *_MPDFK,($this->mpdf->h-($objattr['INNER-Y'] +$objattr['INNER-HEIGHT'] ))*_MPDFK,$objattr['ID'] ) ); | ||
315 | if (isset($objattr['BORDER-WIDTH']) && $objattr['BORDER-WIDTH']) { $this->mpdf->PaintImgBorder($objattr,$is_table); } | ||
316 | } | ||
317 | } | ||
318 | |||
319 | function print_ob_button($objattr,$w,$h,$texto,$rtlalign,$k,$blockdir) { | ||
320 | // BUTTON | ||
321 | if ($this->mpdf->useActiveForms) { | ||
322 | // Flags: 1 - Readonly; 3 - No export; | ||
323 | $flags = array(); | ||
324 | if ($objattr['disabled']) { $flags[] = 1; } // readonly | ||
325 | if ($objattr['disabled']) { $flags[] = 3; } // no export | ||
326 | if ($objattr['disabled']) { $objattr['color'] = array(3,128,128,128); } | ||
327 | $this->mpdf->SetTColor($objattr['color']); | ||
328 | if ($objattr['subtype'] == 'RESET') { | ||
329 | $this->SetFormButtonText( $objattr['value'] ); | ||
330 | $this->SetFormReset( $w, $h, $objattr['fieldname'], $objattr['value'], $objattr['title'], $flags, $objattr['background-col'], $objattr['border-col'], $objattr['noprint'] ); | ||
331 | } | ||
332 | else if ($objattr['subtype'] == 'SUBMIT') { | ||
333 | $url = $this->formAction; | ||
334 | $type = $this->formExportType; | ||
335 | $method = $this->formMethod; | ||
336 | $this->SetFormButtonText( $objattr['value'] ); | ||
337 | $this->SetFormSubmit( $w, $h, $objattr['fieldname'], $objattr['value'], $url, $objattr['title'], $type, $method, $flags, $objattr['background-col'], $objattr['border-col'], $objattr['noprint'] ); | ||
338 | } | ||
339 | else if ($objattr['subtype'] == 'BUTTON') { | ||
340 | $this->SetFormButtonText( $objattr['value'] ); | ||
341 | if ($objattr['onClick']) { $js = $objattr['onClick']; } | ||
342 | else { $js = ''; } | ||
343 | $this->SetJSButton( $w, $h, $objattr['fieldname'], $objattr['value'], $js, 0, $objattr['title'], $flags, false, $objattr['background-col'], $objattr['border-col'], $objattr['noprint'] ); | ||
344 | } | ||
345 | $this->mpdf->SetTColor($this->mpdf->ConvertColor(0)); | ||
346 | } | ||
347 | else { | ||
348 | $this->mpdf->SetLineWidth(0.2 /$k ); | ||
349 | $this->mpdf->SetFColor($this->mpdf->ConvertColor(190)); | ||
350 | $w -= $this->form_element_spacing['button']['outer']['h']*2 /$k ; | ||
351 | $h -= $this->form_element_spacing['button']['outer']['v']*2 /$k ; | ||
352 | $this->mpdf->x += $this->form_element_spacing['button']['outer']['h'] /$k ; | ||
353 | $this->mpdf->y += $this->form_element_spacing['button']['outer']['v'] /$k ; | ||
354 | $this->mpdf->RoundedRect($this->mpdf->x, $this->mpdf->y, $w, $h, 0.5 /$k , 'DF'); | ||
355 | $w -= $this->form_element_spacing['button']['inner']['h']*2 /$k ; | ||
356 | $h -= $this->form_element_spacing['button']['inner']['v']*2 /$k ; | ||
357 | $this->mpdf->x += $this->form_element_spacing['button']['inner']['h'] /$k ; | ||
358 | $this->mpdf->y += $this->form_element_spacing['button']['inner']['v'] /$k ; | ||
359 | $save_linemaxfontsize = $this->mpdf->linemaxfontsize; | ||
360 | $this->mpdf->linemaxfontsize = $this->mpdf->FontSize; | ||
361 | $this->mpdf->magic_reverse_dir($texto, false, $blockdir); // *RTL* | ||
362 | $this->mpdf->Cell($w,$h,$texto,'',0,'C',0,'',0,0,0, 'M') ; | ||
363 | $this->mpdf->SetFColor($this->mpdf->ConvertColor(0)); | ||
364 | $this->mpdf->linemaxfontsize = $save_linemaxfontsize; | ||
365 | } | ||
366 | } | ||
367 | |||
368 | function print_ob_checkbox($objattr,$w,$h,$texto,$rtlalign,$k,$blockdir,$x,$y) { | ||
369 | // CHECKBOX | ||
370 | if ($this->mpdf->useActiveForms) { | ||
371 | // Flags: 1 - Readonly; 2 - Required; 3 - No export; | ||
372 | $flags = array(); | ||
373 | if ($objattr['disabled']) { $flags[] = 1; } // readonly | ||
374 | if ($objattr['disabled']) { $flags[] = 3; } // no export | ||
375 | $checked = false; | ||
376 | if ($objattr['checked']) { $checked = true; } | ||
377 | if ($this->formUseZapD) { | ||
378 | $save_font = $this->mpdf->FontFamily; | ||
379 | $save_currentfont = $this->mpdf->currentfontfamily; | ||
380 | $this->mpdf->SetFont('czapfdingbats','',0); | ||
381 | } | ||
382 | $this->SetCheckBox( $w, $h, $objattr['fieldname'], $objattr['value'], $objattr['title'], $checked, $flags, $objattr['disabled'] ); | ||
383 | if ($this->formUseZapD) { | ||
384 | $this->mpdf->SetFont($save_font,'',0); | ||
385 | $this->mpdf->currentfontfamily = $save_currentfont; | ||
386 | } | ||
387 | } | ||
388 | else { | ||
389 | $iw = $w * 0.7; | ||
390 | $ih = $h * 0.7; | ||
391 | $lx = $x + (($w-$iw)/2); | ||
392 | $ty = $y + (($h-$ih)/2); | ||
393 | $rx = $lx + $iw; | ||
394 | $by = $ty + $ih; | ||
395 | $this->mpdf->SetLineWidth(0.2 /$k ); | ||
396 | if (isset($objattr['disabled']) && $objattr['disabled']) { | ||
397 | $this->mpdf->SetFColor($this->mpdf->ConvertColor(225)); | ||
398 | $this->mpdf->SetDColor($this->mpdf->ConvertColor(127)); | ||
399 | } | ||
400 | else { | ||
401 | $this->mpdf->SetFColor($this->mpdf->ConvertColor(250)); | ||
402 | $this->mpdf->SetDColor($this->mpdf->ConvertColor(0)); | ||
403 | } | ||
404 | $this->mpdf->Rect($lx,$ty,$iw,$ih,'DF'); | ||
405 | if (isset($objattr['checked']) && $objattr['checked']) { | ||
406 | //Round join and cap | ||
407 | $this->mpdf->SetLineCap(1); | ||
408 | $this->mpdf->Line($lx,$ty,$rx,$by); | ||
409 | $this->mpdf->Line($lx,$by,$rx,$ty); | ||
410 | //Set line cap style back to square | ||
411 | $this->mpdf->SetLineCap(2); | ||
412 | } | ||
413 | $this->mpdf->SetFColor($this->mpdf->ConvertColor(255)); | ||
414 | $this->mpdf->SetDColor($this->mpdf->ConvertColor(0)); | ||
415 | } | ||
416 | } | ||
417 | |||
418 | function print_ob_radio($objattr,$w,$h,$texto,$rtlalign,$k,$blockdir,$x,$y) { | ||
419 | // RADIO | ||
420 | if ($this->mpdf->useActiveForms) { | ||
421 | // Flags: 1 - Readonly; 2 - Required; 3 - No export; | ||
422 | $flags = array(); | ||
423 | if ($objattr['disabled']) { $flags[] = 1; } // readonly | ||
424 | if ($objattr['disabled']) { $flags[] = 3; } // no export | ||
425 | $checked = false; | ||
426 | if ($objattr['checked']) { $checked = true; } | ||
427 | if ($this->formUseZapD) { | ||
428 | $save_font = $this->mpdf->FontFamily; | ||
429 | $save_currentfont = $this->mpdf->currentfontfamily; | ||
430 | $this->mpdf->SetFont('czapfdingbats','',0); | ||
431 | } | ||
432 | $this->SetRadio( $w, $h, $objattr['fieldname'], $objattr['value'], $objattr['title'], $checked, $flags, $objattr['disabled'] ); | ||
433 | if ($this->formUseZapD) { | ||
434 | $this->mpdf->SetFont($save_font,'',0); | ||
435 | $this->mpdf->currentfontfamily = $save_currentfont; | ||
436 | } | ||
437 | } | ||
438 | else { | ||
439 | $this->mpdf->SetLineWidth(0.2 /$k ); | ||
440 | $radius = $this->mpdf->FontSize *0.35; | ||
441 | $cx = $x + ($w/2); | ||
442 | $cy = $y + ($h/2); | ||
443 | if (isset($objattr['disabled']) && $objattr['disabled']) { | ||
444 | $this->mpdf->SetFColor($this->mpdf->ConvertColor(127)); | ||
445 | $this->mpdf->SetDColor($this->mpdf->ConvertColor(127)); | ||
446 | } | ||
447 | else { | ||
448 | $this->mpdf->SetFColor($this->mpdf->ConvertColor(0)); | ||
449 | $this->mpdf->SetDColor($this->mpdf->ConvertColor(0)); | ||
450 | } | ||
451 | $this->mpdf->Circle($cx,$cy,$radius,'D'); | ||
452 | if (isset($objattr['checked']) && $objattr['checked']) { | ||
453 | $this->mpdf->Circle($cx,$cy,$radius*0.4,'DF'); | ||
454 | } | ||
455 | $this->mpdf->SetFColor($this->mpdf->ConvertColor(255)); | ||
456 | $this->mpdf->SetDColor($this->mpdf->ConvertColor(0)); | ||
457 | |||
458 | } | ||
459 | } | ||
460 | |||
461 | |||
462 | // In _putpages | ||
463 | function countPageForms($n, &$totaladdnum) { | ||
464 | foreach( $this->forms as $form ) { | ||
465 | if ( $form['page'] == $n ) { | ||
466 | $totaladdnum++; | ||
467 | if ( $form['typ'] == 'Tx' ) { | ||
468 | if ( isset($this->array_form_text_js[$form['T']]) ) { | ||
469 | if ( isset($this->array_form_text_js[$form['T']]['F']) ) { $totaladdnum++; } | ||
470 | if ( isset($this->array_form_text_js[$form['T']]['K']) ) { $totaladdnum++; } | ||
471 | if ( isset($this->array_form_text_js[$form['T']]['V']) ) { $totaladdnum++; } | ||
472 | if ( isset($this->array_form_text_js[$form['T']]['C']) ) { $totaladdnum++; } | ||
473 | } | ||
474 | } | ||
475 | if ( $form['typ'] == 'Bt' ) { | ||
476 | if ( isset($this->array_form_button_js[$form['T']]) ) { $totaladdnum++; } | ||
477 | if ( isset($this->form_button_icon[$form['T']]) ) { | ||
478 | $totaladdnum++; | ||
479 | if ( $this->form_button_icon[$form['T']]['Indexed'] ) { $totaladdnum++; } | ||
480 | } | ||
481 | if ( $form['subtype'] == 'radio' ) { $totaladdnum+=2; } | ||
482 | else if ( $form['subtype'] == 'checkbox' && $this->formUseZapD ) { $totaladdnum++; } | ||
483 | else if ( $form['subtype'] == 'checkbox' && !$this->formUseZapD ) { $totaladdnum+=2; } | ||
484 | } | ||
485 | if ( $form['typ'] == 'Ch' ) { | ||
486 | if ( isset($this->array_form_choice_js[$form['T']]) ) { $totaladdnum++; } | ||
487 | } | ||
488 | } | ||
489 | } | ||
490 | } | ||
491 | |||
492 | // In _putpages | ||
493 | function addFormIds($n, &$s, &$annotid) { | ||
494 | foreach( $this->forms as $form ) { | ||
495 | if ( $form['page'] == $n ) { | ||
496 | $s .= ($annotid) . ' 0 R '; | ||
497 | $annotid++; | ||
498 | if ( $form['typ'] == 'Tx' ) { | ||
499 | if ( isset($this->array_form_text_js[$form['T']]) ) { | ||
500 | if ( isset($this->array_form_text_js[$form['T']]['F']) ) { $annotid++; } | ||
501 | if ( isset($this->array_form_text_js[$form['T']]['K']) ) { $annotid++; } | ||
502 | if ( isset($this->array_form_text_js[$form['T']]['V']) ) { $annotid++; } | ||
503 | if ( isset($this->array_form_text_js[$form['T']]['C']) ) { $annotid++; } | ||
504 | } | ||
505 | } | ||
506 | if ( $form['typ'] == 'Bt' ) { | ||
507 | if ( isset($this->array_form_button_js[$form['T']]) ) { $annotid++; } | ||
508 | if ( isset($this->form_button_icon[$form['T']]) ) { | ||
509 | $annotid++; | ||
510 | if ( $this->form_button_icon[$form['T']]['Indexed'] ) { $annotid++; } | ||
511 | } | ||
512 | if ( $form['subtype'] == 'radio' ) { $annotid+=2; } | ||
513 | else if ( $form['subtype'] == 'checkbox' && $this->formUseZapD ) { $annotid++; } | ||
514 | else if ( $form['subtype'] == 'checkbox' && !$this->formUseZapD ) { $annotid+=2; } | ||
515 | } | ||
516 | if ( $form['typ'] == 'Ch' ) { | ||
517 | if ( isset($this->array_form_choice_js[$form['T']]) ) { $annotid++; } | ||
518 | } | ||
519 | } | ||
520 | } | ||
521 | } | ||
522 | |||
523 | // In _putannots | ||
524 | function _putFormItems($n, $hPt) { | ||
525 | foreach( $this->forms as $val) { | ||
526 | if ( $val['page'] == $n ) { | ||
527 | if ( $val['typ'] == 'Tx' ) $this->_putform_tx( $val, $hPt ); | ||
528 | if ( $val['typ'] == 'Ch' ) $this->_putform_ch( $val, $hPt ); | ||
529 | if ( $val['typ'] == 'Bt' ) $this->_putform_bt( $val, $hPt ); | ||
530 | } | ||
531 | } | ||
532 | } | ||
533 | |||
534 | // In _putannots | ||
535 | function _putRadioItems($n) { | ||
536 | // Output Radio Groups | ||
537 | $key = 1; | ||
538 | foreach($this->form_radio_groups AS $name=>$frg) { | ||
539 | $this->mpdf->_newobj(); | ||
540 | $this->pdf_acro_array .= $this->mpdf->n.' 0 R '; | ||
541 | $this->mpdf->_out('<<'); | ||
542 | $this->mpdf->_out('/Type /Annot '); | ||
543 | $this->mpdf->_out('/Subtype /Widget'); | ||
544 | $this->mpdf->_out('/NM '.$this->mpdf->_textstring(sprintf('%04u-%04u', $n, (3000 + $key++)))); | ||
545 | $this->mpdf->_out('/M '.$this->mpdf->_textstring('D:'.date('YmdHis'))); | ||
546 | $this->mpdf->_out('/Rect [0 0 0 0] '); | ||
547 | $this->mpdf->_out('/FT /Btn '); | ||
548 | if ($frg['disabled']) { $flags=array(1,3,15,16); } // NoExport and readonly | ||
549 | else { $flags=array(15,16); } // Flags for Radiobutton, and NoToggleToOff | ||
550 | $this->mpdf->_out('/Ff '.$this->_setflag($flags) ); | ||
551 | $kstr = ''; | ||
552 | $optstr = ''; | ||
553 | foreach($frg['kids'] AS $kid) { | ||
554 | $kstr .= $this->forms[$kid['n']]['obj'].' 0 R '; | ||
555 | // $optstr .= ' '.$this->mpdf->_textstring($kid['OPT']).' '; | ||
556 | } | ||
557 | $this->mpdf->_out('/Kids [ '.$kstr.' ] '); // 11 0 R 12 0 R etc. | ||
558 | // $this->mpdf->_out('/Opt [ '.$optstr.' ] '); | ||
559 | |||
560 | //V entry holds index corresponding to the appearance state of | ||
561 | //whichever child field is currently in the on state = or Off | ||
562 | if (isset($frg['on'])) { $state = $frg['on']; } | ||
563 | else { $state = 'Off'; } | ||
564 | $this->mpdf->_out('/V /'.$state.' '); | ||
565 | $this->mpdf->_out('/DV /'.$state.' '); | ||
566 | $this->mpdf->_out('/T '.$this->mpdf->_textstring($name).' '); | ||
567 | $this->mpdf->_out('>>'); | ||
568 | $this->mpdf->_out('endobj'); | ||
569 | } | ||
570 | } | ||
571 | |||
572 | function _putFormsCatalog() { | ||
573 | if (isset($this->pdf_acro_array) ) { | ||
574 | $this->mpdf->_out('/AcroForm << /DA (/F1 0 Tf 0 g )'); | ||
575 | $this->mpdf->_out('/Q 0'); | ||
576 | $this->mpdf->_out('/Fields ['.$this->pdf_acro_array.']'); | ||
577 | $f = ''; | ||
578 | foreach($this->form_fonts AS $fn) { | ||
579 | if (is_array($this->mpdf->fonts[$fn]['n'])) { $this->mpdf->Error("Cannot use fonts with SMP or SIP characters for interactive Form elements"); } | ||
580 | $f .= '/F'.$this->mpdf->fonts[$fn]['i'].' '.$this->mpdf->fonts[$fn]['n'].' 0 R '; | ||
581 | } | ||
582 | $this->mpdf->_out('/DR << /Font << '.$f.' >> >>'); | ||
583 | // CO Calculation Order | ||
584 | if ( $this->pdf_array_co ) { | ||
585 | $this->mpdf->_out('/CO ['.$this->pdf_array_co.']'); | ||
586 | } | ||
587 | $this->mpdf->_out('/NeedAppearances true'); | ||
588 | $this->mpdf->_out('>>'); | ||
589 | } | ||
590 | } | ||
591 | |||
592 | |||
593 | |||
594 | function SetFormButtonJS( $name, $js ) { | ||
595 | $js = str_replace("\t",' ', trim($js) ); | ||
596 | if ( isset($name) && isset($js) ) { | ||
597 | $this->array_form_button_js[$this->mpdf->_escape($name)] = array( | ||
598 | 'js' => $js | ||
599 | ); | ||
600 | } | ||
601 | } | ||
602 | |||
603 | function SetFormChoiceJS( $name, $js ) { | ||
604 | $js = str_replace("\t",' ', trim($js) ); | ||
605 | if ( isset($name) && isset($js) ) { | ||
606 | $this->array_form_choice_js[$this->mpdf->_escape($name)] = array( | ||
607 | 'js' => $js | ||
608 | ); | ||
609 | } | ||
610 | } | ||
611 | |||
612 | function SetFormTextJS( $name, $js) { | ||
613 | for ($i=0; $i<count($js); $i++) { | ||
614 | $j = str_replace("\t",' ', trim($js[$i][1]) ); | ||
615 | $format = $js[$i][0]; | ||
616 | if ($name) { | ||
617 | $this->array_form_text_js[$this->mpdf->_escape($name)][$format] = array('js' => $j); | ||
618 | } | ||
619 | } | ||
620 | } | ||
621 | |||
622 | |||
623 | function Win1252ToPDFDocEncoding($txt) { | ||
624 | $Win1252ToPDFDocEncoding = array( | ||
625 | chr(0200) => chr(0240), chr(0214) => chr(0226), chr(0212) => chr(0227), chr(0237) => chr(0230), | ||
626 | chr(0225) => chr(0200), chr(0210) => chr(0032), chr(0206) => chr(0201), chr(0207) => chr(0202), | ||
627 | chr(0205) => chr(0203), chr(0227) => chr(0204), chr(0226) => chr(0205), chr(0203) => chr(0206), | ||
628 | chr(0213) => chr(0210), chr(0233) => chr(0211), chr(0211) => chr(0213), chr(0204) => chr(0214), | ||
629 | chr(0223) => chr(0215), chr(0224) => chr(0216), chr(0221) => chr(0217), chr(0222) => chr(0220), | ||
630 | chr(0202) => chr(0221), chr(0232) => chr(0235), chr(0230) => chr(0037), chr(0231) => chr(0222), | ||
631 | chr(0216) => chr(0231), chr(0240) => chr(0040) | ||
632 | ); // mPDF 5.3.46 | ||
633 | return strtr($txt, $Win1252ToPDFDocEncoding ); | ||
634 | } | ||
635 | |||
636 | |||
637 | function SetFormText( $w, $h, $name, $value = '', $default = '', $title = '', $flags = array(), $align='L', $hidden = false, $maxlen=-1, $js='', $background_col=false, $border_col=false ) { | ||
638 | // Flags: 1 - Readonly; 2 - Required; 3 - No export; 13 - textarea; 14 - Password | ||
639 | $this->formn++; | ||
640 | if( $align == 'C' ) { $align = '1'; } | ||
641 | else if( $align == 'R' ) { $align = '2'; } | ||
642 | else { $align = '0'; } | ||
643 | if ($maxlen < 1) { $maxlen = false; } | ||
644 | if (!preg_match('/^[a-zA-Z0-9_:\-]+$/', $name)) { | ||
645 | $this->mpdf->Error("Field [".$name."] must have a name attribute, which can only contain letters, numbers, colon(:), undersore(_) or hyphen(-)"); | ||
646 | } | ||
647 | if ($this->mpdf->onlyCoreFonts) { | ||
648 | $value = $this->Win1252ToPDFDocEncoding($value); | ||
649 | $default = $this->Win1252ToPDFDocEncoding($default); | ||
650 | $title = $this->Win1252ToPDFDocEncoding($title); | ||
651 | } | ||
652 | else { | ||
653 | if (isset($this->mpdf->CurrentFont['subset'])) { | ||
654 | $this->mpdf->UTF8StringToArray($value, true); // Add characters to font subset | ||
655 | $this->mpdf->UTF8StringToArray($default, true); // Add characters to font subset | ||
656 | $this->mpdf->UTF8StringToArray($title, true); // Add characters to font subset | ||
657 | } | ||
658 | if ($value) $value = $this->mpdf->UTF8ToUTF16BE($value, true); | ||
659 | if ($default ) $default = $this->mpdf->UTF8ToUTF16BE($default, true); | ||
660 | $title = $this->mpdf->UTF8ToUTF16BE($title, true); | ||
661 | } | ||
662 | if ($background_col) { $bg_c = $this->mpdf->SetColor($background_col, 'CodeOnly'); } | ||
663 | else { $bg_c = $this->form_background_color; } | ||
664 | if ($border_col) { $bc_c = $this->mpdf->SetColor($border_col, 'CodeOnly'); } | ||
665 | else { $bc_c = $this->form_border_color; } | ||
666 | $f = array( 'n' => $this->formn, | ||
667 | 'typ' => 'Tx', | ||
668 | 'page' => $this->mpdf->page, | ||
669 | 'x' => $this->mpdf->x, | ||
670 | 'y' => $this->mpdf->y, | ||
671 | 'w' => $w, | ||
672 | 'h' => $h, | ||
673 | 'T' => $name, | ||
674 | 'FF' => $flags, | ||
675 | 'V' => $value, | ||
676 | 'DV' => $default, | ||
677 | 'TU' => $title, | ||
678 | 'hidden' => $hidden, | ||
679 | 'Q' => $align, | ||
680 | 'maxlen' => $maxlen, | ||
681 | 'BS_W' => $this->form_border_width, | ||
682 | 'BS_S' => $this->form_border_style, | ||
683 | 'BC_C' => $bc_c, | ||
684 | 'BG_C' => $bg_c, | ||
685 | 'style' => array( | ||
686 | 'font' => $this->mpdf->FontFamily, | ||
687 | 'fontsize' => $this->mpdf->FontSizePt, | ||
688 | 'fontcolor' => $this->mpdf->TextColor, | ||
689 | ) | ||
690 | ); | ||
691 | if (is_array($js) && count($js)>0) { $this->SetFormTextJS( $name, $js); } // mPDF 5.3.25 | ||
692 | if ($this->mpdf->keep_block_together) { $this->mpdf->ktForms[]= $f; } | ||
693 | else if ($this->mpdf->writingHTMLheader || $this->mpdf->writingHTMLfooter) { $this->mpdf->HTMLheaderPageForms[]= $f; } | ||
694 | else { | ||
695 | if ($this->mpdf->ColActive) { | ||
696 | $this->mpdf->columnbuffer[] = array('s' => 'ACROFORM', 'col' => $this->mpdf->CurrCol, 'x' => $this->mpdf->x, 'y' => $this->mpdf->y, | ||
697 | 'h' => $h); | ||
698 | $this->mpdf->columnForms[$this->mpdf->CurrCol][INTVAL($this->mpdf->x)][INTVAL($this->mpdf->y)] = $this->formn; | ||
699 | } | ||
700 | $this->forms[$this->formn] = $f; | ||
701 | } | ||
702 | if (!in_array($this->mpdf->FontFamily, $this->form_fonts)) { | ||
703 | $this->form_fonts[] = $this->mpdf->FontFamily; | ||
704 | $this->mpdf->fonts[$this->mpdf->FontFamily]['used'] = true; | ||
705 | } | ||
706 | if ( !$hidden ) $this->mpdf->x += $w; | ||
707 | |||
708 | } | ||
709 | |||
710 | |||
711 | function SetFormChoice( $w, $h, $name, $flags, $array, $align='L', $js = '' ) { | ||
712 | $this->formn++; | ||
713 | if( $this->mpdf->blk[$this->mpdf->blklvl]['direction'] == 'rtl' ) { $align = '2'; } | ||
714 | else { $align = '0'; } | ||
715 | if (!preg_match('/^[a-zA-Z0-9_:\-]+$/', $name)) { | ||
716 | $this->mpdf->Error("Field [".$name."] must have a name attribute, which can only contain letters, numbers, colon(:), undersore(_) or hyphen(-)"); | ||
717 | } | ||
718 | if ($this->mpdf->onlyCoreFonts) { | ||
719 | for($i=0;$i<count($array['VAL']);$i++) { | ||
720 | $array['VAL'][$i] = $this->Win1252ToPDFDocEncoding($array['VAL'][$i]); | ||
721 | $array['OPT'][$i] = $this->Win1252ToPDFDocEncoding($array['OPT'][$i]); | ||
722 | } | ||
723 | } | ||
724 | else { | ||
725 | for($i=0;$i<count($array['VAL']);$i++) { | ||
726 | if (isset($this->mpdf->CurrentFont['subset'])) { | ||
727 | $this->mpdf->UTF8StringToArray($array['VAL'][$i], true); // Add characters to font subset | ||
728 | $this->mpdf->UTF8StringToArray($array['OPT'][$i], true); // Add characters to font subset | ||
729 | } | ||
730 | if ($array['VAL'][$i] ) $array['VAL'][$i] = $this->mpdf->UTF8ToUTF16BE($array['VAL'][$i], true); | ||
731 | if ($array['OPT'][$i] ) $array['OPT'][$i] = $this->mpdf->UTF8ToUTF16BE($array['OPT'][$i], true); | ||
732 | } | ||
733 | } | ||
734 | $f = array( 'n' => $this->formn, | ||
735 | 'typ' => 'Ch', | ||
736 | 'page' => $this->mpdf->page, | ||
737 | 'x' => $this->mpdf->x, | ||
738 | 'y' => $this->mpdf->y, | ||
739 | 'w' => $w, | ||
740 | 'h' => $h, | ||
741 | 'T' => $name, | ||
742 | 'OPT' => $array, | ||
743 | 'FF' => $flags, | ||
744 | 'Q' => $align, | ||
745 | 'BS_W' => $this->form_border_width, | ||
746 | 'BS_S' => $this->form_border_style, | ||
747 | 'BC_C' => $this->form_border_color, | ||
748 | 'BG_C' => $this->form_background_color, | ||
749 | 'style' => array( | ||
750 | 'font' => $this->mpdf->FontFamily, | ||
751 | 'fontsize' => $this->mpdf->FontSizePt, | ||
752 | 'fontcolor' => $this->mpdf->TextColor, | ||
753 | ) | ||
754 | ); | ||
755 | if ($js) { $this->SetFormChoiceJS( $name, $js ); } | ||
756 | if ($this->mpdf->keep_block_together) { $this->mpdf->ktForms[]= $f; } | ||
757 | else if ($this->mpdf->writingHTMLheader || $this->mpdf->writingHTMLfooter) { $this->mpdf->HTMLheaderPageForms[]= $f; } | ||
758 | else { | ||
759 | if ($this->mpdf->ColActive) { | ||
760 | $this->mpdf->columnbuffer[] = array('s' => 'ACROFORM', 'col' => $this->mpdf->CurrCol, 'x' => $this->mpdf->x, 'y' => $this->mpdf->y, | ||
761 | 'h' => $h); | ||
762 | $this->mpdf->columnForms[$this->mpdf->CurrCol][INTVAL($this->mpdf->x)][INTVAL($this->mpdf->y)] = $this->formn; | ||
763 | } | ||
764 | $this->forms[$this->formn] = $f; | ||
765 | } | ||
766 | if (!in_array($this->mpdf->FontFamily, $this->form_fonts)) { | ||
767 | $this->form_fonts[] = $this->mpdf->FontFamily; | ||
768 | $this->mpdf->fonts[$this->mpdf->FontFamily]['used'] = true; | ||
769 | } | ||
770 | $this->mpdf->x += $w; | ||
771 | } | ||
772 | |||
773 | // CHECKBOX | ||
774 | function SetCheckBox( $w, $h, $name, $value, $title = '', $checked = false, $flags = array(), $disabled=false ) { | ||
775 | $this->SetFormButton( $w, $h, $name, $value, 'checkbox', $title, $flags, $checked, $disabled ); | ||
776 | $this->mpdf->x += $w; | ||
777 | } | ||
778 | |||
779 | |||
780 | // RADIO | ||
781 | function SetRadio( $w, $h, $name, $value, $title = '', $checked = false, $flags = array(), $disabled=false ) { | ||
782 | $this->SetFormButton( $w, $h, $name, $value, 'radio', $title, $flags, $checked, $disabled ); | ||
783 | $this->mpdf->x += $w; | ||
784 | } | ||
785 | |||
786 | |||
787 | function SetFormReset( $w, $h, $name, $value = 'Reset', $title = '', $flags = array(), $background_col=false, $border_col=false, $noprint=false ) { | ||
788 | if (!$name) { $name = 'Reset'; } | ||
789 | $this->SetFormButton( $w, $h, $name, $value, 'reset', $title, $flags, false, false, $background_col, $border_col, $noprint); | ||
790 | $this->mpdf->x += $w; | ||
791 | } | ||
792 | |||
793 | |||
794 | function SetJSButton( $w, $h, $name, $value, $js, $image_id = 0, $title = '', $flags = array(), $indexed=false , $background_col=false, $border_col=false, $noprint=false ) { | ||
795 | $this->SetFormButton( $w, $h, $name, $value, 'js_button', $title, $flags, false, false, $background_col, $border_col, $noprint); | ||
796 | // pos => 1 = no caption, icon only; 0 = caption only | ||
797 | if ($image_id) { | ||
798 | $this->form_button_icon[$this->mpdf->_escape($name)] = array( | ||
799 | 'pos' => 1, | ||
800 | 'image_id' => $image_id, | ||
801 | 'Indexed' => $indexed, | ||
802 | ); | ||
803 | } | ||
804 | if ($js) { $this->SetFormButtonJS( $name, $js ); } | ||
805 | $this->mpdf->x += $w; | ||
806 | } | ||
807 | |||
808 | |||
809 | function SetFormSubmit( $w, $h, $name, $value = 'Submit', $url, $title = '', $typ = 'html', $method = 'POST', $flags = array(), $background_col=false, $border_col=false, $noprint=false) { | ||
810 | if (!$name) { $name = 'Submit'; } | ||
811 | $this->SetFormButton( $w, $h, $name, $value, 'submit', $title, $flags, false, false, $background_col, $border_col, $noprint); | ||
812 | $this->forms[$this->formn]['URL'] = $url; | ||
813 | $this->forms[$this->formn]['method'] = $method; | ||
814 | $this->forms[$this->formn]['exporttype'] = $typ; | ||
815 | $this->mpdf->x += $w; | ||
816 | } | ||
817 | |||
818 | |||
819 | function SetFormButtonText( $ca, $rc = '', $ac = '' ) { | ||
820 | if ($this->mpdf->onlyCoreFonts) { | ||
821 | $ca = $this->Win1252ToPDFDocEncoding($ca); | ||
822 | if ($rc) $rc = $this->Win1252ToPDFDocEncoding($rc); | ||
823 | if ($ac) $ac = $this->Win1252ToPDFDocEncoding($ac); | ||
824 | } | ||
825 | else { | ||
826 | if (isset($this->mpdf->CurrentFont['subset'])) { | ||
827 | $this->mpdf->UTF8StringToArray($ca, true); // Add characters to font subset | ||
828 | } | ||
829 | $ca = $this->mpdf->UTF8ToUTF16BE($ca, true); | ||
830 | if ($rc) { | ||
831 | if (isset($this->mpdf->CurrentFont['subset'])) { $this->mpdf->UTF8StringToArray($rc, true); } | ||
832 | $rc = $this->mpdf->UTF8ToUTF16BE($rc, true); | ||
833 | } | ||
834 | if ($ac) { | ||
835 | if (isset($this->mpdf->CurrentFont['subset'])) { $this->mpdf->UTF8StringToArray($ac, true); } | ||
836 | $ac = $this->mpdf->UTF8ToUTF16BE($ac, true); | ||
837 | } | ||
838 | } | ||
839 | $this->form_button_text = $ca; | ||
840 | $this->form_button_text_over = $rc ? $rc : $ca; | ||
841 | $this->form_button_text_click = $ac ? $ac : $ca; | ||
842 | } | ||
843 | |||
844 | |||
845 | function SetFormButton( $bb, $hh, $name, $value, $type, $title = '', $flags = array(), $checked=false, $disabled=false, $background_col=false, $border_col=false, $noprint=false ) { | ||
846 | $this->formn++; | ||
847 | if (!preg_match('/^[a-zA-Z0-9_:\-]+$/', $name)) { | ||
848 | $this->mpdf->Error("Field [".$name."] must have a name attribute, which can only contain letters, numbers, colon(:), undersore(_) or hyphen(-)"); | ||
849 | } | ||
850 | if (!$this->mpdf->onlyCoreFonts) { | ||
851 | if (isset($this->mpdf->CurrentFont['subset'])) { | ||
852 | $this->mpdf->UTF8StringToArray($title, true); // Add characters to font subset | ||
853 | $this->mpdf->UTF8StringToArray($value, true); // Add characters to font subset | ||
854 | } | ||
855 | $title = $this->mpdf->UTF8ToUTF16BE($title, true); | ||
856 | if ($type == 'checkbox') { | ||
857 | $uvalue = $this->mpdf->UTF8ToUTF16BE($value, true); | ||
858 | } | ||
859 | else if ($type == 'radio') { | ||
860 | $uvalue = $this->mpdf->UTF8ToUTF16BE($value, true); | ||
861 | $value = mb_convert_encoding($value, 'Windows-1252', 'UTF-8'); | ||
862 | } | ||
863 | else { | ||
864 | $value = $this->mpdf->UTF8ToUTF16BE($value, true); | ||
865 | $uvalue = $value; | ||
866 | } | ||
867 | } | ||
868 | else { | ||
869 | $title = $this->Win1252ToPDFDocEncoding($title); | ||
870 | $value = $this->Win1252ToPDFDocEncoding($value); //// ??? not needed | ||
871 | $uvalue = mb_convert_encoding($value, 'UTF-8', 'Windows-1252'); | ||
872 | $uvalue = $this->mpdf->UTF8ToUTF16BE($uvalue, true); | ||
873 | } | ||
874 | if ($type == 'radio' || $type == 'checkbox') { | ||
875 | if (!preg_match('/^[a-zA-Z0-9_:\-\.]+$/', $value)) { | ||
876 | $this->mpdf->Error("Field '".$name."' must have a value, which can only contain letters, numbers, colon(:), undersore(_), hyphen(-) or period(.)"); | ||
877 | } | ||
878 | } | ||
879 | if ($type == 'radio') { | ||
880 | if (!isset($this->form_radio_groups[$name])) { | ||
881 | $this->form_radio_groups[$name] = array( | ||
882 | 'page' => $this->mpdf->page, | ||
883 | 'kids' => array(), | ||
884 | ); | ||
885 | } | ||
886 | $this->form_radio_groups[$name]['kids'][] = array( | ||
887 | 'n' => $this->formn, 'V'=> $value, 'OPT'=>$uvalue, 'disabled'=>$disabled | ||
888 | ); | ||
889 | if ( $checked ) { $this->form_radio_groups[$name]['on'] = $value; } | ||
890 | // Disable the whole radio group if one is disabled, because of inconsistency in PDF readers | ||
891 | if ( $disabled ) { $this->form_radio_groups[$name]['disabled'] = true; } | ||
892 | } | ||
893 | if ($type == 'checkbox') { | ||
894 | $this->form_checkboxes = true; | ||
895 | } | ||
896 | if ( $checked ) { $activ = 1; } | ||
897 | else { $activ = 0; } | ||
898 | if ($background_col) { $bg_c = $this->mpdf->SetColor($background_col, 'CodeOnly'); } | ||
899 | else { $bg_c = $this->form_button_background_color; } | ||
900 | if ($border_col) { $bc_c = $this->mpdf->SetColor($border_col, 'CodeOnly'); } | ||
901 | else { $bc_c = $this->form_button_border_color; } | ||
902 | $f = array( 'n' => $this->formn, | ||
903 | 'typ' => 'Bt', | ||
904 | 'page' => $this->mpdf->page, | ||
905 | 'subtype' => $type, | ||
906 | 'x' => $this->mpdf->x, | ||
907 | 'y' => $this->mpdf->y, | ||
908 | 'w' => $bb, | ||
909 | 'h' => $hh, | ||
910 | 'T' => $name, | ||
911 | 'V' => $value, | ||
912 | 'OPT' => $uvalue, | ||
913 | 'TU' => $title, | ||
914 | 'FF' => $flags, | ||
915 | 'CA' => $this->form_button_text, | ||
916 | 'RC' => $this->form_button_text_over, | ||
917 | 'AC' => $this->form_button_text_click, | ||
918 | 'BS_W' => $this->form_button_border_width, | ||
919 | 'BS_S' => $this->form_button_border_style, | ||
920 | 'BC_C' => $bc_c, | ||
921 | 'BG_C' => $bg_c, | ||
922 | 'activ' => $activ, | ||
923 | 'disabled' => $disabled, | ||
924 | 'noprint' => $noprint, | ||
925 | 'style' => array( | ||
926 | 'font' => $this->mpdf->FontFamily, | ||
927 | 'fontsize' => $this->mpdf->FontSizePt, | ||
928 | 'fontcolor' => $this->mpdf->TextColor, | ||
929 | ) | ||
930 | ); | ||
931 | if ($this->mpdf->keep_block_together) { $this->mpdf->ktForms[]= $f; } | ||
932 | else if ($this->mpdf->writingHTMLheader || $this->mpdf->writingHTMLfooter) { $this->mpdf->HTMLheaderPageForms[]= $f; } | ||
933 | else { | ||
934 | if ($this->mpdf->ColActive) { | ||
935 | $this->mpdf->columnbuffer[] = array('s' => 'ACROFORM', 'col' => $this->mpdf->CurrCol, 'x' => $this->mpdf->x, 'y' => $this->mpdf->y, | ||
936 | 'h' => $hh); | ||
937 | $this->mpdf->columnForms[$this->mpdf->CurrCol][INTVAL($this->mpdf->x)][INTVAL($this->mpdf->y)] = $this->formn; | ||
938 | } | ||
939 | $this->forms[$this->formn] = $f; | ||
940 | } | ||
941 | if (!in_array($this->mpdf->FontFamily, $this->form_fonts)) { | ||
942 | $this->form_fonts[] = $this->mpdf->FontFamily; | ||
943 | $this->mpdf->fonts[$this->mpdf->FontFamily]['used'] = true; | ||
944 | } | ||
945 | |||
946 | $this->form_button_text = NULL; | ||
947 | $this->form_button_text_over = NULL; | ||
948 | $this->form_button_text_click = NULL; | ||
949 | } | ||
950 | |||
951 | |||
952 | |||
953 | function SetFormBorderWidth ( $string ) { | ||
954 | switch( $string ) { | ||
955 | case 'S': $this->form_border_width = '1'; | ||
956 | break; | ||
957 | case 'M': $this->form_border_width = '2'; | ||
958 | break; | ||
959 | case 'B': $this->form_border_width = '3'; | ||
960 | break; | ||
961 | case '0': $this->form_border_width = '0'; | ||
962 | break; | ||
963 | default: $this->form_border_width = '0'; | ||
964 | break; | ||
965 | } | ||
966 | } | ||
967 | |||
968 | |||
969 | function SetFormBorderStyle ( $string ) { | ||
970 | switch( $string ) { | ||
971 | case 'S': $this->form_border_style = 'S'; | ||
972 | break; | ||
973 | case 'D': $this->form_border_style = 'D /D [3]'; | ||
974 | break; | ||
975 | case 'B': $this->form_border_style = 'B'; | ||
976 | break; | ||
977 | case 'I': $this->form_border_style = 'I'; | ||
978 | break; | ||
979 | case 'U': $this->form_border_style = 'U'; | ||
980 | break; | ||
981 | default: $this->form_border_style = 'B'; | ||
982 | break; | ||
983 | } | ||
984 | } | ||
985 | |||
986 | function SetFormBorderColor ( $r, $g=-1, $b=-1 ) { | ||
987 | if ( ($r==0 and $g==0 and $b==0) || $g==-1 ) | ||
988 | $this->form_border_color = sprintf('%.3F', $r/255); | ||
989 | else | ||
990 | $this->form_border_color = sprintf('%.3F %.3F %.3F', $r/255, $g/255, $b/255); | ||
991 | } | ||
992 | |||
993 | function SetFormBackgroundColor ( $r, $g=-1, $b=-1 ) { | ||
994 | if ( ($r==0 and $g==0 and $b==0) || $g==-1 ) | ||
995 | $this->form_background_color = sprintf('%.3F', $r/255); | ||
996 | else | ||
997 | $this->form_background_color = sprintf('%.3F %.3F %.3F', $r/255, $g/255, $b/255); | ||
998 | } | ||
999 | |||
1000 | function SetFormD ( $W, $S, $BC, $BG ) { | ||
1001 | $this->SetFormBorderWidth ( $W ); | ||
1002 | $this->SetFormBorderStyle ( $S ); | ||
1003 | $this->SetFormBorderColor ( $BC ); | ||
1004 | $this->SetFormBackgroundColor ( $BG ); | ||
1005 | } | ||
1006 | |||
1007 | function _setflag( $array ) { | ||
1008 | $flag = 0; | ||
1009 | foreach($array as $val) { $flag += 1 << ($val-1); } | ||
1010 | return $flag; | ||
1011 | } | ||
1012 | |||
1013 | function _form_rect( $x, $y, $w, $h, $hPt ) { | ||
1014 | $x = $x * _MPDFK; | ||
1015 | $y = $hPt - ($y * _MPDFK); | ||
1016 | $x2 = $x + ($w * _MPDFK); | ||
1017 | $y2 = $y - ($h * _MPDFK); | ||
1018 | $rect = sprintf('%.3F %.3F %.3F %.3F', $x, $y2, $x2, $y ); | ||
1019 | return $rect; | ||
1020 | } | ||
1021 | |||
1022 | |||
1023 | function _put_button_icon( $array , $w, $h ) { | ||
1024 | if (isset($array['image_id'])) { | ||
1025 | $info = false; | ||
1026 | foreach($this->mpdf->images AS $iid=>$img) { | ||
1027 | if ($img['i'] == $array['image_id']) { | ||
1028 | $info = $this->mpdf->images[$iid]; | ||
1029 | break; | ||
1030 | } | ||
1031 | } | ||
1032 | } | ||
1033 | if (!$info) { die("Cannot find Button image"); } | ||
1034 | $this->mpdf->_newobj(); | ||
1035 | $this->mpdf->_out('<<'); | ||
1036 | $this->mpdf->_out('/Type /XObject'); | ||
1037 | $this->mpdf->_out('/Subtype /Image'); | ||
1038 | $this->mpdf->_out('/BBox [0 0 1 1]'); | ||
1039 | $this->mpdf->_out('/Length '.strlen($info['data'])); | ||
1040 | $this->mpdf->_out('/BitsPerComponent '.$info['bpc']); | ||
1041 | if ($info['cs']=='Indexed') { | ||
1042 | $this->mpdf->_out('/ColorSpace [/Indexed /DeviceRGB '.(strlen($info['pal'])/3-1).' '.($this->mpdf->n+1).' 0 R]'); | ||
1043 | } | ||
1044 | else { | ||
1045 | $this->mpdf->_out('/ColorSpace /'.$info['cs']); | ||
1046 | if ($info['cs']=='DeviceCMYK') | ||
1047 | if($info['type']=='jpg') { $this->mpdf->_out('/Decode [1 0 1 0 1 0 1 0]'); } | ||
1048 | } | ||
1049 | if ( isset($info['f']) ) | ||
1050 | $this->mpdf->_out('/Filter /'.$info['f']); | ||
1051 | if ( isset($info['parms']) ) | ||
1052 | $this->mpdf->_out($info['parms']); | ||
1053 | $this->mpdf->_out('/Width '.$info['w']); | ||
1054 | $this->mpdf->_out('/Height '.$info['h']); | ||
1055 | $this->mpdf->_out('>>'); | ||
1056 | $this->mpdf->_putstream($info['data']); | ||
1057 | $this->mpdf->_out('endobj'); | ||
1058 | unset($array); | ||
1059 | //Palette | ||
1060 | if($info['cs']=='Indexed') { | ||
1061 | $filter=($this->mpdf->compress) ? '/Filter /FlateDecode ' : ''; | ||
1062 | $this->mpdf->_newobj(); | ||
1063 | $pal=($this->mpdf->compress) ? gzcompress($info['pal']) : $info['pal']; | ||
1064 | $this->mpdf->_out('<<'.$filter.'/Length '.strlen($pal).'>>'); | ||
1065 | $this->mpdf->_putstream($pal); | ||
1066 | $this->mpdf->_out('endobj'); | ||
1067 | } | ||
1068 | |||
1069 | } | ||
1070 | |||
1071 | |||
1072 | function _putform_bt( $form, $hPt ) { | ||
1073 | $cc = 0; | ||
1074 | $put_xobject = 0; | ||
1075 | $put_js = 0; | ||
1076 | $put_icon = 0; | ||
1077 | $this->mpdf->_newobj(); | ||
1078 | $n = $this->mpdf->n; | ||
1079 | if ($form['subtype'] != 'radio') $this->pdf_acro_array .= $n.' 0 R '; // Add to /Field element | ||
1080 | $this->forms[ $form['n'] ]['obj'] = $n; | ||
1081 | $this->mpdf->_out('<<'); | ||
1082 | $this->mpdf->_out('/Type /Annot '); | ||
1083 | $this->mpdf->_out('/Subtype /Widget'); | ||
1084 | $this->mpdf->_out('/NM '.$this->mpdf->_textstring(sprintf('%04u-%04u', $n, (7000 + $form['n'])))); | ||
1085 | $this->mpdf->_out('/M '.$this->mpdf->_textstring('D:'.date('YmdHis'))); | ||
1086 | $this->mpdf->_out('/Rect [ '.$this->_form_rect($form['x'],$form['y'],$form['w'],$form['h'], $hPt).' ]'); | ||
1087 | $form['noprint'] ? $this->mpdf->_out('/F 0 ') : $this->mpdf->_out('/F 4 '); | ||
1088 | $this->mpdf->_out('/FT /Btn '); | ||
1089 | $this->mpdf->_out('/H /P '); | ||
1090 | if ( $form['subtype'] != 'radio' ) // mPDF 5.3.23 | ||
1091 | $this->mpdf->_out('/T '.$this->mpdf->_textstring($form['T']) ); | ||
1092 | $this->mpdf->_out('/TU '.$this->mpdf->_textstring($form['TU']) ); | ||
1093 | if ( isset( $this->form_button_icon[ $form['T'] ] ) ) { $form['BS_W'] = 0; } | ||
1094 | if ($form['BS_W'] == 0) { $form['BC_C'] = $form['BG_C']; } | ||
1095 | $bstemp = ''; | ||
1096 | $bstemp .= '/W '.$form['BS_W'].' '; | ||
1097 | $bstemp .= '/S /'.$form['BS_S'].' '; | ||
1098 | $temp = ''; | ||
1099 | $temp .= '/BC [ '.$form['BC_C']." ] "; | ||
1100 | $temp .= '/BG [ '.$form['BG_C']." ] "; | ||
1101 | if ( $form['subtype'] == 'checkbox' ) { | ||
1102 | if ($form['disabled']) { | ||
1103 | $radio_color = '0.5 0.5 0.5'; | ||
1104 | $radio_background_color = '0.9 0.9 0.9'; | ||
1105 | } | ||
1106 | else { | ||
1107 | $radio_color = $this->form_radio_color; | ||
1108 | $radio_background_color = $this->form_radio_background_color; | ||
1109 | } | ||
1110 | $temp = ''; | ||
1111 | $temp .= '/BC [ '.$radio_color." ] "; | ||
1112 | $temp .= '/BG [ '.$radio_background_color." ] "; | ||
1113 | $this->mpdf->_out("/BS << /W 1 /S /S >>"); | ||
1114 | $this->mpdf->_out("/MK << $temp >>"); | ||
1115 | $this->mpdf->_out('/Ff '.$this->_setflag($form['FF']) ); | ||
1116 | if ( $form['activ'] ) { | ||
1117 | $this->mpdf->_out('/V /'.$this->mpdf->_escape($form['V']).' '); | ||
1118 | $this->mpdf->_out('/DV /'.$this->mpdf->_escape($form['V']).' '); | ||
1119 | $this->mpdf->_out('/AS /'.$this->mpdf->_escape($form['V']).' '); | ||
1120 | } else { | ||
1121 | $this->mpdf->_out('/AS /Off '); | ||
1122 | } | ||
1123 | if ($this->formUseZapD) { | ||
1124 | $this->mpdf->_out('/DA (/F'.$this->mpdf->fonts['czapfdingbats']['i'].' 0 Tf '.$radio_color.' rg)'); | ||
1125 | $this->mpdf->_out("/AP << /N << /".$this->mpdf->_escape($form['V'])." ".($this->mpdf->n+1)." 0 R /Off /Off >> >>"); | ||
1126 | } | ||
1127 | else { | ||
1128 | $this->mpdf->_out('/DA (/F'.$this->mpdf->fonts[$this->mpdf->CurrentFont['fontkey']]['i'].' 0 Tf '.$radio_color.' rg)'); | ||
1129 | $this->mpdf->_out("/AP << /N << /".$this->mpdf->_escape($form['V'])." ".($this->mpdf->n+1)." 0 R /Off ".($this->mpdf->n+2)." 0 R >> >>"); | ||
1130 | } | ||
1131 | $this->mpdf->_out('/Opt [ '.$this->mpdf->_textstring($form['OPT']).' '.$this->mpdf->_textstring($form['OPT']).' ]'); | ||
1132 | } | ||
1133 | |||
1134 | |||
1135 | if ( $form['subtype'] == 'radio' ) { | ||
1136 | if ($form['disabled'] || $this->form_radio_groups[$form['T']]['disabled']) { | ||
1137 | $radio_color = '0.5 0.5 0.5'; | ||
1138 | $radio_background_color = '0.9 0.9 0.9'; | ||
1139 | } | ||
1140 | else { | ||
1141 | $radio_color = $this->form_radio_color; | ||
1142 | $radio_background_color = $this->form_radio_background_color; | ||
1143 | } | ||
1144 | $this->mpdf->_out('/Parent '.$this->form_radio_groups[$form['T']]['obj_id'].' 0 R '); | ||
1145 | $temp = ''; | ||
1146 | $temp .= '/BC [ '.$radio_color." ] "; | ||
1147 | $temp .= '/BG [ '.$radio_background_color." ] "; | ||
1148 | $this->mpdf->_out("/BS << /W 1 /S /S >>"); | ||
1149 | $this->mpdf->_out('/MK << '.$temp.' >> '); | ||
1150 | $form['FF'][] = 16; // Radiobutton | ||
1151 | $form['FF'][] = 15; // NoToggleOff - must be same as radio button group setting? | ||
1152 | $this->mpdf->_out('/Ff '.$this->_setflag($form['FF']) ); | ||
1153 | if ($this->formUseZapD) | ||
1154 | $this->mpdf->_out('/DA (/F'.$this->mpdf->fonts['czapfdingbats']['i'].' 0 Tf '.$radio_color.' rg)'); | ||
1155 | else | ||
1156 | $this->mpdf->_out('/DA (/F'.$this->mpdf->fonts[$this->mpdf->CurrentFont['fontkey']]['i'].' 0 Tf '.$radio_color.' rg)'); | ||
1157 | $this->mpdf->_out("/AP << /N << /".$this->mpdf->_escape($form['V'])." ".($this->mpdf->n+1)." 0 R /Off ".($this->mpdf->n+2)." 0 R >> >>"); | ||
1158 | if ( $form['activ'] ) { | ||
1159 | $this->mpdf->_out('/V /'.$this->mpdf->_escape($form['V']).' '); | ||
1160 | $this->mpdf->_out('/DV /'.$this->mpdf->_escape($form['V']).' '); | ||
1161 | $this->mpdf->_out('/AS /'.$this->mpdf->_escape($form['V']).' '); | ||
1162 | } | ||
1163 | else { | ||
1164 | $this->mpdf->_out('/AS /Off '); | ||
1165 | } | ||
1166 | $this->mpdf->_out("/AP << /N << /".$this->mpdf->_escape($form['V'])." ".($this->mpdf->n+1)." 0 R /Off ".($this->mpdf->n+2)." 0 R >> >>"); | ||
1167 | // $this->mpdf->_out('/Opt [ '.$this->mpdf->_textstring($form['OPT']).' '.$this->mpdf->_textstring($form['OPT']).' ]'); | ||
1168 | } | ||
1169 | |||
1170 | if ( $form['subtype'] == 'reset' ) { | ||
1171 | $temp .= $form['CA'] ? '/CA '.$this->mpdf->_textstring($form['CA']).' ' : '/CA '.$this->mpdf->_textstring($form['T']).' '; | ||
1172 | $temp .= $form['RC'] ? '/RC '.$this->mpdf->_textstring($form['RC']).' ' : '/RC '.$this->mpdf->_textstring($form['T']).' '; | ||
1173 | $temp .= $form['AC'] ? '/AC '.$this->mpdf->_textstring($form['AC']).' ' : '/AC '.$this->mpdf->_textstring($form['T']).' '; | ||
1174 | $this->mpdf->_out("/BS << $bstemp >>"); | ||
1175 | $this->mpdf->_out('/MK << '.$temp.' >>'); | ||
1176 | $this->mpdf->_out('/DA (/F'.$this->mpdf->fonts[$form['style']['font']]['i'].' '.$form['style']['fontsize'].' Tf '.$form['style']['fontcolor'].')'); | ||
1177 | $this->mpdf->_out('/AA << /D << /S /ResetForm /Flags 1 >> >>'); | ||
1178 | $form['FF'][] = 17; | ||
1179 | $this->mpdf->_out('/Ff '.$this->_setflag($form['FF']) ); | ||
1180 | } | ||
1181 | |||
1182 | |||
1183 | if ( $form['subtype'] == 'submit' ) { | ||
1184 | $temp .= $form['CA'] ? '/CA '.$this->mpdf->_textstring($form['CA']).' ' : '/CA '.$this->mpdf->_textstring($form['T']).' '; | ||
1185 | $temp .= $form['RC'] ? '/RC '.$this->mpdf->_textstring($form['RC']).' ' : '/RC '.$this->mpdf->_textstring($form['T']).' '; | ||
1186 | $temp .= $form['AC'] ? '/AC '.$this->mpdf->_textstring($form['AC']).' ' : '/AC '.$this->mpdf->_textstring($form['T']).' '; | ||
1187 | $this->mpdf->_out("/BS << $bstemp >>"); | ||
1188 | $this->mpdf->_out("/MK << $temp >>"); | ||
1189 | $this->mpdf->_out('/DA (/F'.$this->mpdf->fonts[$form['style']['font']]['i'].' '.$form['style']['fontsize'].' Tf '.$form['style']['fontcolor'].')'); | ||
1190 | // Bit 4 (8) = useGETmethod else use POST | ||
1191 | // Bit 3 (4) = HTML export format (charset chosen by Adobe)--- OR --- | ||
1192 | // Bit 6 (32) = XFDF export format (form of XML in UTF-8) | ||
1193 | if ($form['exporttype'] == 'xfdf') { $flag = 32; } // 'xfdf' or 'html' | ||
1194 | else { | ||
1195 | if ($form['method'] == 'GET') { $flag = 12; } | ||
1196 | else { $flag = 4; } | ||
1197 | } | ||
1198 | // Bit 2 (2) = IncludeNoValueFields | ||
1199 | if ($this->formSubmitNoValueFields) $flag += 2; | ||
1200 | // To submit a value, needs to be in /AP dictionary, AND this object must contain a /Fields entry | ||
1201 | // listing all fields to output | ||
1202 | $this->mpdf->_out('/AA << /D << /S /SubmitForm /F ('.$form['URL'].') /Flags '.$flag.' >> >>'); | ||
1203 | $form['FF'][] = 17; | ||
1204 | $this->mpdf->_out('/Ff '.$this->_setflag($form['FF']) ); | ||
1205 | } | ||
1206 | |||
1207 | if ( $form['subtype'] == 'js_button' ) { | ||
1208 | // Icon / image | ||
1209 | if ( isset( $this->form_button_icon[ $form['T'] ] ) ) { | ||
1210 | $cc++; | ||
1211 | $temp .= '/TP '.$this->form_button_icon[$form['T']]['pos'].' '; | ||
1212 | $temp .= '/I '.($cc + $this->mpdf->n).' 0 R '; // Normal icon | ||
1213 | $temp .= '/RI '.($cc + $this->mpdf->n).' 0 R '; // onMouseOver | ||
1214 | $temp .= '/IX '.($cc + $this->mpdf->n).' 0 R '; // onClick / onMouseDown | ||
1215 | $temp .= '/IF << /SW /A /S /A /A [0.0 0.0] >> '; // Icon fit dictionary | ||
1216 | if ($this->form_button_icon[ $form['T'] ]['Indexed']) { $cc++; } | ||
1217 | $put_icon = 1; | ||
1218 | } | ||
1219 | $temp .= $form['CA'] ? '/CA '.$this->mpdf->_textstring($form['CA']).' ' : '/CA '.$this->mpdf->_textstring($form['T']).' '; | ||
1220 | $temp .= $form['RC'] ? '/RC '.$this->mpdf->_textstring($form['RC']).' ' : '/RC '.$this->mpdf->_textstring($form['T']).' '; | ||
1221 | $temp .= $form['AC'] ? '/AC '.$this->mpdf->_textstring($form['AC']).' ' : '/AC '.$this->mpdf->_textstring($form['T']).' '; | ||
1222 | $this->mpdf->_out("/BS << $bstemp >>"); | ||
1223 | $this->mpdf->_out("/MK << $temp >>"); | ||
1224 | $this->mpdf->_out('/DA (/F'.$this->mpdf->fonts[$form['style']['font']]['i'].' '.$form['style']['fontsize'].' Tf '.$form['style']['fontcolor'].')'); | ||
1225 | $form['FF'][] = 17; | ||
1226 | $this->mpdf->_out('/Ff '.$this->_setflag($form['FF']) ); | ||
1227 | // Javascript | ||
1228 | if ( isset($this->array_form_button_js[$form['T']]) ) { | ||
1229 | $cc++; | ||
1230 | $this->mpdf->_out("/AA << /D ".($cc + $this->mpdf->n)." 0 R >>"); | ||
1231 | $put_js = 1; | ||
1232 | } | ||
1233 | } | ||
1234 | |||
1235 | $this->mpdf->_out('>>'); | ||
1236 | $this->mpdf->_out('endobj'); | ||
1237 | |||
1238 | // additional objects | ||
1239 | // obj icon | ||
1240 | if ( $put_icon == 1 ) { | ||
1241 | $this->_put_button_icon( $this->form_button_icon[ $form['T'] ], $form['w'], $form['h'] ); | ||
1242 | $put_icon = NULL; | ||
1243 | } | ||
1244 | // obj + 1 | ||
1245 | if ( $put_js == 1 ) { | ||
1246 | $this->mpdf->_set_object_javascript( $this->array_form_button_js[$form['T']]['js'] ); | ||
1247 | unset( $this->array_form_button_js[$form['T']] ); | ||
1248 | $put_js = NULL; | ||
1249 | } | ||
1250 | |||
1251 | // RADIO and CHECK BOX appearance streams | ||
1252 | $filter=($this->mpdf->compress) ? '/Filter /FlateDecode ' : ''; | ||
1253 | if ( $form['subtype'] == 'radio' ) { | ||
1254 | // output 2 appearance streams for radio buttons on/off | ||
1255 | if ($this->formUseZapD) { | ||
1256 | $fs = sprintf('%.3F', $form['style']['fontsize']*1.25); | ||
1257 | $fi = 'czapfdingbats'; | ||
1258 | $r_on = 'q '.$radio_color .' rg BT /F'.$this->mpdf->fonts[$fi]['i'].' '.$fs.' Tf 0 0 Td (4) Tj ET Q'; | ||
1259 | $r_off = 'q '.$radio_color .' rg BT /F'.$this->mpdf->fonts[$fi]['i'].' '.$fs.' Tf 0 0 Td (8) Tj ET Q'; | ||
1260 | } | ||
1261 | else { | ||
1262 | $matrix = sprintf('%.3F 0 0 %.3F 0 %.3F', $form['style']['fontsize']*1.33/10, $form['style']['fontsize']*1.25/10, $form['style']['fontsize']); | ||
1263 | $fill = $radio_background_color.' rg 3.778 -7.410 m 2.800 -7.410 1.947 -7.047 1.225 -6.322 c 0.500 -5.600 0.138 -4.747 0.138 -3.769 c 0.138 -2.788 0.500 -1.938 1.225 -1.213 c 1.947 -0.491 2.800 -0.128 3.778 -0.128 c 4.757 -0.128 5.610 -0.491 6.334 -1.213 c 7.056 -1.938 7.419 -2.788 7.419 -3.769 c 7.419 -4.747 7.056 -5.600 6.334 -6.322 c 5.610 -7.047 4.757 -7.410 3.778 -7.410 c h f '; | ||
1264 | $circle = '3.778 -6.963 m 4.631 -6.963 5.375 -6.641 6.013 -6.004 c 6.653 -5.366 6.972 -4.619 6.972 -3.769 c 6.972 -2.916 6.653 -2.172 6.013 -1.532 c 5.375 -0.894 4.631 -0.576 3.778 -0.576 c 2.928 -0.576 2.182 -0.894 1.544 -1.532 c 0.904 -2.172 0.585 -2.916 0.585 -3.769 c 0.585 -4.619 0.904 -5.366 1.544 -6.004 c 2.182 -6.641 2.928 -6.963 3.778 -6.963 c h 3.778 -7.410 m 2.800 -7.410 1.947 -7.047 1.225 -6.322 c 0.500 -5.600 0.138 -4.747 0.138 -3.769 c 0.138 -2.788 0.500 -1.938 1.225 -1.213 c 1.947 -0.491 2.800 -0.128 3.778 -0.128 c 4.757 -0.128 5.610 -0.491 6.334 -1.213 c 7.056 -1.938 7.419 -2.788 7.419 -3.769 c 7.419 -4.747 7.056 -5.600 6.334 -6.322 c 5.610 -7.047 4.757 -7.410 3.778 -7.410 c h f '; | ||
1265 | $r_on = 'q '.$matrix.' cm '.$fill .$radio_color.' rg '.$circle.' '.$radio_color.' rg | ||
1266 | 5.184 -5.110 m 4.800 -5.494 4.354 -5.685 3.841 -5.685 c 3.331 -5.685 2.885 -5.494 2.501 -5.110 c 2.119 -4.725 1.925 -4.279 1.925 -3.769 c 1.925 -3.257 2.119 -2.810 2.501 -2.429 c 2.885 -2.044 3.331 -1.853 3.841 -1.853 c 4.354 -1.853 4.800 -2.044 5.184 -2.429 c 5.566 -2.810 5.760 -3.257 5.760 -3.769 c 5.760 -4.279 5.566 -4.725 5.184 -5.110 c h | ||
1267 | f Q '; | ||
1268 | $r_off = 'q '.$matrix.' cm '.$fill .$radio_color.' rg '.$circle.' Q '; | ||
1269 | } | ||
1270 | |||
1271 | $this->mpdf->_newobj(); | ||
1272 | $p=($this->mpdf->compress) ? gzcompress($r_on) : $r_on; | ||
1273 | $this->mpdf->_out('<<'.$filter.'/Length '.strlen($p).' /Resources 2 0 R>>'); | ||
1274 | $this->mpdf->_putstream($p); | ||
1275 | $this->mpdf->_out('endobj'); | ||
1276 | |||
1277 | $this->mpdf->_newobj(); | ||
1278 | $p=($this->mpdf->compress) ? gzcompress($r_off) : $r_off; | ||
1279 | $this->mpdf->_out('<<'.$filter.'/Length '.strlen($p).' /Resources 2 0 R>>'); | ||
1280 | $this->mpdf->_putstream($p); | ||
1281 | $this->mpdf->_out('endobj'); | ||
1282 | } | ||
1283 | if ( $form['subtype'] == 'checkbox' ) { | ||
1284 | // First output appearance stream for check box on | ||
1285 | if ($this->formUseZapD) { | ||
1286 | $fs = sprintf('%.3F', $form['style']['fontsize']*1.25); | ||
1287 | $fi = 'czapfdingbats'; | ||
1288 | $cb_on = 'q '.$radio_color .' rg BT /F'.$this->mpdf->fonts[$fi]['i'].' '.$fs.' Tf 0 0 Td (4) Tj ET Q'; | ||
1289 | $cb_off = 'q '.$radio_color .' rg BT /F'.$this->mpdf->fonts[$fi]['i'].' '.$fs.' Tf 0 0 Td (8) Tj ET Q'; | ||
1290 | } | ||
1291 | else { | ||
1292 | $matrix = sprintf('%.3F 0 0 %.3F 0 %.3F', $form['style']['fontsize']*1.33/10, $form['style']['fontsize']*1.25/10, $form['style']['fontsize']); | ||
1293 | $fill = $radio_background_color.' rg 7.395 -0.070 m 7.395 -7.344 l 0.121 -7.344 l 0.121 -0.070 l 7.395 -0.070 l h f '; | ||
1294 | $square = '0.508 -6.880 m 6.969 -6.880 l 6.969 -0.534 l 0.508 -0.534 l 0.508 -6.880 l h 7.395 -0.070 m 7.395 -7.344 l 0.121 -7.344 l 0.121 -0.070 l 7.395 -0.070 l h '; | ||
1295 | $cb_on = 'q '.$matrix.' cm '.$fill. $radio_color.' rg '.$square.' f '.$radio_color.' rg | ||
1296 | 6.321 -1.352 m 5.669 -2.075 5.070 -2.801 4.525 -3.532 c 3.979 -4.262 3.508 -4.967 3.112 -5.649 c 3.080 -5.706 3.039 -5.779 2.993 -5.868 c 2.858 -6.118 2.638 -6.243 2.334 -6.243 c 2.194 -6.243 2.100 -6.231 2.052 -6.205 c 2.003 -6.180 1.954 -6.118 1.904 -6.020 c 1.787 -5.788 1.688 -5.523 1.604 -5.226 c 1.521 -4.930 1.480 -4.721 1.480 -4.600 c 1.480 -4.535 1.491 -4.484 1.512 -4.447 c 1.535 -4.410 1.579 -4.367 1.647 -4.319 c 1.733 -4.259 1.828 -4.210 1.935 -4.172 c 2.040 -4.134 2.131 -4.115 2.205 -4.115 c 2.267 -4.115 2.341 -4.232 2.429 -4.469 c 2.437 -4.494 2.444 -4.511 2.448 -4.522 c 2.451 -4.531 2.456 -4.546 2.465 -4.568 c 2.546 -4.795 2.614 -4.910 2.668 -4.910 c 2.714 -4.910 2.898 -4.652 3.219 -4.136 c 3.539 -3.620 3.866 -3.136 4.197 -2.683 c 4.426 -2.367 4.633 -2.103 4.816 -1.889 c 4.998 -1.676 5.131 -1.544 5.211 -1.493 c 5.329 -1.426 5.483 -1.368 5.670 -1.319 c 5.856 -1.271 6.066 -1.238 6.296 -1.217 c 6.321 -1.352 l h f Q '; | ||
1297 | $cb_off = 'q '.$matrix.' cm '.$fill. $radio_color.' rg '.$square.' f Q '; | ||
1298 | |||
1299 | } | ||
1300 | $this->mpdf->_newobj(); | ||
1301 | $p=($this->mpdf->compress) ? gzcompress($cb_on) : $cb_on; | ||
1302 | $this->mpdf->_out('<<'.$filter.'/Length '.strlen($p).' /Resources 2 0 R>>'); | ||
1303 | $this->mpdf->_putstream($p); | ||
1304 | $this->mpdf->_out('endobj'); | ||
1305 | |||
1306 | // output appearance stream for check box off (only if not using ZapfDingbats) | ||
1307 | if (!$this->formUseZapD) { | ||
1308 | $this->mpdf->_newobj(); | ||
1309 | $p=($this->mpdf->compress) ? gzcompress($cb_off) : $cb_off; | ||
1310 | $this->mpdf->_out('<<'.$filter.'/Length '.strlen($p).' /Resources 2 0 R>>'); | ||
1311 | $this->mpdf->_putstream($p); | ||
1312 | $this->mpdf->_out('endobj'); | ||
1313 | } | ||
1314 | |||
1315 | } | ||
1316 | return $n; | ||
1317 | } | ||
1318 | |||
1319 | |||
1320 | function _putform_ch( $form, $hPt ) { | ||
1321 | $put_js = 0; | ||
1322 | $this->mpdf->_newobj(); | ||
1323 | $n = $this->mpdf->n; | ||
1324 | $this->pdf_acro_array .= $n.' 0 R '; | ||
1325 | $this->forms[ $form['n'] ]['obj'] = $n; | ||
1326 | |||
1327 | $this->mpdf->_out('<<'); | ||
1328 | $this->mpdf->_out('/Type /Annot '); | ||
1329 | $this->mpdf->_out('/Subtype /Widget'); | ||
1330 | $this->mpdf->_out('/Rect [ '.$this->_form_rect($form['x'],$form['y'],$form['w'],$form['h'], $hPt).' ]'); | ||
1331 | $this->mpdf->_out('/F 4'); | ||
1332 | $this->mpdf->_out('/FT /Ch'); | ||
1333 | if ($form['Q']) $this->mpdf->_out('/Q '.$form['Q'].''); | ||
1334 | $temp = ''; | ||
1335 | $temp .= '/W '.$form['BS_W'].' '; | ||
1336 | $temp .= '/S /'.$form['BS_S'].' '; | ||
1337 | $this->mpdf->_out("/BS << $temp >>"); | ||
1338 | |||
1339 | $temp = ''; | ||
1340 | $temp .= '/BC [ '.$form['BC_C']." ] "; | ||
1341 | $temp .= '/BG [ '.$form['BG_C']." ] "; | ||
1342 | $this->mpdf->_out('/MK << '.$temp.' >>'); | ||
1343 | |||
1344 | $this->mpdf->_out('/NM '.$this->mpdf->_textstring(sprintf('%04u-%04u', $n, (6000 + $form['n'])))); | ||
1345 | $this->mpdf->_out('/M '.$this->mpdf->_textstring('D:'.date('YmdHis'))); | ||
1346 | |||
1347 | $this->mpdf->_out('/T '.$this->mpdf->_textstring($form['T']) ); | ||
1348 | $this->mpdf->_out('/DA (/F'.$this->mpdf->fonts[$form['style']['font']]['i'].' '.$form['style']['fontsize'].' Tf '.$form['style']['fontcolor'].')'); | ||
1349 | |||
1350 | $opt = ''; | ||
1351 | for( $i = 0; $i < count($form['OPT']['VAL']) ; $i++ ) { | ||
1352 | $opt .= '[ '.$this->mpdf->_textstring($form['OPT']['VAL'][$i]).' '.$this->mpdf->_textstring($form['OPT']['OPT'][$i]).' ] '; | ||
1353 | } | ||
1354 | $this->mpdf->_out('/Opt [ '.$opt.']'); | ||
1355 | |||
1356 | // selected | ||
1357 | $selectItem = false; | ||
1358 | $selectIndex = false; | ||
1359 | foreach ( $form['OPT']['SEL'] as $selectKey => $selectVal ) { | ||
1360 | $selectName = $this->mpdf->_textstring($form['OPT']['VAL'][$selectVal]); | ||
1361 | $selectItem .= ' '.$selectName.' '; | ||
1362 | $selectIndex .= ' '.$selectVal.' '; | ||
1363 | } | ||
1364 | if ( $selectItem ) { | ||
1365 | if (count($form['OPT']['SEL']) < 2) { | ||
1366 | $this->mpdf->_out('/V '.$selectItem.' '); | ||
1367 | $this->mpdf->_out('/DV '.$selectItem.' '); | ||
1368 | } | ||
1369 | else { | ||
1370 | $this->mpdf->_out('/V ['.$selectItem.'] '); | ||
1371 | $this->mpdf->_out('/DV ['.$selectItem.'] '); | ||
1372 | } | ||
1373 | $this->mpdf->_out('/I ['.$selectIndex.'] '); | ||
1374 | } | ||
1375 | |||
1376 | if ( is_array($form['FF']) && count($form['FF'])>0 ) { | ||
1377 | $this->mpdf->_out('/Ff '.$this->_setflag($form['FF']).' '); | ||
1378 | } | ||
1379 | // Javascript | ||
1380 | if ( isset($this->array_form_choice_js[$form['T']]) ) { | ||
1381 | $this->mpdf->_out("/AA << /V ".($this->mpdf->n+1)." 0 R >>"); | ||
1382 | $put_js = 1; | ||
1383 | } | ||
1384 | |||
1385 | $this->mpdf->_out('>>'); | ||
1386 | $this->mpdf->_out('endobj'); | ||
1387 | // obj + 1 | ||
1388 | if ( $put_js == 1 ) { | ||
1389 | $this->mpdf->_set_object_javascript( $this->array_form_choice_js[$form['T']]['js'] ); | ||
1390 | unset( $this->array_form_choice_js[$form['T']] ); | ||
1391 | $put_js = NULL; | ||
1392 | } | ||
1393 | |||
1394 | return $n; | ||
1395 | } | ||
1396 | |||
1397 | |||
1398 | function _putform_tx( $form, $hPt ) { | ||
1399 | $put_js = 0; | ||
1400 | $this->mpdf->_newobj(); | ||
1401 | $n = $this->mpdf->n; | ||
1402 | $this->pdf_acro_array .= $n.' 0 R '; | ||
1403 | $this->forms[ $form['n'] ]['obj'] = $n; | ||
1404 | |||
1405 | $this->mpdf->_out('<<'); | ||
1406 | $this->mpdf->_out('/Type /Annot '); | ||
1407 | $this->mpdf->_out('/Subtype /Widget '); | ||
1408 | |||
1409 | $this->mpdf->_out('/Rect [ '.$this->_form_rect($form['x'],$form['y'],$form['w'],$form['h'], $hPt).' ] '); | ||
1410 | $form['hidden'] ? $this->mpdf->_out('/F 2 ') : $this->mpdf->_out('/F 4 '); | ||
1411 | $this->mpdf->_out('/FT /Tx '); | ||
1412 | |||
1413 | $this->mpdf->_out('/H /N '); | ||
1414 | $this->mpdf->_out('/R 0 '); | ||
1415 | |||
1416 | if ( is_array($form['FF']) && count($form['FF'])>0 ) { | ||
1417 | $this->mpdf->_out('/Ff '.$this->_setflag($form['FF']).' '); | ||
1418 | } | ||
1419 | if ( isset($form['maxlen']) && $form['maxlen']>0 ) { | ||
1420 | $this->mpdf->_out('/MaxLen '.$form['maxlen']); | ||
1421 | } | ||
1422 | |||
1423 | $temp = ''; | ||
1424 | $temp .= '/W '.$form['BS_W'].' '; | ||
1425 | $temp .= '/S /'.$form['BS_S'].' '; | ||
1426 | $this->mpdf->_out("/BS << $temp >>"); | ||
1427 | |||
1428 | $temp = ''; | ||
1429 | $temp .= '/BC [ '.$form['BC_C']." ] "; | ||
1430 | $temp .= '/BG [ '.$form['BG_C']." ] "; | ||
1431 | $this->mpdf->_out('/MK <<'.$temp.' >>'); | ||
1432 | |||
1433 | $this->mpdf->_out('/T '.$this->mpdf->_textstring($form['T']) ); | ||
1434 | $this->mpdf->_out('/TU '.$this->mpdf->_textstring($form['TU']) ); | ||
1435 | if ($form['V'] || $form['V']==='0') | ||
1436 | $this->mpdf->_out('/V '.$this->mpdf->_textstring($form['V']) ); | ||
1437 | $this->mpdf->_out('/DV '.$this->mpdf->_textstring($form['DV']) ); | ||
1438 | $this->mpdf->_out('/DA (/F'.$this->mpdf->fonts[$form['style']['font']]['i'].' '.$form['style']['fontsize'].' Tf '.$form['style']['fontcolor'].')'); | ||
1439 | if ( $form['Q'] ) $this->mpdf->_out('/Q '.$form['Q'].''); | ||
1440 | |||
1441 | $this->mpdf->_out('/NM '.$this->mpdf->_textstring(sprintf('%04u-%04u', $n, (5000 + $form['n'])))); | ||
1442 | $this->mpdf->_out('/M '.$this->mpdf->_textstring('D:'.date('YmdHis'))); | ||
1443 | |||
1444 | |||
1445 | if ( isset($this->array_form_text_js[$form['T']]) ) { | ||
1446 | $put_js = 1; | ||
1447 | $cc = 0; | ||
1448 | $js_str = ''; | ||
1449 | |||
1450 | if ( isset($this->array_form_text_js[$form['T']]['F']) ) { | ||
1451 | $cc++; | ||
1452 | $js_str .= '/F '.($cc + $this->mpdf->n).' 0 R '; | ||
1453 | } | ||
1454 | if ( isset($this->array_form_text_js[$form['T']]['K']) ) { | ||
1455 | $cc++; | ||
1456 | $js_str .= '/K '.($cc + $this->mpdf->n).' 0 R '; | ||
1457 | } | ||
1458 | if ( isset($this->array_form_text_js[$form['T']]['V']) ) { | ||
1459 | $cc++; | ||
1460 | $js_str .= '/V '.($cc + $this->mpdf->n).' 0 R '; | ||
1461 | } | ||
1462 | if ( isset($this->array_form_text_js[$form['T']]['C']) ) { | ||
1463 | $cc++; | ||
1464 | $js_str .= '/C '.($cc + $this->mpdf->n).' 0 R '; | ||
1465 | $this->pdf_array_co .= $this->mpdf->n.' 0 R '; | ||
1466 | } | ||
1467 | $this->mpdf->_out('/AA << '.$js_str.' >>'); | ||
1468 | } | ||
1469 | |||
1470 | $this->mpdf->_out('>>'); | ||
1471 | $this->mpdf->_out('endobj'); | ||
1472 | |||
1473 | if ( $put_js == 1 ) { | ||
1474 | if ( isset($this->array_form_text_js[$form['T']]['F']) ) { | ||
1475 | $this->mpdf->_set_object_javascript( $this->array_form_text_js[$form['T']]['F']['js'] ); | ||
1476 | unset( $this->array_form_text_js[$form['T']]['F'] ); | ||
1477 | } | ||
1478 | if ( isset($this->array_form_text_js[$form['T']]['K']) ) { | ||
1479 | $this->mpdf->_set_object_javascript( $this->array_form_text_js[$form['T']]['K']['js'] ); | ||
1480 | unset( $this->array_form_text_js[$form['T']]['K'] ); | ||
1481 | } | ||
1482 | if ( isset($this->array_form_text_js[$form['T']]['V']) ) { | ||
1483 | $this->mpdf->_set_object_javascript( $this->array_form_text_js[$form['T']]['V']['js'] ); | ||
1484 | unset( $this->array_form_text_js[$form['T']]['V'] ); | ||
1485 | } | ||
1486 | if ( isset($this->array_form_text_js[$form['T']]['C']) ) { | ||
1487 | $this->mpdf->_set_object_javascript( $this->array_form_text_js[$form['T']]['C']['js'] ); | ||
1488 | unset( $this->array_form_text_js[$form['T']]['C'] ); | ||
1489 | } | ||
1490 | } | ||
1491 | return $n; | ||
1492 | } | ||
1493 | |||
1494 | |||
1495 | |||
1496 | } | ||
1497 | |||
1498 | ?> \ No newline at end of file | ||
diff --git a/inc/3rdparty/libraries/mpdf/classes/gif.php b/inc/3rdparty/libraries/mpdf/classes/gif.php new file mode 100644 index 00000000..263513e2 --- /dev/null +++ b/inc/3rdparty/libraries/mpdf/classes/gif.php | |||
@@ -0,0 +1,700 @@ | |||
1 | <?php | ||
2 | /////////////////////////////////////////////////////////////////////////////////////////////////// | ||
3 | // 2009-12-22 Adapted for mPDF 4.2 | ||
4 | /////////////////////////////////////////////////////////////////////////////////////////////////// | ||
5 | // GIF Util - (C) 2003 Yamasoft (S/C) | ||
6 | // http://www.yamasoft.com | ||
7 | // All Rights Reserved | ||
8 | // This file can be freely copied, distributed, modified, updated by anyone under the only | ||
9 | // condition to leave the original address (Yamasoft, http://www.yamasoft.com) and this header. | ||
10 | /////////////////////////////////////////////////////////////////////////////////////////////////// | ||
11 | /////////////////////////////////////////////////////////////////////////////////////////////////// | ||
12 | // 2009-12-22 Adapted INB | ||
13 | // Functions calling functionname($x, $len = 0) were not working on PHP5.1.5 as pass by reference | ||
14 | // All edited to $len = 0; then call function. | ||
15 | /////////////////////////////////////////////////////////////////////////////////////////////////// | ||
16 | |||
17 | |||
18 | /////////////////////////////////////////////////////////////////////////////////////////////////// | ||
19 | |||
20 | class CGIFLZW | ||
21 | { | ||
22 | var $MAX_LZW_BITS; | ||
23 | var $Fresh, $CodeSize, $SetCodeSize, $MaxCode, $MaxCodeSize, $FirstCode, $OldCode; | ||
24 | var $ClearCode, $EndCode, $Next, $Vals, $Stack, $sp, $Buf, $CurBit, $LastBit, $Done, $LastByte; | ||
25 | |||
26 | /////////////////////////////////////////////////////////////////////////// | ||
27 | |||
28 | // CONSTRUCTOR | ||
29 | function CGIFLZW() | ||
30 | { | ||
31 | $this->MAX_LZW_BITS = 12; | ||
32 | unSet($this->Next); | ||
33 | unSet($this->Vals); | ||
34 | unSet($this->Stack); | ||
35 | unSet($this->Buf); | ||
36 | |||
37 | $this->Next = range(0, (1 << $this->MAX_LZW_BITS) - 1); | ||
38 | $this->Vals = range(0, (1 << $this->MAX_LZW_BITS) - 1); | ||
39 | $this->Stack = range(0, (1 << ($this->MAX_LZW_BITS + 1)) - 1); | ||
40 | $this->Buf = range(0, 279); | ||
41 | } | ||
42 | |||
43 | /////////////////////////////////////////////////////////////////////////// | ||
44 | |||
45 | function deCompress($data, &$datLen) | ||
46 | { | ||
47 | $stLen = strlen($data); | ||
48 | $datLen = 0; | ||
49 | $ret = ""; | ||
50 | $dp = 0; // data pointer | ||
51 | |||
52 | // INITIALIZATION | ||
53 | $this->LZWCommandInit($data, $dp); | ||
54 | |||
55 | while(($iIndex = $this->LZWCommand($data, $dp)) >= 0) { | ||
56 | $ret .= chr($iIndex); | ||
57 | } | ||
58 | |||
59 | $datLen = $dp; | ||
60 | |||
61 | if($iIndex != -2) { | ||
62 | return false; | ||
63 | } | ||
64 | |||
65 | return $ret; | ||
66 | } | ||
67 | |||
68 | /////////////////////////////////////////////////////////////////////////// | ||
69 | function LZWCommandInit(&$data, &$dp) | ||
70 | { | ||
71 | $this->SetCodeSize = ord($data[0]); | ||
72 | $dp += 1; | ||
73 | |||
74 | $this->CodeSize = $this->SetCodeSize + 1; | ||
75 | $this->ClearCode = 1 << $this->SetCodeSize; | ||
76 | $this->EndCode = $this->ClearCode + 1; | ||
77 | $this->MaxCode = $this->ClearCode + 2; | ||
78 | $this->MaxCodeSize = $this->ClearCode << 1; | ||
79 | |||
80 | $this->GetCodeInit($data, $dp); | ||
81 | |||
82 | $this->Fresh = 1; | ||
83 | for($i = 0; $i < $this->ClearCode; $i++) { | ||
84 | $this->Next[$i] = 0; | ||
85 | $this->Vals[$i] = $i; | ||
86 | } | ||
87 | |||
88 | for(; $i < (1 << $this->MAX_LZW_BITS); $i++) { | ||
89 | $this->Next[$i] = 0; | ||
90 | $this->Vals[$i] = 0; | ||
91 | } | ||
92 | |||
93 | $this->sp = 0; | ||
94 | return 1; | ||
95 | } | ||
96 | |||
97 | function LZWCommand(&$data, &$dp) | ||
98 | { | ||
99 | if($this->Fresh) { | ||
100 | $this->Fresh = 0; | ||
101 | do { | ||
102 | $this->FirstCode = $this->GetCode($data, $dp); | ||
103 | $this->OldCode = $this->FirstCode; | ||
104 | } | ||
105 | while($this->FirstCode == $this->ClearCode); | ||
106 | |||
107 | return $this->FirstCode; | ||
108 | } | ||
109 | |||
110 | if($this->sp > 0) { | ||
111 | $this->sp--; | ||
112 | return $this->Stack[$this->sp]; | ||
113 | } | ||
114 | |||
115 | while(($Code = $this->GetCode($data, $dp)) >= 0) { | ||
116 | if($Code == $this->ClearCode) { | ||
117 | for($i = 0; $i < $this->ClearCode; $i++) { | ||
118 | $this->Next[$i] = 0; | ||
119 | $this->Vals[$i] = $i; | ||
120 | } | ||
121 | |||
122 | for(; $i < (1 << $this->MAX_LZW_BITS); $i++) { | ||
123 | $this->Next[$i] = 0; | ||
124 | $this->Vals[$i] = 0; | ||
125 | } | ||
126 | |||
127 | $this->CodeSize = $this->SetCodeSize + 1; | ||
128 | $this->MaxCodeSize = $this->ClearCode << 1; | ||
129 | $this->MaxCode = $this->ClearCode + 2; | ||
130 | $this->sp = 0; | ||
131 | $this->FirstCode = $this->GetCode($data, $dp); | ||
132 | $this->OldCode = $this->FirstCode; | ||
133 | |||
134 | return $this->FirstCode; | ||
135 | } | ||
136 | |||
137 | if($Code == $this->EndCode) { | ||
138 | return -2; | ||
139 | } | ||
140 | |||
141 | $InCode = $Code; | ||
142 | if($Code >= $this->MaxCode) { | ||
143 | $this->Stack[$this->sp++] = $this->FirstCode; | ||
144 | $Code = $this->OldCode; | ||
145 | } | ||
146 | |||
147 | while($Code >= $this->ClearCode) { | ||
148 | $this->Stack[$this->sp++] = $this->Vals[$Code]; | ||
149 | |||
150 | if($Code == $this->Next[$Code]) // Circular table entry, big GIF Error! | ||
151 | return -1; | ||
152 | |||
153 | $Code = $this->Next[$Code]; | ||
154 | } | ||
155 | |||
156 | $this->FirstCode = $this->Vals[$Code]; | ||
157 | $this->Stack[$this->sp++] = $this->FirstCode; | ||
158 | |||
159 | if(($Code = $this->MaxCode) < (1 << $this->MAX_LZW_BITS)) { | ||
160 | $this->Next[$Code] = $this->OldCode; | ||
161 | $this->Vals[$Code] = $this->FirstCode; | ||
162 | $this->MaxCode++; | ||
163 | |||
164 | if(($this->MaxCode >= $this->MaxCodeSize) && ($this->MaxCodeSize < (1 << $this->MAX_LZW_BITS))) { | ||
165 | $this->MaxCodeSize *= 2; | ||
166 | $this->CodeSize++; | ||
167 | } | ||
168 | } | ||
169 | |||
170 | $this->OldCode = $InCode; | ||
171 | if($this->sp > 0) { | ||
172 | $this->sp--; | ||
173 | return $this->Stack[$this->sp]; | ||
174 | } | ||
175 | } | ||
176 | |||
177 | return $Code; | ||
178 | } | ||
179 | |||
180 | /////////////////////////////////////////////////////////////////////////// | ||
181 | |||
182 | function GetCodeInit(&$data, &$dp) | ||
183 | { | ||
184 | $this->CurBit = 0; | ||
185 | $this->LastBit = 0; | ||
186 | $this->Done = 0; | ||
187 | $this->LastByte = 2; | ||
188 | return 1; | ||
189 | } | ||
190 | |||
191 | function GetCode(&$data, &$dp) | ||
192 | { | ||
193 | if(($this->CurBit + $this->CodeSize) >= $this->LastBit) { | ||
194 | if($this->Done) { | ||
195 | if($this->CurBit >= $this->LastBit) { | ||
196 | // Ran off the end of my bits | ||
197 | return 0; | ||
198 | } | ||
199 | return -1; | ||
200 | } | ||
201 | |||
202 | $this->Buf[0] = $this->Buf[$this->LastByte - 2]; | ||
203 | $this->Buf[1] = $this->Buf[$this->LastByte - 1]; | ||
204 | |||
205 | $Count = ord($data[$dp]); | ||
206 | $dp += 1; | ||
207 | |||
208 | if($Count) { | ||
209 | for($i = 0; $i < $Count; $i++) { | ||
210 | $this->Buf[2 + $i] = ord($data[$dp+$i]); | ||
211 | } | ||
212 | $dp += $Count; | ||
213 | } | ||
214 | else { | ||
215 | $this->Done = 1; | ||
216 | } | ||
217 | |||
218 | $this->LastByte = 2 + $Count; | ||
219 | $this->CurBit = ($this->CurBit - $this->LastBit) + 16; | ||
220 | $this->LastBit = (2 + $Count) << 3; | ||
221 | } | ||
222 | |||
223 | $iRet = 0; | ||
224 | for($i = $this->CurBit, $j = 0; $j < $this->CodeSize; $i++, $j++) { | ||
225 | $iRet |= (($this->Buf[intval($i / 8)] & (1 << ($i % 8))) != 0) << $j; | ||
226 | } | ||
227 | |||
228 | $this->CurBit += $this->CodeSize; | ||
229 | return $iRet; | ||
230 | } | ||
231 | } | ||
232 | |||
233 | /////////////////////////////////////////////////////////////////////////////////////////////////// | ||
234 | |||
235 | class CGIFCOLORTABLE | ||
236 | { | ||
237 | var $m_nColors; | ||
238 | var $m_arColors; | ||
239 | |||
240 | /////////////////////////////////////////////////////////////////////////// | ||
241 | |||
242 | // CONSTRUCTOR | ||
243 | function CGIFCOLORTABLE() | ||
244 | { | ||
245 | unSet($this->m_nColors); | ||
246 | unSet($this->m_arColors); | ||
247 | } | ||
248 | |||
249 | /////////////////////////////////////////////////////////////////////////// | ||
250 | |||
251 | function load($lpData, $num) | ||
252 | { | ||
253 | $this->m_nColors = 0; | ||
254 | $this->m_arColors = array(); | ||
255 | |||
256 | for($i = 0; $i < $num; $i++) { | ||
257 | $rgb = substr($lpData, $i * 3, 3); | ||
258 | if(strlen($rgb) < 3) { | ||
259 | return false; | ||
260 | } | ||
261 | |||
262 | $this->m_arColors[] = (ord($rgb[2]) << 16) + (ord($rgb[1]) << 8) + ord($rgb[0]); | ||
263 | $this->m_nColors++; | ||
264 | } | ||
265 | |||
266 | return true; | ||
267 | } | ||
268 | |||
269 | /////////////////////////////////////////////////////////////////////////// | ||
270 | |||
271 | function toString() | ||
272 | { | ||
273 | $ret = ""; | ||
274 | |||
275 | for($i = 0; $i < $this->m_nColors; $i++) { | ||
276 | $ret .= | ||
277 | chr(($this->m_arColors[$i] & 0x000000FF)) . // R | ||
278 | chr(($this->m_arColors[$i] & 0x0000FF00) >> 8) . // G | ||
279 | chr(($this->m_arColors[$i] & 0x00FF0000) >> 16); // B | ||
280 | } | ||
281 | |||
282 | return $ret; | ||
283 | } | ||
284 | |||
285 | |||
286 | /////////////////////////////////////////////////////////////////////////// | ||
287 | |||
288 | function colorIndex($rgb) | ||
289 | { | ||
290 | $rgb = intval($rgb) & 0xFFFFFF; | ||
291 | $r1 = ($rgb & 0x0000FF); | ||
292 | $g1 = ($rgb & 0x00FF00) >> 8; | ||
293 | $b1 = ($rgb & 0xFF0000) >> 16; | ||
294 | $idx = -1; | ||
295 | |||
296 | for($i = 0; $i < $this->m_nColors; $i++) { | ||
297 | $r2 = ($this->m_arColors[$i] & 0x000000FF); | ||
298 | $g2 = ($this->m_arColors[$i] & 0x0000FF00) >> 8; | ||
299 | $b2 = ($this->m_arColors[$i] & 0x00FF0000) >> 16; | ||
300 | $d = abs($r2 - $r1) + abs($g2 - $g1) + abs($b2 - $b1); | ||
301 | |||
302 | if(($idx == -1) || ($d < $dif)) { | ||
303 | $idx = $i; | ||
304 | $dif = $d; | ||
305 | } | ||
306 | } | ||
307 | |||
308 | return $idx; | ||
309 | } | ||
310 | } | ||
311 | |||
312 | /////////////////////////////////////////////////////////////////////////////////////////////////// | ||
313 | |||
314 | class CGIFFILEHEADER | ||
315 | { | ||
316 | var $m_lpVer; | ||
317 | var $m_nWidth; | ||
318 | var $m_nHeight; | ||
319 | var $m_bGlobalClr; | ||
320 | var $m_nColorRes; | ||
321 | var $m_bSorted; | ||
322 | var $m_nTableSize; | ||
323 | var $m_nBgColor; | ||
324 | var $m_nPixelRatio; | ||
325 | var $m_colorTable; | ||
326 | |||
327 | /////////////////////////////////////////////////////////////////////////// | ||
328 | |||
329 | // CONSTRUCTOR | ||
330 | function CGIFFILEHEADER() | ||
331 | { | ||
332 | unSet($this->m_lpVer); | ||
333 | unSet($this->m_nWidth); | ||
334 | unSet($this->m_nHeight); | ||
335 | unSet($this->m_bGlobalClr); | ||
336 | unSet($this->m_nColorRes); | ||
337 | unSet($this->m_bSorted); | ||
338 | unSet($this->m_nTableSize); | ||
339 | unSet($this->m_nBgColor); | ||
340 | unSet($this->m_nPixelRatio); | ||
341 | unSet($this->m_colorTable); | ||
342 | } | ||
343 | |||
344 | /////////////////////////////////////////////////////////////////////////// | ||
345 | |||
346 | function load($lpData, &$hdrLen) | ||
347 | { | ||
348 | $hdrLen = 0; | ||
349 | |||
350 | $this->m_lpVer = substr($lpData, 0, 6); | ||
351 | if(($this->m_lpVer <> "GIF87a") && ($this->m_lpVer <> "GIF89a")) { | ||
352 | return false; | ||
353 | } | ||
354 | |||
355 | $this->m_nWidth = $this->w2i(substr($lpData, 6, 2)); | ||
356 | $this->m_nHeight = $this->w2i(substr($lpData, 8, 2)); | ||
357 | if(!$this->m_nWidth || !$this->m_nHeight) { | ||
358 | return false; | ||
359 | } | ||
360 | |||
361 | $b = ord(substr($lpData, 10, 1)); | ||
362 | $this->m_bGlobalClr = ($b & 0x80) ? true : false; | ||
363 | $this->m_nColorRes = ($b & 0x70) >> 4; | ||
364 | $this->m_bSorted = ($b & 0x08) ? true : false; | ||
365 | $this->m_nTableSize = 2 << ($b & 0x07); | ||
366 | $this->m_nBgColor = ord(substr($lpData, 11, 1)); | ||
367 | $this->m_nPixelRatio = ord(substr($lpData, 12, 1)); | ||
368 | $hdrLen = 13; | ||
369 | |||
370 | if($this->m_bGlobalClr) { | ||
371 | $this->m_colorTable = new CGIFCOLORTABLE(); | ||
372 | if(!$this->m_colorTable->load(substr($lpData, $hdrLen), $this->m_nTableSize)) { | ||
373 | return false; | ||
374 | } | ||
375 | $hdrLen += 3 * $this->m_nTableSize; | ||
376 | } | ||
377 | |||
378 | return true; | ||
379 | } | ||
380 | |||
381 | /////////////////////////////////////////////////////////////////////////// | ||
382 | |||
383 | function w2i($str) | ||
384 | { | ||
385 | return ord(substr($str, 0, 1)) + (ord(substr($str, 1, 1)) << 8); | ||
386 | } | ||
387 | } | ||
388 | |||
389 | /////////////////////////////////////////////////////////////////////////////////////////////////// | ||
390 | |||
391 | class CGIFIMAGEHEADER | ||
392 | { | ||
393 | var $m_nLeft; | ||
394 | var $m_nTop; | ||
395 | var $m_nWidth; | ||
396 | var $m_nHeight; | ||
397 | var $m_bLocalClr; | ||
398 | var $m_bInterlace; | ||
399 | var $m_bSorted; | ||
400 | var $m_nTableSize; | ||
401 | var $m_colorTable; | ||
402 | |||
403 | /////////////////////////////////////////////////////////////////////////// | ||
404 | |||
405 | // CONSTRUCTOR | ||
406 | function CGIFIMAGEHEADER() | ||
407 | { | ||
408 | unSet($this->m_nLeft); | ||
409 | unSet($this->m_nTop); | ||
410 | unSet($this->m_nWidth); | ||
411 | unSet($this->m_nHeight); | ||
412 | unSet($this->m_bLocalClr); | ||
413 | unSet($this->m_bInterlace); | ||
414 | unSet($this->m_bSorted); | ||
415 | unSet($this->m_nTableSize); | ||
416 | unSet($this->m_colorTable); | ||
417 | } | ||
418 | |||
419 | /////////////////////////////////////////////////////////////////////////// | ||
420 | |||
421 | function load($lpData, &$hdrLen) | ||
422 | { | ||
423 | $hdrLen = 0; | ||
424 | |||
425 | $this->m_nLeft = $this->w2i(substr($lpData, 0, 2)); | ||
426 | $this->m_nTop = $this->w2i(substr($lpData, 2, 2)); | ||
427 | $this->m_nWidth = $this->w2i(substr($lpData, 4, 2)); | ||
428 | $this->m_nHeight = $this->w2i(substr($lpData, 6, 2)); | ||
429 | |||
430 | if(!$this->m_nWidth || !$this->m_nHeight) { | ||
431 | return false; | ||
432 | } | ||
433 | |||
434 | $b = ord($lpData{8}); | ||
435 | $this->m_bLocalClr = ($b & 0x80) ? true : false; | ||
436 | $this->m_bInterlace = ($b & 0x40) ? true : false; | ||
437 | $this->m_bSorted = ($b & 0x20) ? true : false; | ||
438 | $this->m_nTableSize = 2 << ($b & 0x07); | ||
439 | $hdrLen = 9; | ||
440 | |||
441 | if($this->m_bLocalClr) { | ||
442 | $this->m_colorTable = new CGIFCOLORTABLE(); | ||
443 | if(!$this->m_colorTable->load(substr($lpData, $hdrLen), $this->m_nTableSize)) { | ||
444 | return false; | ||
445 | } | ||
446 | $hdrLen += 3 * $this->m_nTableSize; | ||
447 | } | ||
448 | |||
449 | return true; | ||
450 | } | ||
451 | |||
452 | /////////////////////////////////////////////////////////////////////////// | ||
453 | |||
454 | function w2i($str) | ||
455 | { | ||
456 | return ord(substr($str, 0, 1)) + (ord(substr($str, 1, 1)) << 8); | ||
457 | } | ||
458 | } | ||
459 | |||
460 | /////////////////////////////////////////////////////////////////////////////////////////////////// | ||
461 | |||
462 | class CGIFIMAGE | ||
463 | { | ||
464 | var $m_disp; | ||
465 | var $m_bUser; | ||
466 | var $m_bTrans; | ||
467 | var $m_nDelay; | ||
468 | var $m_nTrans; | ||
469 | var $m_lpComm; | ||
470 | var $m_gih; | ||
471 | var $m_data; | ||
472 | var $m_lzw; | ||
473 | |||
474 | /////////////////////////////////////////////////////////////////////////// | ||
475 | |||
476 | function CGIFIMAGE() | ||
477 | { | ||
478 | unSet($this->m_disp); | ||
479 | unSet($this->m_bUser); | ||
480 | unSet($this->m_bTrans); | ||
481 | unSet($this->m_nDelay); | ||
482 | unSet($this->m_nTrans); | ||
483 | unSet($this->m_lpComm); | ||
484 | unSet($this->m_data); | ||
485 | $this->m_gih = new CGIFIMAGEHEADER(); | ||
486 | $this->m_lzw = new CGIFLZW(); | ||
487 | } | ||
488 | |||
489 | /////////////////////////////////////////////////////////////////////////// | ||
490 | |||
491 | function load($data, &$datLen) | ||
492 | { | ||
493 | $datLen = 0; | ||
494 | |||
495 | while(true) { | ||
496 | $b = ord($data[0]); | ||
497 | $data = substr($data, 1); | ||
498 | $datLen++; | ||
499 | |||
500 | switch($b) { | ||
501 | case 0x21: // Extension | ||
502 | $len = 0; | ||
503 | if(!$this->skipExt($data, $len)) { | ||
504 | return false; | ||
505 | } | ||
506 | $datLen += $len; | ||
507 | break; | ||
508 | |||
509 | case 0x2C: // Image | ||
510 | // LOAD HEADER & COLOR TABLE | ||
511 | $len = 0; | ||
512 | if(!$this->m_gih->load($data, $len)) { | ||
513 | return false; | ||
514 | } | ||
515 | $data = substr($data, $len); | ||
516 | $datLen += $len; | ||
517 | |||
518 | // ALLOC BUFFER | ||
519 | $len = 0; | ||
520 | |||
521 | if(!($this->m_data = $this->m_lzw->deCompress($data, $len))) { | ||
522 | return false; | ||
523 | } | ||
524 | |||
525 | $data = substr($data, $len); | ||
526 | $datLen += $len; | ||
527 | |||
528 | if($this->m_gih->m_bInterlace) { | ||
529 | $this->deInterlace(); | ||
530 | } | ||
531 | |||
532 | return true; | ||
533 | |||
534 | case 0x3B: // EOF | ||
535 | default: | ||
536 | return false; | ||
537 | } | ||
538 | } | ||
539 | return false; | ||
540 | } | ||
541 | |||
542 | /////////////////////////////////////////////////////////////////////////// | ||
543 | |||
544 | function skipExt(&$data, &$extLen) | ||
545 | { | ||
546 | $extLen = 0; | ||
547 | |||
548 | $b = ord($data[0]); | ||
549 | $data = substr($data, 1); | ||
550 | $extLen++; | ||
551 | |||
552 | switch($b) { | ||
553 | case 0xF9: // Graphic Control | ||
554 | $b = ord($data[1]); | ||
555 | $this->m_disp = ($b & 0x1C) >> 2; | ||
556 | $this->m_bUser = ($b & 0x02) ? true : false; | ||
557 | $this->m_bTrans = ($b & 0x01) ? true : false; | ||
558 | $this->m_nDelay = $this->w2i(substr($data, 2, 2)); | ||
559 | $this->m_nTrans = ord($data[4]); | ||
560 | break; | ||
561 | |||
562 | case 0xFE: // Comment | ||
563 | $this->m_lpComm = substr($data, 1, ord($data[0])); | ||
564 | break; | ||
565 | |||
566 | case 0x01: // Plain text | ||
567 | break; | ||
568 | |||
569 | case 0xFF: // Application | ||
570 | break; | ||
571 | } | ||
572 | |||
573 | // SKIP DEFAULT AS DEFS MAY CHANGE | ||
574 | $b = ord($data[0]); | ||
575 | $data = substr($data, 1); | ||
576 | $extLen++; | ||
577 | while($b > 0) { | ||
578 | $data = substr($data, $b); | ||
579 | $extLen += $b; | ||
580 | $b = ord($data[0]); | ||
581 | $data = substr($data, 1); | ||
582 | $extLen++; | ||
583 | } | ||
584 | return true; | ||
585 | } | ||
586 | |||
587 | /////////////////////////////////////////////////////////////////////////// | ||
588 | |||
589 | function w2i($str) | ||
590 | { | ||
591 | return ord(substr($str, 0, 1)) + (ord(substr($str, 1, 1)) << 8); | ||
592 | } | ||
593 | |||
594 | /////////////////////////////////////////////////////////////////////////// | ||
595 | |||
596 | function deInterlace() | ||
597 | { | ||
598 | $data = $this->m_data; | ||
599 | |||
600 | for($i = 0; $i < 4; $i++) { | ||
601 | switch($i) { | ||
602 | case 0: | ||
603 | $s = 8; | ||
604 | $y = 0; | ||
605 | break; | ||
606 | |||
607 | case 1: | ||
608 | $s = 8; | ||
609 | $y = 4; | ||
610 | break; | ||
611 | |||
612 | case 2: | ||
613 | $s = 4; | ||
614 | $y = 2; | ||
615 | break; | ||
616 | |||
617 | case 3: | ||
618 | $s = 2; | ||
619 | $y = 1; | ||
620 | break; | ||
621 | } | ||
622 | |||
623 | for(; $y < $this->m_gih->m_nHeight; $y += $s) { | ||
624 | $lne = substr($this->m_data, 0, $this->m_gih->m_nWidth); | ||
625 | $this->m_data = substr($this->m_data, $this->m_gih->m_nWidth); | ||
626 | |||
627 | $data = | ||
628 | substr($data, 0, $y * $this->m_gih->m_nWidth) . | ||
629 | $lne . | ||
630 | substr($data, ($y + 1) * $this->m_gih->m_nWidth); | ||
631 | } | ||
632 | } | ||
633 | |||
634 | $this->m_data = $data; | ||
635 | } | ||
636 | } | ||
637 | |||
638 | /////////////////////////////////////////////////////////////////////////////////////////////////// | ||
639 | |||
640 | class CGIF | ||
641 | { | ||
642 | var $m_gfh; | ||
643 | var $m_lpData; | ||
644 | var $m_img; | ||
645 | var $m_bLoaded; | ||
646 | |||
647 | /////////////////////////////////////////////////////////////////////////// | ||
648 | |||
649 | // CONSTRUCTOR | ||
650 | function CGIF() | ||
651 | { | ||
652 | $this->m_gfh = new CGIFFILEHEADER(); | ||
653 | $this->m_img = new CGIFIMAGE(); | ||
654 | $this->m_lpData = ""; | ||
655 | $this->m_bLoaded = false; | ||
656 | } | ||
657 | |||
658 | /////////////////////////////////////////////////////////////////////////// | ||
659 | function ClearData() { | ||
660 | $this->m_lpData = ''; | ||
661 | unSet($this->m_img->m_data); | ||
662 | unSet($this->m_img->m_lzw->Next); | ||
663 | unSet($this->m_img->m_lzw->Vals); | ||
664 | unSet($this->m_img->m_lzw->Stack); | ||
665 | unSet($this->m_img->m_lzw->Buf); | ||
666 | } | ||
667 | |||
668 | function loadFile(&$data, $iIndex) | ||
669 | { | ||
670 | if($iIndex < 0) { | ||
671 | return false; | ||
672 | } | ||
673 | $this->m_lpData = $data; | ||
674 | |||
675 | // GET FILE HEADER | ||
676 | $len = 0; | ||
677 | if(!$this->m_gfh->load($this->m_lpData, $len)) { | ||
678 | return false; | ||
679 | } | ||
680 | |||
681 | $this->m_lpData = substr($this->m_lpData, $len); | ||
682 | |||
683 | do { | ||
684 | $imgLen = 0; | ||
685 | if(!$this->m_img->load($this->m_lpData, $imgLen)) { | ||
686 | return false; | ||
687 | } | ||
688 | $this->m_lpData = substr($this->m_lpData, $imgLen); | ||
689 | } | ||
690 | while($iIndex-- > 0); | ||
691 | |||
692 | $this->m_bLoaded = true; | ||
693 | return true; | ||
694 | } | ||
695 | |||
696 | } | ||
697 | |||
698 | /////////////////////////////////////////////////////////////////////////////////////////////////// | ||
699 | |||
700 | ?> \ No newline at end of file | ||
diff --git a/inc/3rdparty/libraries/mpdf/classes/grad.php b/inc/3rdparty/libraries/mpdf/classes/grad.php new file mode 100644 index 00000000..2691bf5d --- /dev/null +++ b/inc/3rdparty/libraries/mpdf/classes/grad.php | |||
@@ -0,0 +1,723 @@ | |||
1 | <?php | ||
2 | |||
3 | class grad { | ||
4 | |||
5 | var $mpdf = null; | ||
6 | |||
7 | function grad(&$mpdf) { | ||
8 | $this->mpdf = $mpdf; | ||
9 | } | ||
10 | |||
11 | // mPDF 5.3.A1 | ||
12 | function CoonsPatchMesh($x, $y, $w, $h, $patch_array=array(), $x_min=0, $x_max=1, $y_min=0, $y_max=1, $colspace='RGB', $return=false){ | ||
13 | $s=' q '; | ||
14 | $s.=sprintf(' %.3F %.3F %.3F %.3F re W n ', $x*_MPDFK, ($this->mpdf->h-$y)*_MPDFK, $w*_MPDFK, -$h*_MPDFK); | ||
15 | $s.=sprintf(' %.3F 0 0 %.3F %.3F %.3F cm ', $w*_MPDFK, $h*_MPDFK, $x*_MPDFK, ($this->mpdf->h-($y+$h))*_MPDFK); | ||
16 | $n = count($this->mpdf->gradients)+1; | ||
17 | $this->mpdf->gradients[$n]['type'] = 6; //coons patch mesh | ||
18 | $this->mpdf->gradients[$n]['colorspace'] = $colspace; //coons patch mesh | ||
19 | $bpcd=65535; //16 BitsPerCoordinate | ||
20 | $trans = false; | ||
21 | $this->mpdf->gradients[$n]['stream']=''; | ||
22 | for($i=0;$i<count($patch_array);$i++){ | ||
23 | $this->mpdf->gradients[$n]['stream'].=chr($patch_array[$i]['f']); //start with the edge flag as 8 bit | ||
24 | for($j=0;$j<count($patch_array[$i]['points']);$j++){ | ||
25 | //each point as 16 bit | ||
26 | if (($j % 2) == 1) { // Y coordinate (adjusted as input is From top left) | ||
27 | $patch_array[$i]['points'][$j]=(($patch_array[$i]['points'][$j]-$y_min)/($y_max-$y_min))*$bpcd; | ||
28 | $patch_array[$i]['points'][$j]=$bpcd-$patch_array[$i]['points'][$j]; | ||
29 | } | ||
30 | else { | ||
31 | $patch_array[$i]['points'][$j]=(($patch_array[$i]['points'][$j]-$x_min)/($x_max-$x_min))*$bpcd; | ||
32 | } | ||
33 | if($patch_array[$i]['points'][$j]<0) $patch_array[$i]['points'][$j]=0; | ||
34 | if($patch_array[$i]['points'][$j]>$bpcd) $patch_array[$i]['points'][$j]=$bpcd; | ||
35 | $this->mpdf->gradients[$n]['stream'].=chr(floor($patch_array[$i]['points'][$j]/256)); | ||
36 | $this->mpdf->gradients[$n]['stream'].=chr(floor($patch_array[$i]['points'][$j]%256)); | ||
37 | } | ||
38 | for($j=0;$j<count($patch_array[$i]['colors']);$j++){ | ||
39 | //each color component as 8 bit | ||
40 | if ($colspace=='RGB') { | ||
41 | $this->mpdf->gradients[$n]['stream'].=($patch_array[$i]['colors'][$j][1]); | ||
42 | $this->mpdf->gradients[$n]['stream'].=($patch_array[$i]['colors'][$j][2]); | ||
43 | $this->mpdf->gradients[$n]['stream'].=($patch_array[$i]['colors'][$j][3]); | ||
44 | if (isset($patch_array[$i]['colors'][$j][4]) && ord($patch_array[$i]['colors'][$j][4])<100) { $trans = true; } | ||
45 | } | ||
46 | else if ($colspace=='CMYK') { | ||
47 | $this->mpdf->gradients[$n]['stream'].=chr(ord($patch_array[$i]['colors'][$j][1])*2.55); | ||
48 | $this->mpdf->gradients[$n]['stream'].=chr(ord($patch_array[$i]['colors'][$j][2])*2.55); | ||
49 | $this->mpdf->gradients[$n]['stream'].=chr(ord($patch_array[$i]['colors'][$j][3])*2.55); | ||
50 | $this->mpdf->gradients[$n]['stream'].=chr(ord($patch_array[$i]['colors'][$j][4])*2.55); | ||
51 | if (isset($patch_array[$i]['colors'][$j][5]) && ord($patch_array[$i]['colors'][$j][5])<100) { $trans = true; } | ||
52 | } | ||
53 | else if ($colspace=='Gray') { | ||
54 | $this->mpdf->gradients[$n]['stream'].=($patch_array[$i]['colors'][$j][1]); | ||
55 | if ($patch_array[$i]['colors'][$j][2]==1) { $trans = true; } // transparency converted from rgba or cmyka() | ||
56 | } | ||
57 | } | ||
58 | } | ||
59 | // TRANSPARENCY | ||
60 | if ($trans) { | ||
61 | $this->mpdf->gradients[$n]['stream_trans']=''; | ||
62 | for($i=0;$i<count($patch_array);$i++){ | ||
63 | $this->mpdf->gradients[$n]['stream_trans'].=chr($patch_array[$i]['f']); | ||
64 | for($j=0;$j<count($patch_array[$i]['points']);$j++){ | ||
65 | //each point as 16 bit | ||
66 | $this->mpdf->gradients[$n]['stream_trans'].=chr(floor($patch_array[$i]['points'][$j]/256)); | ||
67 | $this->mpdf->gradients[$n]['stream_trans'].=chr(floor($patch_array[$i]['points'][$j]%256)); | ||
68 | } | ||
69 | for($j=0;$j<count($patch_array[$i]['colors']);$j++){ | ||
70 | //each color component as 8 bit // OPACITY | ||
71 | if ($colspace=='RGB') { | ||
72 | $this->mpdf->gradients[$n]['stream_trans'].=chr(intval(ord($patch_array[$i]['colors'][$j][4])*2.55)); | ||
73 | } | ||
74 | else if ($colspace=='CMYK') { | ||
75 | $this->mpdf->gradients[$n]['stream_trans'].=chr(intval(ord($patch_array[$i]['colors'][$j][5])*2.55)); | ||
76 | } | ||
77 | else if ($colspace=='Gray') { | ||
78 | $this->mpdf->gradients[$n]['stream_trans'].=chr(intval(ord($patch_array[$i]['colors'][$j][3])*2.55)); | ||
79 | } | ||
80 | } | ||
81 | } | ||
82 | $this->mpdf->gradients[$n]['trans'] = true; | ||
83 | $s .= ' /TGS'.$n.' gs '; | ||
84 | } | ||
85 | //paint the gradient | ||
86 | $s .= '/Sh'.$n.' sh'."\n"; | ||
87 | //restore previous Graphic State | ||
88 | $s .= 'Q'."\n"; | ||
89 | if ($return) { return $s; } | ||
90 | else { $this->mpdf->_out($s); } | ||
91 | } | ||
92 | |||
93 | |||
94 | // type = linear:2; radial: 3; | ||
95 | // Linear: $coords - array of the form (x1, y1, x2, y2) which defines the gradient vector (see linear_gradient_coords.jpg). | ||
96 | // The default value is from left to right (x1=0, y1=0, x2=1, y2=0). | ||
97 | // Radial: $coords - array of the form (fx, fy, cx, cy, r) where (fx, fy) is the starting point of the gradient with color1, | ||
98 | // (cx, cy) is the center of the circle with color2, and r is the radius of the circle (see radial_gradient_coords.jpg). | ||
99 | // (fx, fy) should be inside the circle, otherwise some areas will not be defined | ||
100 | // $col = array(R,G,B/255); or array(G/255); or array(C,M,Y,K/100) | ||
101 | // $stops = array('col'=>$col [, 'opacity'=>0-1] [, 'offset'=>0-1]) | ||
102 | function Gradient($x, $y, $w, $h, $type, $stops=array(), $colorspace='RGB', $coords='', $extend='', $return=false, $is_mask=false) { | ||
103 | if (strtoupper(substr($type,0,1)) == 'L') { $type = 2; } // linear | ||
104 | else if (strtoupper(substr($type,0,1)) == 'R') { $type = 3; } // radial | ||
105 | if ($colorspace != 'CMYK' && $colorspace != 'Gray') { | ||
106 | $colorspace = 'RGB'; | ||
107 | } | ||
108 | $bboxw = $w; | ||
109 | $bboxh = $h; | ||
110 | $usex = $x; | ||
111 | $usey = $y; | ||
112 | $usew = $bboxw; | ||
113 | $useh = $bboxh; | ||
114 | if ($type < 1) { $type = 2; } | ||
115 | if ($coords[0]!==false && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i',$coords[0],$m)) { | ||
116 | $tmp = $this->mpdf->ConvertSize($m[1],$this->mpdf->w,$this->mpdf->FontSize,false); | ||
117 | if ($tmp) { $coords[0] = $tmp/$w; } | ||
118 | } | ||
119 | if ($coords[1]!==false && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i',$coords[1],$m)) { | ||
120 | $tmp = $this->mpdf->ConvertSize($m[1],$this->mpdf->w,$this->mpdf->FontSize,false); | ||
121 | if ($tmp) { $coords[1] = 1-($tmp/$h); } | ||
122 | } | ||
123 | // LINEAR | ||
124 | if ($type == 2) { | ||
125 | $angle = $coords[4]; | ||
126 | $repeat = $coords[5]; | ||
127 | // ALL POINTS SET (default for custom mPDF linear gradient) - no -moz | ||
128 | if ($coords[0]!==false && $coords[1]!==false && $coords[2]!==false && $coords[3]!==false) { | ||
129 | // do nothing - coords used as they are | ||
130 | } | ||
131 | |||
132 | // If both a <point> and <angle> are defined, the gradient axis starts from the point and runs along the angle. The end point is | ||
133 | // defined as before - in this case start points may not be in corners, and axis may not correctly fall in the right quadrant. | ||
134 | // NO end points (Angle defined & Start points) | ||
135 | else if ($angle!==false && $coords[0]!==false && $coords[1]!==false && $coords[2]===false && $coords[3]===false) { | ||
136 | if ($angle==0 || $angle==360) { $coords[3]=$coords[1]; if ($coords[0]==1) $coords[2]=2; else $coords[2]=1; } | ||
137 | else if ($angle==90) { $coords[2]=$coords[0]; $coords[3]=1; if ($coords[1]==1) $coords[3]=2; else $coords[3]=1; } | ||
138 | else if ($angle==180) { if ($coords[4]==0) $coords[2]=-1; else $coords[2]=0; $coords[3]=$coords[1]; } | ||
139 | else if ($angle==270) { $coords[2]=$coords[0]; if ($coords[1]==0) $coords[3]=-1; else $coords[3]=0; } | ||
140 | else { | ||
141 | $endx=1; $endy=1; | ||
142 | if ($angle <=90) { | ||
143 | if ($angle <=45) { $endy=tan(deg2rad($angle)); } | ||
144 | else { $endx=tan(deg2rad(90-$angle)); } | ||
145 | $b = atan2(($endy*$bboxh), ($endx*$bboxw)); | ||
146 | $ny = 1 - $coords[1] - (tan($b) * (1-$coords[0])); | ||
147 | $tx = sin($b) * cos($b) * $ny; | ||
148 | $ty = cos($b) * cos($b) * $ny; | ||
149 | $coords[2] = 1+$tx; $coords[3] = 1-$ty; | ||
150 | } | ||
151 | else if ($angle <=180) { | ||
152 | if ($angle <=135) { $endx=tan(deg2rad($angle-90)); } | ||
153 | else { $endy=tan(deg2rad(180-$angle)); } | ||
154 | $b = atan2(($endy*$bboxh), ($endx*$bboxw)); | ||
155 | $ny = 1 - $coords[1] - (tan($b) * ($coords[0])); | ||
156 | $tx = sin($b) * cos($b) * $ny; | ||
157 | $ty = cos($b) * cos($b) * $ny; | ||
158 | $coords[2] = -$tx; $coords[3] = 1-$ty; | ||
159 | } | ||
160 | else if ($angle <=270) { | ||
161 | if ($angle <=225) { $endy=tan(deg2rad($angle-180)); } | ||
162 | else { $endx=tan(deg2rad(270-$angle)); } | ||
163 | $b = atan2(($endy*$bboxh), ($endx*$bboxw)); | ||
164 | $ny = $coords[1] - (tan($b) * ($coords[0])); | ||
165 | $tx = sin($b) * cos($b) * $ny; | ||
166 | $ty = cos($b) * cos($b) * $ny; | ||
167 | $coords[2] = -$tx; $coords[3] = $ty; | ||
168 | } | ||
169 | else { | ||
170 | if ($angle <=315) { $endx=tan(deg2rad($angle-270)); } | ||
171 | else { $endy=tan(deg2rad(360-$angle)); } | ||
172 | $b = atan2(($endy*$bboxh), ($endx*$bboxw)); | ||
173 | $ny = $coords[1] - (tan($b) * (1-$coords[0])); | ||
174 | $tx = sin($b) * cos($b) * $ny; | ||
175 | $ty = cos($b) * cos($b) * $ny; | ||
176 | $coords[2] = 1+$tx; $coords[3] = $ty; | ||
177 | |||
178 | } | ||
179 | } | ||
180 | } | ||
181 | |||
182 | // -moz If the first parameter is only an <angle>, the gradient axis starts from the box's corner that would ensure the | ||
183 | // axis goes through the box. The axis runs along the specified angle. The end point of the axis is defined such that the | ||
184 | // farthest corner of the box from the starting point is perpendicular to the gradient axis at that point. | ||
185 | // NO end points or Start points (Angle defined) | ||
186 | else if ($angle!==false && $coords[0]===false && $coords[1]===false) { | ||
187 | if ($angle==0 || $angle==360) { $coords[0]=0; $coords[1]=0; $coords[2]=1; $coords[3]=0; } | ||
188 | else if ($angle==90) { $coords[0]=0; $coords[1]=0; $coords[2]=0; $coords[3]=1; } | ||
189 | else if ($angle==180) { $coords[0]=1; $coords[1]=0; $coords[2]=0; $coords[3]=0; } | ||
190 | else if ($angle==270) { $coords[0]=0; $coords[1]=1; $coords[2]=0; $coords[3]=0; } | ||
191 | else { | ||
192 | if ($angle <=90) { | ||
193 | $coords[0]=0; $coords[1]=0; | ||
194 | if ($angle <=45) { $endx=1; $endy=tan(deg2rad($angle)); } | ||
195 | else { $endx=tan(deg2rad(90-$angle)); $endy=1; } | ||
196 | } | ||
197 | else if ($angle <=180) { | ||
198 | $coords[0]=1; $coords[1]=0; | ||
199 | if ($angle <=135) { $endx=tan(deg2rad($angle-90)); $endy=1; } | ||
200 | else { $endx=1; $endy=tan(deg2rad(180-$angle)); } | ||
201 | } | ||
202 | else if ($angle <=270) { | ||
203 | $coords[0]=1; $coords[1]=1; | ||
204 | if ($angle <=225) { $endx=1; $endy=tan(deg2rad($angle-180)); } | ||
205 | else { $endx=tan(deg2rad(270-$angle)); $endy=1; } | ||
206 | } | ||
207 | else { | ||
208 | $coords[0]=0; $coords[1]=1; | ||
209 | if ($angle <=315) { $endx=tan(deg2rad($angle-270)); $endy=1; } | ||
210 | else { $endx=1; $endy=tan(deg2rad(360-$angle)); } | ||
211 | } | ||
212 | $b = atan2(($endy*$bboxh), ($endx*$bboxw)); | ||
213 | $h2 = $bboxh - ($bboxh * tan($b)); | ||
214 | $px = $bboxh + ($h2 * sin($b) * cos($b)); | ||
215 | $py = ($bboxh * tan($b)) + ($h2 * sin($b) * sin($b)); | ||
216 | $x1 = $px / $bboxh; | ||
217 | $y1 = $py / $bboxh; | ||
218 | if ($angle <=90) { $coords[2] = $x1; $coords[3] = $y1; } | ||
219 | else if ($angle <=180) { $coords[2] = 1-$x1; $coords[3] = $y1; } | ||
220 | else if ($angle <=270) { $coords[2] = 1-$x1; $coords[3] = 1-$y1; } | ||
221 | else { $coords[2] = $x1; $coords[3] = 1-$y1; } | ||
222 | } | ||
223 | } | ||
224 | // -moz If the first parameter to the gradient function is only a <point>, the gradient axis starts from the specified point, | ||
225 | // and ends at the point you would get if you rotated the starting point by 180 degrees about the center of the box that the | ||
226 | // gradient is to be applied to. | ||
227 | // NO angle and NO end points (Start points defined) | ||
228 | else if ((!isset($angle) || $angle===false) && $coords[0]!==false && $coords[1]!==false) { // should have start and end defined | ||
229 | $coords[2] = 1-$coords[0]; $coords[3] = 1-$coords[1]; | ||
230 | $angle = rad2deg(atan2($coords[3]-$coords[1],$coords[2]-$coords[0])); | ||
231 | if ($angle < 0) { $angle += 360; } | ||
232 | else if ($angle > 360) { $angle -= 360; } | ||
233 | if ($angle!=0 && $angle!=360 && $angle!=90 && $angle!=180 && $angle!=270) { | ||
234 | if ($w >= $h) { | ||
235 | $coords[1] *= $h/$w ; | ||
236 | $coords[3] *= $h/$w ; | ||
237 | $usew = $useh = $bboxw; | ||
238 | $usey -= ($w-$h); | ||
239 | } | ||
240 | else { | ||
241 | $coords[0] *= $w/$h ; | ||
242 | $coords[2] *= $w/$h ; | ||
243 | $usew = $useh = $bboxh; | ||
244 | } | ||
245 | } | ||
246 | } | ||
247 | |||
248 | // -moz If neither a <point> or <angle> is specified, i.e. the entire function consists of only <stop> values, the gradient | ||
249 | // axis starts from the top of the box and runs vertically downwards, ending at the bottom of the box. | ||
250 | else { // default values T2B | ||
251 | // All values are set in parseMozGradient - so won't appear here | ||
252 | $coords = array(0,0,1,0); // default for original linear gradient (L2R) | ||
253 | } | ||
254 | $s = ' q'; | ||
255 | $s .= sprintf(' %.3F %.3F %.3F %.3F re W n', $x*_MPDFK, ($this->mpdf->h-$y)*_MPDFK, $w*_MPDFK, -$h*_MPDFK)."\n"; | ||
256 | $s .= sprintf(' %.3F 0 0 %.3F %.3F %.3F cm', $usew*_MPDFK, $useh*_MPDFK, $usex*_MPDFK, ($this->mpdf->h-($usey+$useh))*_MPDFK)."\n"; | ||
257 | } | ||
258 | |||
259 | // RADIAL | ||
260 | else if ($type == 3) { | ||
261 | $radius = $coords[4]; | ||
262 | $angle = $coords[5]; // ?? no effect | ||
263 | $shape = $coords[6]; | ||
264 | $size = $coords[7]; | ||
265 | $repeat = $coords[8]; | ||
266 | // ALL POINTS AND RADIUS SET (default for custom mPDF radial gradient) - no -moz | ||
267 | if ($coords[0]!==false && $coords[1]!==false && $coords[2]!==false && $coords[3]!==false && $coords[4]!==false) { | ||
268 | // do nothing - coords used as they are | ||
269 | } | ||
270 | // If a <point> is defined | ||
271 | else if ($shape!==false && $size!==false) { | ||
272 | if ($coords[2]==false) { $coords[2] = $coords[0]; } | ||
273 | if ($coords[3]==false) { $coords[3] = $coords[1]; } | ||
274 | // ELLIPSE | ||
275 | if ($shape=='ellipse') { | ||
276 | $corner1 = sqrt(pow($coords[0],2) + pow($coords[1],2)); | ||
277 | $corner2 = sqrt(pow($coords[0],2) + pow((1-$coords[1]),2)); | ||
278 | $corner3 = sqrt(pow((1-$coords[0]),2) + pow($coords[1],2)); | ||
279 | $corner4 = sqrt(pow((1-$coords[0]),2) + pow((1-$coords[1]),2)); | ||
280 | if ($size=='closest-side') { $radius = min($coords[0], $coords[1], (1-$coords[0]), (1-$coords[1])); } | ||
281 | else if ($size=='closest-corner') { $radius = min($corner1, $corner2, $corner3, $corner4); } | ||
282 | else if ($size=='farthest-side') { $radius = max($coords[0], $coords[1], (1-$coords[0]), (1-$coords[1])); } | ||
283 | else { $radius = max($corner1, $corner2, $corner3, $corner4); } // farthest corner (default) | ||
284 | } | ||
285 | // CIRCLE | ||
286 | else if ($shape=='circle') { | ||
287 | if ($w >= $h) { | ||
288 | $coords[1] = $coords[3] = ($coords[1] * $h/$w) ; | ||
289 | $corner1 = sqrt(pow($coords[0],2) + pow($coords[1],2)); | ||
290 | $corner2 = sqrt(pow($coords[0],2) + pow((($h/$w)-$coords[1]),2)); | ||
291 | $corner3 = sqrt(pow((1-$coords[0]),2) + pow($coords[1],2)); | ||
292 | $corner4 = sqrt(pow((1-$coords[0]),2) + pow((($h/$w)-$coords[1]),2)); | ||
293 | if ($size=='closest-side') { $radius = min($coords[0], $coords[1], (1-$coords[0]), (($h/$w)-$coords[1])); } | ||
294 | else if ($size=='closest-corner') { $radius = min($corner1, $corner2, $corner3, $corner4); } | ||
295 | else if ($size=='farthest-side') { $radius = max($coords[0], $coords[1], (1-$coords[0]), (($h/$w)-$coords[1])); } | ||
296 | else if ($size=='farthest-corner') { $radius = max($corner1, $corner2, $corner3, $corner4); } // farthest corner (default) | ||
297 | $usew = $useh = $bboxw; | ||
298 | $usey -= ($w-$h); | ||
299 | } | ||
300 | else { | ||
301 | $coords[0] = $coords[2] = ($coords[0] * $w/$h) ; | ||
302 | $corner1 = sqrt(pow($coords[0],2) + pow($coords[1],2)); | ||
303 | $corner2 = sqrt(pow($coords[0],2) + pow((1-$coords[1]),2)); | ||
304 | $corner3 = sqrt(pow((($w/$h)-$coords[0]),2) + pow($coords[1],2)); | ||
305 | $corner4 = sqrt(pow((($w/$h)-$coords[0]),2) + pow((1-$coords[1]),2)); | ||
306 | if ($size=='closest-side') { $radius = min($coords[0], $coords[1], (($w/$h)-$coords[0]), (1-$coords[1])); } | ||
307 | else if ($size=='closest-corner') { $radius = min($corner1, $corner2, $corner3, $corner4); } | ||
308 | else if ($size=='farthest-side') { $radius = max($coords[0], $coords[1], (($w/$h)-$coords[0]), (1-$coords[1])); } | ||
309 | else if ($size=='farthest-corner') { $radius = max($corner1, $corner2, $corner3, $corner4); } // farthest corner (default) | ||
310 | $usew = $useh = $bboxh; | ||
311 | } | ||
312 | } | ||
313 | if ($radius==0) { $radius=0.001; } // to prevent error | ||
314 | $coords[4] = $radius; | ||
315 | } | ||
316 | |||
317 | // -moz If entire function consists of only <stop> values | ||
318 | else { // default values | ||
319 | // All values are set in parseMozGradient - so won't appear here | ||
320 | $coords = array(0.5,0.5,0.5,0.5); // default for radial gradient (centred) | ||
321 | } | ||
322 | $s = ' q'; | ||
323 | $s .= sprintf(' %.3F %.3F %.3F %.3F re W n', $x*_MPDFK, ($this->mpdf->h-$y)*_MPDFK, $w*_MPDFK, -$h*_MPDFK)."\n"; | ||
324 | $s .= sprintf(' %.3F 0 0 %.3F %.3F %.3F cm', $usew*_MPDFK, $useh*_MPDFK, $usex*_MPDFK, ($this->mpdf->h-($usey+$useh))*_MPDFK)."\n"; | ||
325 | } | ||
326 | |||
327 | $n = count($this->mpdf->gradients) + 1; | ||
328 | $this->mpdf->gradients[$n]['type'] = $type; | ||
329 | $this->mpdf->gradients[$n]['colorspace'] = $colorspace; | ||
330 | $trans = false; | ||
331 | $this->mpdf->gradients[$n]['is_mask'] = $is_mask; | ||
332 | if ($is_mask) { $trans = true; } | ||
333 | if (count($stops) == 1) { $stops[1] = $stops[0]; } | ||
334 | if (!isset($stops[0]['offset'])) { $stops[0]['offset'] = 0; } | ||
335 | if (!isset($stops[(count($stops)-1)]['offset'])) { $stops[(count($stops)-1)]['offset'] = 1; } | ||
336 | |||
337 | // Fix stop-offsets set as absolute lengths | ||
338 | if ($type==2) { | ||
339 | $axisx = ($coords[2]-$coords[0])*$usew; | ||
340 | $axisy = ($coords[3]-$coords[1])*$useh; | ||
341 | $axis_length = sqrt(pow($axisx,2) + pow($axisy,2)); | ||
342 | } | ||
343 | else { $axis_length = $coords[4]*$usew; } // Absolute lengths are meaningless for an ellipse - Firefox uses Width as reference | ||
344 | |||
345 | for($i=0;$i<count($stops);$i++) { | ||
346 | if (isset($stops[$i]['offset']) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i',$stops[$i]['offset'],$m)) { | ||
347 | $tmp = $this->mpdf->ConvertSize($m[1],$this->mpdf->w,$this->mpdf->FontSize,false); | ||
348 | $stops[$i]['offset'] = $tmp/$axis_length; | ||
349 | } | ||
350 | } | ||
351 | |||
352 | |||
353 | if (isset($stops[0]['offset']) && $stops[0]['offset']>0) { | ||
354 | $firststop = $stops[0]; | ||
355 | $firststop['offset'] = 0; | ||
356 | array_unshift($stops, $firststop); | ||
357 | } | ||
358 | if (!$repeat && isset($stops[(count($stops)-1)]['offset']) && $stops[(count($stops)-1)]['offset']<1) { | ||
359 | $endstop = $stops[(count($stops)-1)]; | ||
360 | $endstop['offset'] = 1; | ||
361 | $stops[] = $endstop; | ||
362 | } | ||
363 | if ($stops[0]['offset'] > $stops[(count($stops)-1)]['offset']) { | ||
364 | $stops[0]['offset'] = 0; | ||
365 | $stops[(count($stops)-1)]['offset'] = 1; | ||
366 | } | ||
367 | |||
368 | for($i=0;$i<count($stops);$i++) { | ||
369 | // mPDF 5.3.74 | ||
370 | if ($colorspace == 'CMYK') { | ||
371 | $this->mpdf->gradients[$n]['stops'][$i]['col'] = sprintf('%.3F %.3F %.3F %.3F', (ord($stops[$i]['col']{1})/100), (ord($stops[$i]['col']{2})/100), (ord($stops[$i]['col']{3})/100), (ord($stops[$i]['col']{4})/100)); | ||
372 | } | ||
373 | else if ($colorspace == 'Gray') { | ||
374 | $this->mpdf->gradients[$n]['stops'][$i]['col'] = sprintf('%.3F', (ord($stops[$i]['col']{1})/255)); | ||
375 | } | ||
376 | else { | ||
377 | $this->mpdf->gradients[$n]['stops'][$i]['col'] = sprintf('%.3F %.3F %.3F', (ord($stops[$i]['col']{1})/255), (ord($stops[$i]['col']{2})/255), (ord($stops[$i]['col']{3})/255)); | ||
378 | } | ||
379 | if (!isset($stops[$i]['opacity'])) { $stops[$i]['opacity'] = 1; } | ||
380 | else if ($stops[$i]['opacity'] > 1 || $stops[$i]['opacity'] < 0) { $stops[$i]['opacity'] = 1; } | ||
381 | else if ($stops[$i]['opacity'] < 1) { | ||
382 | $trans = true; | ||
383 | } | ||
384 | $this->mpdf->gradients[$n]['stops'][$i]['opacity'] = $stops[$i]['opacity']; | ||
385 | // OFFSET | ||
386 | if ($i>0 && $i<(count($stops)-1)) { | ||
387 | if (!isset($stops[$i]['offset']) || (isset($stops[$i+1]['offset']) && $stops[$i]['offset']>$stops[$i+1]['offset']) || $stops[$i]['offset']<$stops[$i-1]['offset']) { | ||
388 | if (isset($stops[$i-1]['offset']) && isset($stops[$i+1]['offset'])) { | ||
389 | $stops[$i]['offset'] = ($stops[$i-1]['offset']+$stops[$i+1]['offset'])/2; | ||
390 | } | ||
391 | else { | ||
392 | for($j=($i+1);$j<count($stops);$j++) { | ||
393 | if(isset($stops[$j]['offset'])) { break; } | ||
394 | } | ||
395 | $int = ($stops[$j]['offset'] - $stops[($i-1)]['offset'])/($j-$i+1); | ||
396 | for($f=0;$f<($j-$i-1);$f++) { | ||
397 | $stops[($i+$f)]['offset'] = $stops[($i+$f-1)]['offset'] + ($int); | ||
398 | } | ||
399 | } | ||
400 | } | ||
401 | } | ||
402 | $this->mpdf->gradients[$n]['stops'][$i]['offset'] = $stops[$i]['offset']; | ||
403 | $this->mpdf->gradients[$n]['stops'][$i]['offset'] = $stops[$i]['offset']; | ||
404 | } | ||
405 | |||
406 | if ($repeat) { | ||
407 | $ns = count($this->mpdf->gradients[$n]['stops']); | ||
408 | $offs = array(); | ||
409 | for($i=0;$i<$ns;$i++) { | ||
410 | $offs[$i] = $this->mpdf->gradients[$n]['stops'][$i]['offset']; | ||
411 | } | ||
412 | $gp = 0; | ||
413 | $inside=true; | ||
414 | while($inside) { | ||
415 | $gp++; | ||
416 | for($i=0;$i<$ns;$i++) { | ||
417 | $this->mpdf->gradients[$n]['stops'][(($ns*$gp)+$i)] = $this->mpdf->gradients[$n]['stops'][(($ns*($gp-1))+$i)]; | ||
418 | $tmp = $this->mpdf->gradients[$n]['stops'][(($ns*($gp-1))+($ns-1))]['offset']+$offs[$i] ; | ||
419 | if ($tmp < 1) { $this->mpdf->gradients[$n]['stops'][(($ns*$gp)+$i)]['offset'] = $tmp; } | ||
420 | else { | ||
421 | $this->mpdf->gradients[$n]['stops'][(($ns*$gp)+$i)]['offset'] = 1; | ||
422 | $inside = false; | ||
423 | break(2); | ||
424 | } | ||
425 | } | ||
426 | } | ||
427 | } | ||
428 | |||
429 | if ($trans) { | ||
430 | $this->mpdf->gradients[$n]['trans'] = true; | ||
431 | $s .= ' /TGS'.$n.' gs '; | ||
432 | } | ||
433 | if (!is_array($extend) || count($extend) <1) { | ||
434 | $extend=array('true', 'true'); // These are supposed to be quoted - appear in PDF file as text | ||
435 | } | ||
436 | $this->mpdf->gradients[$n]['coords'] = $coords; | ||
437 | $this->mpdf->gradients[$n]['extend'] = $extend; | ||
438 | //paint the gradient | ||
439 | $s .= '/Sh'.$n.' sh '."\n"; | ||
440 | //restore previous Graphic State | ||
441 | $s .= ' Q '."\n"; | ||
442 | if ($return) { return $s; } | ||
443 | else { $this->mpdf->_out($s); } | ||
444 | } | ||
445 | |||
446 | |||
447 | function parseMozGradient($bg) { | ||
448 | // background[-image]: -moz-linear-gradient(left, #c7Fdde 20%, #FF0000 ); | ||
449 | // background[-image]: linear-gradient(left, #c7Fdde 20%, #FF0000 ); // CSS3 | ||
450 | if (preg_match('/repeating-/',$bg)) { $repeat = true; } | ||
451 | else { $repeat = false; } | ||
452 | if (preg_match('/linear-gradient\((.*)\)/',$bg,$m)) { | ||
453 | $g = array(); | ||
454 | $g['type'] = 2; | ||
455 | $g['colorspace'] = 'RGB'; | ||
456 | $g['extend'] = array('true','true'); | ||
457 | $v = trim($m[1]); | ||
458 | // Change commas inside e.g. rgb(x,x,x) | ||
459 | while(preg_match('/(\([^\)]*?),/',$v)) { $v = preg_replace('/(\([^\)]*?),/','\\1@',$v); } | ||
460 | // Remove spaces inside e.g. rgb(x, x, x) | ||
461 | while(preg_match('/(\([^\)]*?)[ ]/',$v)) { $v = preg_replace('/(\([^\)]*?)[ ]/','\\1',$v); } | ||
462 | $bgr = preg_split('/\s*,\s*/',$v); | ||
463 | for($i=0;$i<count($bgr);$i++) { $bgr[$i] = preg_replace('/@/', ',', $bgr[$i]); } | ||
464 | // Is first part $bgr[0] a valid point/angle? | ||
465 | $first = preg_split('/\s+/',trim($bgr[0])); | ||
466 | if (preg_match('/(left|center|right|bottom|top|deg|grad|rad)/i',$bgr[0]) && !preg_match('/(<#|rgb|rgba|hsl|hsla)/i',$bgr[0])) { | ||
467 | $startStops = 1; | ||
468 | } | ||
469 | else if (trim($first[(count($first)-1)]) === "0") { | ||
470 | $startStops = 1; | ||
471 | } | ||
472 | else { | ||
473 | $check = $this->mpdf->ConvertColor($first[0]); | ||
474 | if ($check) $startStops = 0; | ||
475 | else $startStops = 1; | ||
476 | } | ||
477 | // first part a valid point/angle? | ||
478 | if ($startStops == 1) { // default values | ||
479 | // [<point> || <angle>,] = [<% em px left center right bottom top> || <deg grad rad 0>,] | ||
480 | if (preg_match('/([\-]*[0-9\.]+)(deg|grad|rad)/i',$bgr[0],$m)) { | ||
481 | $angle = $m[1] + 0; | ||
482 | if (strtolower($m[2])=='deg') { $angle = $angle; } | ||
483 | else if (strtolower($m[2])=='grad') { $angle *= (360/400); } | ||
484 | else if (strtolower($m[2])=='rad') { $angle = rad2deg($angle); } | ||
485 | while($angle < 0) { $angle += 360; } | ||
486 | $angle = ($angle % 360); | ||
487 | } | ||
488 | else if (trim($first[(count($first)-1)]) === "0") { $angle = 0; } | ||
489 | if (preg_match('/left/i',$bgr[0])) { $startx = 0; } | ||
490 | else if (preg_match('/right/i',$bgr[0])) { $startx = 1; } | ||
491 | if (preg_match('/top/i',$bgr[0])) { $starty = 1; } | ||
492 | else if (preg_match('/bottom/i',$bgr[0])) { $starty = 0; } | ||
493 | // Check for %? ?% or %% | ||
494 | if (preg_match('/(\d+)[%]/i',$first[0],$m)) { $startx = $m[1]/100; } | ||
495 | else if (!isset($startx) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i',$first[0],$m)) { | ||
496 | $tmp = $this->mpdf->ConvertSize($m[1],$this->mpdf->w,$this->mpdf->FontSize,false); | ||
497 | if ($tmp) { $startx = $m[1]; } | ||
498 | } | ||
499 | if (isset($first[1]) && preg_match('/(\d+)[%]/i',$first[1],$m)) { $starty = 1 - ($m[1]/100); } | ||
500 | else if (!isset($starty) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i',$first[1],$m)) { | ||
501 | $tmp = $this->mpdf->ConvertSize($m[1],$this->mpdf->w,$this->mpdf->FontSize,false); | ||
502 | if ($tmp) { $starty = $m[1]; } | ||
503 | } | ||
504 | if (isset($startx) && !isset($starty)) { $starty = 0.5; } | ||
505 | if (!isset($startx) && isset($starty)) { $startx = 0.5; } | ||
506 | |||
507 | } | ||
508 | // If neither a <point> or <angle> is specified, i.e. the entire function consists of only <stop> values, the gradient axis starts from the top of the box and runs vertically downwards, ending at the bottom of the box. | ||
509 | else { // default values T2B | ||
510 | $starty = 1; $startx = 0.5; | ||
511 | $endy = 0; $endx = 0.5; | ||
512 | } | ||
513 | $coords = array(); | ||
514 | if (!isset($startx)) { $startx = false; } | ||
515 | if (!isset($starty)) { $starty = false; } | ||
516 | if (!isset($endx)) { $endx = false; } | ||
517 | if (!isset($endy)) { $endy = false; } | ||
518 | if (!isset($angle)) { $angle = false; } | ||
519 | $g['coords'] = array($startx ,$starty ,$endx ,$endy, $angle, $repeat ); | ||
520 | $g['stops'] = array(); | ||
521 | for($i=$startStops;$i<count($bgr);$i++) { | ||
522 | $stop = array(); | ||
523 | // parse stops | ||
524 | $el = preg_split('/\s+/',trim($bgr[$i])); | ||
525 | // mPDF 5.3.74 | ||
526 | $col = $this->mpdf->ConvertColor($el[0]); | ||
527 | if ($col) { $stop['col'] = $col; } | ||
528 | else { $stop['col'] = $col = $this->mpdf->ConvertColor(255); } | ||
529 | if ($col{0}==1) $g['colorspace'] = 'Gray'; | ||
530 | else if ($col{0}==4 || $col{0}==6) $g['colorspace'] = 'CMYK'; | ||
531 | if ($col{0}==5) { $stop['opacity'] = ord($col{4})/100; } // transparency from rgba() | ||
532 | else if ($col{0}==6) { $stop['opacity'] = ord($col{5})/100; } // transparency from cmyka() | ||
533 | else if ($col{0}==1 && $col{2}==1) { $stop['opacity'] = ord($col{3})/100; } // transparency converted from rgba or cmyka() | ||
534 | |||
535 | if (isset($el[1]) && preg_match('/(\d+)[%]/',$el[1],$m)) { | ||
536 | $stop['offset'] = $m[1]/100; | ||
537 | if ($stop['offset']>1) { unset($stop['offset']); } | ||
538 | } | ||
539 | else if (isset($el[1]) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i',$el[1],$m)) { | ||
540 | $tmp = $this->mpdf->ConvertSize($m[1],$this->mpdf->w,$this->mpdf->FontSize,false); | ||
541 | if ($tmp) { $stop['offset'] = $m[1]; } | ||
542 | } | ||
543 | $g['stops'][] = $stop; | ||
544 | } | ||
545 | if (count($g['stops'] )) { return $g; } | ||
546 | } | ||
547 | else if (preg_match('/radial-gradient\((.*)\)/',$bg,$m)) { | ||
548 | $g = array(); | ||
549 | $g['type'] = 3; | ||
550 | $g['colorspace'] = 'RGB'; | ||
551 | $g['extend'] = array('true','true'); | ||
552 | $v = trim($m[1]); | ||
553 | // Change commas inside e.g. rgb(x,x,x) | ||
554 | while(preg_match('/(\([^\)]*?),/',$v)) { $v = preg_replace('/(\([^\)]*?),/','\\1@',$v); } | ||
555 | // Remove spaces inside e.g. rgb(x, x, x) | ||
556 | while(preg_match('/(\([^\)]*?)[ ]/',$v)) { $v = preg_replace('/(\([^\)]*?)[ ]/','\\1',$v); } | ||
557 | $bgr = preg_split('/\s*,\s*/',$v); | ||
558 | for($i=0;$i<count($bgr);$i++) { $bgr[$i] = preg_replace('/@/', ',', $bgr[$i]); } | ||
559 | |||
560 | // Is first part $bgr[0] a valid point/angle? | ||
561 | $startStops = 0; | ||
562 | $pos_angle = false; | ||
563 | $shape_size = false; | ||
564 | $first = preg_split('/\s+/',trim($bgr[0])); | ||
565 | $checkCol = $this->mpdf->ConvertColor($first[0]); | ||
566 | if (preg_match('/(left|center|right|bottom|top|deg|grad|rad)/i',$bgr[0]) && !preg_match('/(<#|rgb|rgba|hsl|hsla)/i',$bgr[0])) { | ||
567 | $startStops=1; | ||
568 | $pos_angle = $bgr[0]; | ||
569 | } | ||
570 | else if (trim($first[(count($first)-1)]) === "0") { | ||
571 | $startStops=1; | ||
572 | $pos_angle = $bgr[0]; | ||
573 | } | ||
574 | else if (preg_match('/(circle|ellipse|closest-side|closest-corner|farthest-side|farthest-corner|contain|cover)/i',$bgr[0])) { | ||
575 | $startStops=1; | ||
576 | $shape_size = $bgr[0]; | ||
577 | } | ||
578 | else if (!$checkCol) { | ||
579 | $startStops=1; | ||
580 | $pos_angle = $bgr[0]; | ||
581 | } | ||
582 | if (preg_match('/(circle|ellipse|closest-side|closest-corner|farthest-side|farthest-corner|contain|cover)/i',$bgr[1])) { | ||
583 | $startStops=2; | ||
584 | $shape_size = $bgr[1]; | ||
585 | } | ||
586 | |||
587 | // If valid point/angle? | ||
588 | if ($pos_angle) { // default values | ||
589 | // [<point> || <angle>,] = [<% em px left center right bottom top> || <deg grad rad 0>,] | ||
590 | if (preg_match('/left/i',$pos_angle)) { $startx = 0; } | ||
591 | else if (preg_match('/right/i',$pos_angle)) { $startx = 1; } | ||
592 | if (preg_match('/top/i',$pos_angle)) { $starty = 1; } | ||
593 | else if (preg_match('/bottom/i',$pos_angle)) { $starty = 0; } | ||
594 | // Check for %? ?% or %% | ||
595 | if (preg_match('/(\d+)[%]/i',$first[0],$m)) { $startx = $m[1]/100; } | ||
596 | else if (!isset($startx) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i',$first[0],$m)) { | ||
597 | $tmp = $this->mpdf->ConvertSize($m[1],$this->mpdf->w,$this->mpdf->FontSize,false); | ||
598 | if ($tmp) { $startx = $m[1]; } | ||
599 | } | ||
600 | if (isset($first[1]) && preg_match('/(\d+)[%]/i',$first[1],$m)) { $starty = 1 - ($m[1]/100); } | ||
601 | else if (!isset($starty) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i',$first[1],$m)) { | ||
602 | $tmp = $this->mpdf->ConvertSize($m[1],$this->mpdf->w,$this->mpdf->FontSize,false); | ||
603 | if ($tmp) { $starty = $m[1]; } | ||
604 | } | ||
605 | |||
606 | /* | ||
607 | // ?? Angle has no effect in radial gradient (does not exist in CSS3 spec.) | ||
608 | if (preg_match('/([\-]*[0-9\.]+)(deg|grad|rad)/i',$pos_angle,$m)) { | ||
609 | $angle = $m[1] + 0; | ||
610 | if (strtolower($m[2])=='deg') { $angle = $angle; } | ||
611 | else if (strtolower($m[2])=='grad') { $angle *= (360/400); } | ||
612 | else if (strtolower($m[2])=='rad') { $angle = rad2deg($angle); } | ||
613 | while($angle < 0) { $angle += 360; } | ||
614 | $angle = ($angle % 360); | ||
615 | } | ||
616 | */ | ||
617 | if (!isset($starty)) { $starty = 0.5; } | ||
618 | if (!isset($startx)) { $startx = 0.5; } | ||
619 | |||
620 | } | ||
621 | // If neither a <point> or <angle> is specified, i.e. the entire function consists of only <stop> values, the gradient axis starts from the top of the box and runs vertically downwards, ending at the bottom of the box. | ||
622 | else { // default values Center | ||
623 | $starty = 0.5; $startx = 0.5; | ||
624 | $endy = 0.5; $endx = 0.5; | ||
625 | } | ||
626 | |||
627 | // If valid shape/size? | ||
628 | $shape = 'ellipse'; // default | ||
629 | $size = 'farthest-corner'; // default | ||
630 | if ($shape_size) { // default values | ||
631 | if (preg_match('/(circle|ellipse)/i',$shape_size, $m)) { | ||
632 | $shape = $m[1]; | ||
633 | } | ||
634 | if (preg_match('/(closest-side|closest-corner|farthest-side|farthest-corner|contain|cover)/i',$shape_size, $m)) { | ||
635 | $size = $m[1]; | ||
636 | if ($size=='contain') { $size = 'closest-side'; } | ||
637 | else if ($size=='cover') { $size = 'farthest-corner'; } | ||
638 | } | ||
639 | } | ||
640 | |||
641 | $coords = array(); | ||
642 | if (!isset($startx)) { $startx = false; } | ||
643 | if (!isset($starty)) { $starty = false; } | ||
644 | if (!isset($endx)) { $endx = false; } | ||
645 | if (!isset($endy)) { $endy = false; } | ||
646 | if (!isset($radius)) { $radius = false; } | ||
647 | if (!isset($angle)) { $angle = 0; } | ||
648 | $g['coords'] = array($startx ,$starty ,$endx ,$endy, $radius, $angle, $shape, $size, $repeat ); | ||
649 | |||
650 | $g['stops'] = array(); | ||
651 | for($i=$startStops;$i<count($bgr);$i++) { | ||
652 | $stop = array(); | ||
653 | // parse stops | ||
654 | $el = preg_split('/\s+/',trim($bgr[$i])); | ||
655 | // mPDF 5.3.74 | ||
656 | $col = $this->mpdf->ConvertColor($el[0]); | ||
657 | if ($col) { $stop['col'] = $col; } | ||
658 | else { $stop['col'] = $col = $this->mpdf->ConvertColor(255); } | ||
659 | if ($col{0}==1) $g['colorspace'] = 'Gray'; | ||
660 | else if ($col{0}==4 || $col{0}==6) $g['colorspace'] = 'CMYK'; | ||
661 | if ($col{0}==5) { $stop['opacity'] = ord($col{4})/100; } // transparency from rgba() | ||
662 | else if ($col{0}==6) { $stop['opacity'] = ord($col{5})/100; } // transparency from cmyka() | ||
663 | else if ($col{0}==1 && $col{2}==1) { $stop['opacity'] = ord($col{3})/100; } // transparency converted from rgba or cmyka() | ||
664 | |||
665 | if (isset($el[1]) && preg_match('/(\d+)[%]/',$el[1],$m)) { | ||
666 | $stop['offset'] = $m[1]/100; | ||
667 | if ($stop['offset']>1) { unset($stop['offset']); } | ||
668 | } | ||
669 | else if (isset($el[1]) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i',$el[1],$m)) { | ||
670 | $tmp = $this->mpdf->ConvertSize($m[1],$this->mpdf->w,$this->mpdf->FontSize,false); | ||
671 | $stop['offset'] = $el[1]; | ||
672 | } | ||
673 | $g['stops'][] = $stop; | ||
674 | } | ||
675 | if (count($g['stops'] )) { return $g; } | ||
676 | } | ||
677 | return array(); | ||
678 | } | ||
679 | |||
680 | function parseBackgroundGradient($bg) { | ||
681 | // background-gradient: linear #00FFFF #FFFF00 0 0.5 1 0.5; or | ||
682 | // background-gradient: radial #00FFFF #FFFF00 0.5 0.5 1 1 1.2; | ||
683 | |||
684 | $v = trim($bg); | ||
685 | $bgr = preg_split('/\s+/',$v); | ||
686 | $g = array(); | ||
687 | if (count($bgr)> 6) { | ||
688 | if (strtoupper(substr($bgr[0],0,1)) == 'L' && count($bgr)==7) { // linear | ||
689 | $g['type'] = 2; | ||
690 | //$coords = array(0,0,1,1 ); // 0 0 1 0 or 0 1 1 1 is L 2 R; 1,1,0,1 is R2L; 1,1,1,0 is T2B; 1,0,1,1 is B2T | ||
691 | // Linear: $coords - array of the form (x1, y1, x2, y2) which defines the gradient vector (see linear_gradient_coords.jpg). | ||
692 | // The default value is from left to right (x1=0, y1=0, x2=1, y2=0). | ||
693 | $g['coords'] = array($bgr[3], $bgr[4], $bgr[5], $bgr[6]); | ||
694 | } | ||
695 | else if (count($bgr)==8) { // radial | ||
696 | $g['type'] = 3; | ||
697 | // Radial: $coords - array of the form (fx, fy, cx, cy, r) where (fx, fy) is the starting point of the gradient with color1, | ||
698 | // (cx, cy) is the center of the circle with color2, and r is the radius of the circle (see radial_gradient_coords.jpg). | ||
699 | // (fx, fy) should be inside the circle, otherwise some areas will not be defined | ||
700 | $g['coords'] = array($bgr[3], $bgr[4], $bgr[5], $bgr[6], $bgr[7]); | ||
701 | } | ||
702 | $g['colorspace'] = 'RGB'; | ||
703 | // mPDF 5.3.74 | ||
704 | $cor = $this->mpdf->ConvertColor($bgr[1]); | ||
705 | if ($cor{0}==1) $g['colorspace'] = 'Gray'; | ||
706 | else if ($cor{0}==4 || $cor{0}==6) $g['colorspace'] = 'CMYK'; | ||
707 | if ($cor) { $g['col'] = $cor; } | ||
708 | else { $g['col'] = $this->mpdf->ConvertColor(255); } | ||
709 | $cor = $this->mpdf->ConvertColor($bgr[2]); | ||
710 | if ($cor) { $g['col2'] = $cor; } | ||
711 | else { $g['col2'] = $this->mpdf->ConvertColor(255); } | ||
712 | $g['extend'] = array('true','true'); | ||
713 | $g['stops'] = array(array('col'=>$g['col'], 'opacity'=>1, 'offset'=>0), array('col'=>$g['col2'], 'opacity'=>1, 'offset'=>1)); | ||
714 | return $g; | ||
715 | } | ||
716 | return false; | ||
717 | } | ||
718 | |||
719 | |||
720 | |||
721 | } | ||
722 | |||
723 | ?> \ No newline at end of file | ||
diff --git a/inc/3rdparty/libraries/mpdf/classes/indic.php b/inc/3rdparty/libraries/mpdf/classes/indic.php new file mode 100644 index 00000000..0573053b --- /dev/null +++ b/inc/3rdparty/libraries/mpdf/classes/indic.php | |||
@@ -0,0 +1,433 @@ | |||
1 | <?php | ||
2 | |||
3 | class indic { | ||
4 | |||
5 | function indic() { | ||
6 | |||
7 | } | ||
8 | |||
9 | |||
10 | function substituteIndic($earr, $lang, $font) { | ||
11 | global $voltdata; | ||
12 | |||
13 | if (!isset($voltdata[$font])) { | ||
14 | include_once(_MPDF_PATH.'includes/'.$font.'.volt.php'); | ||
15 | $voltdata[$font] = $volt; | ||
16 | } | ||
17 | |||
18 | foreach($earr as $eid=>$char) { | ||
19 | $earr[$eid] = sprintf("%04s", strtoupper(dechex($char))); | ||
20 | } | ||
21 | $vstr = "0020 ".implode(" ",$earr)." 0020"; | ||
22 | //============================ | ||
23 | // Common Indic Punctuation marks | ||
24 | // If NOT devanagari | ||
25 | if ($lang!='hi') { | ||
26 | $vstr = str_replace('0964','007C', $vstr); // U+0964 replace with "|" | ||
27 | $vstr = str_replace('0965','007C 007C', $vstr); // U+0964 replace with "|" | ||
28 | } | ||
29 | //============================ | ||
30 | // Tamil numeral for Zero missing Added mPDF 4.2 | ||
31 | if ($lang=='ta') { | ||
32 | $vstr = str_replace('0BE6','0030', $vstr); // U+0BEB replace with "0" | ||
33 | } | ||
34 | |||
35 | //============================ | ||
36 | // Re-order vowels | ||
37 | |||
38 | // DEVANAGARI vowel sign matraI[093F] before consonant | ||
39 | if ($lang=='hi') { | ||
40 | $prebasedvowels = "(093F)"; | ||
41 | $nukta = "093C"; | ||
42 | $halant = "094D"; | ||
43 | $vstr = preg_replace('/([A-F0-9]{4}) '.$prebasedvowels.'/','\\2 \\1', $vstr); // vowel sign pre-based shift left | ||
44 | $vstr = preg_replace('/([A-F0-9]{4}) '.$prebasedvowels.' '.$nukta.'/','\\2 \\1 '.$nukta, $vstr); // before NUKTA | ||
45 | $vstr = preg_replace('/([A-F0-9]{4}) '.$halant.' '.$prebasedvowels.'/','\\2 \\1 '.$halant, $vstr); // before CHAR HALANT == VIRAMA | ||
46 | } | ||
47 | |||
48 | // BENGALI vowels [09BF 09C7 09C8] | ||
49 | else if ($lang=='bn') { | ||
50 | |||
51 | // Khanda Ta 09CE not in font -> replace with 09A4|09CD | ||
52 | $vstr = preg_replace('/09CE/','09A4 09CD 200D', $vstr); // mPDF 5.3.09 | ||
53 | |||
54 | // BENGALI double-part vowels [09CB 09C7 09BE][09CC 09C7 09D7] | ||
55 | $vstr = str_replace('09CB','09C7 09BE', $vstr); // convert to 2 parts | ||
56 | $vstr = str_replace('09CC','09C7 09D7', $vstr); // 09C7 pre-based is then shifted below | ||
57 | $prebasedvowels = "(09BF|09C7|09C8)"; | ||
58 | $nukta = "09BC"; | ||
59 | $halant = "09CD"; | ||
60 | // mPDF 5.0.044 | ||
61 | $bnfullcons = "0995|0996|0997|0998|0999|099A|099B|099C|099D|099F|09A0|09A1|09A2|09A3|09A4|09A5|09A6|09A7|09A8|09AA|09AB|09AC|09AD|09AE|09AF|09B0|09B2|09B6|09B7|09B8|09B9|09DC|09DD|09DF"; | ||
62 | $vstr = preg_replace('/([A-F0-9]{4}) '.$prebasedvowels.'/','\\2 \\1', $vstr); // vowel sign pre-based shift left | ||
63 | $vstr = preg_replace('/([A-F0-9]{4}) '.$prebasedvowels.' '.$nukta.'/','\\2 \\1 '.$nukta, $vstr); // before NUKTA | ||
64 | $vstr = preg_replace('/([A-F0-9]{4}) '.$halant.' '.$prebasedvowels.'/','\\2 \\1 '.$halant, $vstr); // before CHAR HALANT | ||
65 | // mPDF 5.0.044 | ||
66 | // .. and shifting left-based vowel further to the left in case 3 consonants together. | ||
67 | $vstr = preg_replace('/('.$bnfullcons.') '.$halant.' '.$prebasedvowels.'/','\\2 \\1 '.$halant, $vstr); | ||
68 | |||
69 | // mPDF 5.0.044 | ||
70 | // If left-based vowel has now been shifted to left of RA/Halant (09B0/09CD) | ||
71 | // Convert here to above-line form (E068) as it would get missed later | ||
72 | // e.g. 09B0 09CD 09AD 09C7 would be changed above => | ||
73 | // e.g. 09C7 09B0 09CD 09AD. The 09B0 09CD should => E068 | ||
74 | // ??? need to add 09BF as well (09BF|09C7|09C8) | ||
75 | $vstr = preg_replace('/(09C7|09C8) 09B0 09CD/', '\\1 E068', $vstr); | ||
76 | |||
77 | } | ||
78 | |||
79 | // GUJARATI pre-based vowel [0ABF] | ||
80 | else if ($lang=='gu') { | ||
81 | $prebasedvowels = "(0ABF)"; | ||
82 | $nukta = "0ABC"; | ||
83 | $halant = "0ACD"; | ||
84 | $vstr = preg_replace('/([A-F0-9]{4}) '.$prebasedvowels.'/','\\2 \\1', $vstr); // vowel sign pre-based shift left | ||
85 | $vstr = preg_replace('/([A-F0-9]{4}) '.$prebasedvowels.' '.$nukta.'/','\\2 \\1 '.$nukta, $vstr); // before NUKTA | ||
86 | $vstr = preg_replace('/([A-F0-9]{4}) '.$halant.' '.$prebasedvowels.'/','\\2 \\1 '.$halant, $vstr); // before CHAR HALANT | ||
87 | } | ||
88 | |||
89 | // GURMUKHI/PUNJABI pre-based vowel [0ABF] | ||
90 | else if ($lang=='pa') { | ||
91 | $prebasedvowels = "(0A3F)"; | ||
92 | $nukta = "0A3C"; | ||
93 | $halant = "0A4D"; | ||
94 | $vstr = preg_replace('/([A-F0-9]{4}) '.$prebasedvowels.'/','\\2 \\1', $vstr); // vowel sign pre-based shift left | ||
95 | $vstr = preg_replace('/([A-F0-9]{4}) '.$prebasedvowels.' '.$nukta.'/','\\2 \\1 '.$nukta, $vstr); // before NUKTA | ||
96 | $vstr = preg_replace('/([A-F0-9]{4}) '.$halant.' '.$prebasedvowels.'/','\\2 \\1 '.$halant, $vstr); // before CHAR HALANT | ||
97 | } | ||
98 | |||
99 | // TAMIL pre-based vowel [0ABF] | ||
100 | else if ($lang=='ta') { | ||
101 | // Shrii (Shree) | ||
102 | $vstr = preg_replace('/0BB6 0BCD 0BB0 0BC0/','E04B', $vstr); | ||
103 | |||
104 | // TAMIL double-part vowels [0BCA 0BC6 0BBE][0BCB 0BC7 0BBE][0BCC 0BC6 0BD7] | ||
105 | $vstr = preg_replace('/0BCA/','0BC6 0BBE', $vstr); // convert to 2 parts | ||
106 | $vstr = preg_replace('/0BCB/','0BC7 0BBE', $vstr); // pre-based is then shifted below | ||
107 | $vstr = preg_replace('/0BCC/','0BC6 0BD7', $vstr); | ||
108 | $prebasedvowels = "(0BC6|0BC7|0BC8)"; | ||
109 | // No nukta | ||
110 | $halant = "0BCD"; // Doesn't seem to move most in front of halanted consonants | ||
111 | $vstr = preg_replace('/([A-F0-9]{4}) '.$prebasedvowels.'/','\\2 \\1', $vstr); // vowel sign pre-based shift left | ||
112 | // ? Only for special case KSS (already moved to left of 0BB7) | ||
113 | $vstr = preg_replace('/0B95 '.$halant.' '.$prebasedvowels.' 0BB7/','\\1 0B95 '.$halant.' 0BB7', $vstr); | ||
114 | } | ||
115 | |||
116 | // ORIYA | ||
117 | else if ($lang=='or') { | ||
118 | // ORIYA double-part vowels [] | ||
119 | $vstr = str_replace('0B48','0B47 0B56', $vstr); // 2-part Vowel | ||
120 | $vstr = str_replace('0B4B','0B47 0B3E', $vstr); // 2-part Vowel | ||
121 | $vstr = str_replace('0B4C','0B47 0B57', $vstr); // 2-part Vowel | ||
122 | $orprebasedvowels = "(0B47)"; | ||
123 | // No nukta | ||
124 | $halant = "0B4D"; | ||
125 | $vstr = preg_replace('/([A-F0-9]{4}) '.$orprebasedvowels.'/','\\2 \\1', $vstr); // vowel sign pre-based shift left | ||
126 | $vstr = preg_replace('/([A-F0-9]{4}) '.$halant.' '.$orprebasedvowels.'/','\\2 \\1 '.$halant, $vstr); // before CHAR HALANT | ||
127 | $vstr = preg_replace('/([A-F0-9]{4}) '.$halant.' '.$orprebasedvowels.'/','\\2 \\1 '.$halant, $vstr); // before CHAR HALANT | ||
128 | } | ||
129 | |||
130 | // MALAYALAM | ||
131 | else if ($lang=='ml') { | ||
132 | // Chillus - old forms - remove ZWNJ after | ||
133 | // This font Volt rules recognises e.g. "Na Halant(Virama)" as ChilluN | ||
134 | $vstr = preg_replace('/(0D23 0D4D|0D28 0D4D|0D30 0D4D|0D32 0D4D|0D33 0D4D) 200D/','\\1', $vstr); | ||
135 | // See Chillus in Unicode [http://en.wikipedia.org/wiki/Malayalam_script] | ||
136 | $vstr = str_replace('0D7A','0D23 0D4D', $vstr); // [mlymChilluNn] | ||
137 | $vstr = str_replace('0D7B','0D28 0D4D', $vstr); // [mlymChilluN] | ||
138 | $vstr = str_replace('0D7C','0D30 0D4D', $vstr); // [mlymChilluR] | ||
139 | $vstr = str_replace('0D7D','0D32 0D4D', $vstr); // [mlymChilluL] | ||
140 | $vstr = str_replace('0D7E','0D33 0D4D', $vstr); // [mlymChilluLl] | ||
141 | /* | ||
142 | // Chillus - 0D7A-0D7E not in font directly, but as E005-E009 | ||
143 | $vstr = preg_replace('/0D23 0D4D 200D/','0D7A', $vstr); | ||
144 | $vstr = preg_replace('/0D28 0D4D 200D/','0D7B', $vstr); | ||
145 | $vstr = preg_replace('/0D30 0D4D 200D/','0D7C', $vstr); | ||
146 | $vstr = preg_replace('/0D32 0D4D 200D/','0D7D', $vstr); | ||
147 | $vstr = preg_replace('/0D33 0D4D 200D/','0D7E', $vstr); | ||
148 | |||
149 | $vstr = preg_replace('/0D7F/','E004', $vstr); // [mlymChilluK] | ||
150 | $vstr = preg_replace('/0D7A/','E005', $vstr); // [mlymChilluNn] | ||
151 | $vstr = preg_replace('/0D7B/','E006', $vstr); // [mlymChilluN] | ||
152 | $vstr = preg_replace('/0D7C/','E007', $vstr); // [mlymChilluR] | ||
153 | $vstr = preg_replace('/0D7D/','E008', $vstr); // [mlymChilluL] | ||
154 | $vstr = preg_replace('/0D7E/','E009', $vstr); // [mlymChilluLl] | ||
155 | */ | ||
156 | |||
157 | // MALAYALAM double-part vowels [] | ||
158 | $vstr = str_replace('0D4A','0D46 0D3E', $vstr); // 2-part Vowel | ||
159 | $vstr = str_replace('0D4B','0D47 0D3E', $vstr); // 2-part Vowel | ||
160 | $vstr = str_replace('0D4C','0D46 0D57', $vstr); // 2-part Vowel | ||
161 | $mlprebasedvowels = "(0D46|0D47|0D48)"; | ||
162 | // No nukta | ||
163 | $halant = "0D4D"; | ||
164 | $vstr = preg_replace('/([A-F0-9]{4}) '.$mlprebasedvowels.'/','\\2 \\1', $vstr); // vowel sign pre-based shift left | ||
165 | $vstr = preg_replace('/([A-F0-9]{4}) '.$halant.' '.$mlprebasedvowels.'/','\\2 \\1 '.$halant, $vstr); // before CHAR HALANT | ||
166 | } | ||
167 | |||
168 | // TELUGU | ||
169 | else if ($lang=='te') { | ||
170 | // TELUGU double-part vowels [0C48 -> 0C46 0C56] | ||
171 | $vstr = str_replace('0C48','0C46 0C56', $vstr); // 2-part Vowel | ||
172 | $prebasedvowels = "(0C46)"; | ||
173 | $abvvowels = "(0C3E|0C3F|0C40|0C46|0C47|0C4A|0C4B|0C4C|0C55)"; | ||
174 | // No nukta | ||
175 | $halant = "0C4D"; | ||
176 | $tefullforms = "0C15|0C17|0C18|0C1A|0C1B|0C1C|0C1D|0C20|0C21|0C22|0C24|0C25|0C26|0C27|0C28|0C2A|0C2B|0C2D|0C2E|0C2F|0C30|0C33|0C35|0C36|0C37|0C38|0C39|E028|E029|E02A|E02B|E078|E07A|E07B"; | ||
177 | $vstr = preg_replace('/('.$tefullforms .') '.$halant.' ('.$tefullforms .') '.$abvvowels .'/','\\1 \\3 '.$halant.' \\2', $vstr); // before HALANT | ||
178 | } | ||
179 | |||
180 | |||
181 | // KANNADA | ||
182 | else if ($lang=='kn') { | ||
183 | // KANNADA double-part vowels [0CC8 -> 0CC6 0CD6] | ||
184 | $vstr = str_replace('0CC0','0CBF 0CD5', $vstr); // 2-part Vowel | ||
185 | $vstr = str_replace('0CC7','0CC6 0CD5', $vstr); // 2-part Vowel | ||
186 | $vstr = str_replace('0CC8','0CC6 0CD6', $vstr); // 2-part Vowel AI - no glyph for single | ||
187 | $vstr = str_replace('0CCA','0CC6 0CC2', $vstr); // 2-part Vowel | ||
188 | $vstr = str_replace('0CCB','0CC6 0CC2 0CD5', $vstr); // 2-part Vowel | ||
189 | $prebasedvowels = "(0CBF|0CC6)"; | ||
190 | $halant = "0CCD"; | ||
191 | } | ||
192 | |||
193 | |||
194 | //============================ | ||
195 | |||
196 | // SPECIALS | ||
197 | |||
198 | // DEVANAGARI Ra Halant Ra | ||
199 | if ($lang=='hi') { | ||
200 | $vstr = str_replace('0930 094D 0930','E05D 0930', $vstr); // Ra Halant Ra => halfRa FullRa | ||
201 | } | ||
202 | |||
203 | // GUJARATI | ||
204 | if ($lang=='gu') { | ||
205 | $vstr = str_replace('0AB0 0AC2','E02E', $vstr); // Ra VowelUu => SpecialForm RaUu | ||
206 | } | ||
207 | |||
208 | // TELUGU Ra Halant <Consonant> Halant => halfRa Halant<Consonant> Halant | ||
209 | if ($lang=='te') { | ||
210 | $vstr = preg_replace('/0C30 0C4D ([A-F0-9]{4}) 0C4D/','E021 0C4D \\1 0C4D', $vstr); | ||
211 | } | ||
212 | |||
213 | // KANNADA | ||
214 | // Reph at end of word becomes E0CC instead of E00B | ||
215 | if ($lang=='kn') { | ||
216 | $vstr = str_replace('0CB0 0CCD 0020','E0CC 0020', $vstr); // mPDF 5.3.87 | ||
217 | } | ||
218 | |||
219 | |||
220 | //============================ | ||
221 | // MAIN BIT FROM VOLT RULES | ||
222 | foreach($voltdata[$font] AS $rid=>$reps) { | ||
223 | //echo $rid . ': ' . $vstr.'<br />'; | ||
224 | $vstr = preg_replace('/'.$reps['match'].'/',$reps['replace'], $vstr); | ||
225 | } | ||
226 | //echo $vstr.'<br />'; exit; | ||
227 | |||
228 | |||
229 | //============================ | ||
230 | |||
231 | // SPECIALS | ||
232 | |||
233 | // KANNADA | ||
234 | // <Base> <BelowBase1> [<BelowBase2> ] MatraI -> <Base/MatraI ligature> <Belowbase1> etc | ||
235 | if ($lang=='kn') { | ||
236 | $matraI = "0CBF"; | ||
237 | $knbase = preg_split('/\|/', "0C95|0C96|0C97|0C98|0C9A|0C9B|0C9C|0C9D|0CA0|0CA1|0CA2|0CA3|0CA4|0CA5|0CA6|0CA7|0CA8|0CAA|0CAB|0CAC|0CAD|0CAE|0CAF|0CB0|0CB2|0CB3|0CB5|0CB6|0CB7|0CB8|0CB9|E0A3|E07D|E07E"); | ||
238 | $knmatraIligature = preg_split('/\|/', "E082|E083|E084|E085|E086|E087|E088|E089|E08A|E08B|E08C|E08D|E08E|E08F|E090|E091|E092|E093|E094|E095|E096|E097|E098|E099|E09A|E09B|E09C|E09D|E09E|E09F|E0A0|E0A4|E0A1|E0A2"); | ||
239 | $belowbase1 = "E02E|E02F|E030|E031|E032|E033|E034|E035|E036|E037|E038|E039|E03A|E03B|E03C|E03D|E03E|E03F|E040|E041|E042|E043|E044|E045|E046|E047|E048|E049|E04A|E04B|E04C|E04D|E04E|E04F|E050|E081"; | ||
240 | $belowbase2 = "E052|E053|E054|E055|E056|E057|E058|E059|E05A|E05B|E05C|E05D|E05E|E05F|E060|E061|E062|E063|E064|E065|E066|E067|E068|E069|E06A|E06B|E06C|E06D|E06E|E06F|E070|E071|E072|E073|E074|E081"; | ||
241 | for ($i=0; $i<count($knbase);$i++) { | ||
242 | $vstr = preg_replace('/'.$knbase[$i].' ('.$belowbase1.') ('.$belowbase2.') '.$matraI.'/', $knmatraIligature[$i].' \\1 \\2', $vstr); | ||
243 | $vstr = preg_replace('/'.$knbase[$i].' ('.$belowbase1.') '.$matraI.'/', $knmatraIligature[$i].' \\1', $vstr); | ||
244 | } | ||
245 | } | ||
246 | |||
247 | // KANNADA | ||
248 | // [KanTtaFull] [matraI] => [KanTtaPartial] [matraI] | ||
249 | if ($lang=='kn') { | ||
250 | $vstr = preg_replace('/0C9F '.$matraI.'/', 'E015 '.$matraI, $vstr); | ||
251 | } | ||
252 | |||
253 | // ORIYA | ||
254 | if ($lang=='or') { | ||
255 | // SpecialCase Ra[0B30] Halant still left before [oryaFullNnNna] => E00F | ||
256 | $vstr = preg_replace('/0B30 '.$halant.' E00F/','E00F E069', $vstr); // convert to Reph | ||
257 | } | ||
258 | |||
259 | //============================ | ||
260 | // SHIFT REPH | ||
261 | |||
262 | // DEVANAGARI Shift Reph [E015] | ||
263 | if ($lang=='hi') { | ||
264 | // FIRSTLY - halfRa = E05D - Change this to Reph [E015] | ||
265 | $himatchhalfforms = "E043|E044|E045|E046|E047|E048|E049|E04A|E04B|E04C|E04D|E04E|E04F|E050|E051|E052|E053|E054|E055|E056|E057|E058|E059|E05A|E05B|E05C|E05D|E05E|E05F|E060|E061|E062|E063|E064|E065|E066|E067|E068|E069|E06A|E06B|E06C|E06D|E06E|E06F|E070|E071|E072|E073|E074|E075|E076|E077|E078|E079|E07A|E07B|E07C|E07D|E07E|E07F|E080|E081|E082|E083|E084|E085|E086|E087|E088|E089|E08A|E0D3|E0D4|E0D5|E0D6|E0D7|E0D8|E0D9|E0DA|E0DB|E0DC|E0DD|E0DE|E0DF|E0E0|E0E1|E0E2|E0E3|E0E4|E0E5|E0E6|E0E7|E0E8|E0E9|E0EA|E0EB|E0EC|E0ED|E0EE|E0EF|E0F0|E0F1|E0F2|E0F3|E0F4|E0F5|E0F6|E0F7|E0F8|E0F9|E0FA|E0FB|E0FC|E0FD|E0FE|E0FF|E100|E101|E102|E103|E104|E105|E106|E107|E108|E109|E10A|E10B|E10C|E10D|E10E|E10F|E110|E111|E112|E113|E114|E115|E116|E117|E118|E119|E11A|E13D|E13E|E13F|E140|E141|E142|E143|E144|E145"; | ||
266 | $himatchfullforms = "0915|0916|0917|0918|0919|091A|091B|091C|091D|091E|091F|0920|0921|0922|0923|0924|0925|0926|0927|0928|092A|092B|092C|092D|092E|092F|0930|0932|0933|0935|0936|0937|0938|0939|E028|E029|0958|0959|095A|E02A|E02B|E02C|E02D|095B|E02E|E02F|E030|E031|095C|095D|E032|E033|E034|E035|E036|0929|E037|095E|E038|E039|E03A|095F|0931|E03B|0934|E03C|E03D|E03E|E03F|E040|E041|E042|E08B|E08C|E08D|E08E|E08F|E090|E091|E092|E093|E094|E095|E096|E097|E098|E099|E09A|E09B|E09C|E09D|E09E|E09F|E0A0|E0A1|E0A2|E0A3|E0A4|E0A5|E0A6|E0A7|E0A8|E0A9|E0AA|E0AB|E0AC|E0AD|E0AE|E0AF|E0B0|E0B1|E0B2|E0B3|E0B4|E0B5|E0B6|E0B7|E0B8|E0B9|E0BA|E0BB|E0BC|E0BD|E0BE|E0BF|E0C0|E0C1|E0C2|E0C3|E0C4|E0C5|E0C6|E0C7|E0C8|E0C9|E0CA|E0CB|E0CC|E0CD|E0CE|E0CF|E0D0|E0D1|E0D2|E11E|E11F|E120|E121|E122|E123|E124|E125|E126|E127|E128|E129|E12A|E12B|E12C|E12D|E12E|E12F|E130|E131|E132|E133"; | ||
267 | $vstr = preg_replace('/E05D ('.$himatchhalfforms.'|'.$himatchfullforms.')/', 'E015 \\1', $vstr); | ||
268 | |||
269 | // Reph = E015 - Shift Right to just after end of syllable | ||
270 | // FullAllForms + HalfAllForms + 093E matraA | ||
271 | while(preg_match('/E015 ('.$himatchhalfforms.')/', $vstr)) { | ||
272 | $vstr = preg_replace('/E015 ('.$himatchhalfforms.')/', '\\1 E015', $vstr); | ||
273 | } | ||
274 | $vstr = preg_replace('/E015 ('.$himatchfullforms.')/', '\\1 E015', $vstr); | ||
275 | |||
276 | // Now shift it beyond post-based vowels // ??? Need to add others e.g. 0949,094A,094B,094C + presentation forms like E198 | ||
277 | $vstr = str_replace('E015 093E', '093E E015', $vstr); | ||
278 | $vstr = preg_replace('/E015 (0940|E194|E195|E196|E197|E198)/', '\\1 E014', $vstr); // (Small) reph [E014] to Right of matraI | ||
279 | $vstr = str_replace('E015 0947', '0947 E014', $vstr); // (Small) reph [E014] to Right of matraI | ||
280 | } | ||
281 | |||
282 | // BENGALI Shift Reph [E068] | ||
283 | else if ($lang=='bn') { | ||
284 | $bnfullconjuncts = "E002|E003|E004|E041|E042|E043|E044|E045|E046|E047|E048|E049|E04A|E04B|E04C|E04D|E04E|E04F|E050|E051|E052|E053|E054|E055|E056|E057|E058|E059|E05A|E05B|E05C|E05D|E05E|E05F|E060|E061|E062|E063|E064|E065|E06A|E06B|E06C|E06D|E06E|E06F|E070|E071|E072|E073|E074|E075|E076|E077|E078|E079|E07A|E07B|E07C|E07D|E07E|E07F|E080|E081|E082|E083|E084|E085|E086|E087|E088|E089|E08A|E08B|E08C|E08D|E08E|E08F|E090|E091|E092|E093|E094|E095|E096|E097|E098|E099|E09A|E09B|E09C|E09D|E09E|E09F|E0A0|E0A1|E0A2|E0A3|E0A4|E0A5|E0A6|E0A7|E0A8|E0A9|E0AA|E0AB|E0AC|E0AD|E0AE|E0AF|E0B0|E0B1|E0B2|E0B3|E0B4|E0B5|E0B6|E0B7|E0B8|E0B9|E0BA|E0BB|E0BC|E0BD|E0BE|E0BF|E0C0|E0C1|E0C2|E0C3|E0C4|E0C5|E0C6|E0C7|E0C8|E0C9|E0CA|E0CB|E0CC|E0CD|E0CE|E0CF|E0D0|E0D1|E0D2|E0D3|E0D4|E0D5|E0D6|E0D7|E0D8|E0D9|E0DA|E0DB|E0DC|E0DD|E0DE|E0DF|E0E0|E0E1|E0E2|E0E3|E0E4|E0E5|E0E6|E0E7|E0E8|E0E9|E0EA|E0EB|E0EC|E0ED|E0EE|E0EF|E0F0|E0F1|E0F2|E0F3|E0F4|E0F5|E0F6|E0F7|E0F8|E0F9|E0FA|E0FB|E0FC|E0FD|E0FE|E0FF|E100|E101|E102|E103|E104|E105|E106|E107|E108|E109|E10A|E10B|E10C|E10D|E10E|E10F|E110|E111|E112|E113|E114|E115|E116|E117|E118|E119|E11A|E11B|E11C|E11D|E11E|E11F|E120|E121|E122|E123|E124|E125|E126|E127|E128|E129|E12A|E12B|E12C|E12D|E12E|E12F|E130|E131|E132|E133|E134|E135|E136|E137|E138|E139|E13A|E13B|E13C|E13D|E13E|E13F|E140|E141|E142|E143|E144|E145|E146|E147|E148|E149|E14A|E14B|E14C|E14D|E14E|E14F|E150|E151|E152|E153|E154|E155|E156|E157|E158|E159|E15A|E15B|E15C|E15D|E15E|E15F|E160|E161|E162|E163|E164|E165|E166|E167|E168|E169|E16A|E16B|E16C|E16D|E16E|E16F|E170|E171|E172|E173|E174|E175|E176|E177|E178|E179|E17A|E17B|E17C|E17D|E17E|E17F|E180|E181|E182|E183|E184|E185|E186|E187|E188|E189|E18A|E18B|E18C|E18D|E18E|E18F|E190|E191|E192|E193|E194|E195|E196|E197|E198|E199|E19A"; | ||
285 | // $bnfullcons - set above; | ||
286 | $vstr = preg_replace('/E068 ('.$bnfullconjuncts.'|'.$bnfullcons.')/', '\\1 E068', $vstr); | ||
287 | // ? Need to shift it beyond post-base vowels 09BE, 09C0, 09D7 haven't found so can't test?? | ||
288 | $vstr = preg_replace('/E068 (09BE|09C0|09D7)/', '\\1 E068', $vstr); | ||
289 | } | ||
290 | |||
291 | // GUJARATI Shift Reph [E032] | ||
292 | else if ($lang=='gu') { | ||
293 | $gufullforms = "0A95|0A96|0A97|0A98|0A99|0A9A|0A9B|0A9C|0A9D|0A9E|0A9F|0AA0|0AA1|0AA2|0AA3|0AA4|0AA5|0AA6|0AA7|0AA8|0AAA|0AAB|0AAC|0AAD|0AAE|0AAF|0AB0|0AB2|0AB3|0AB5|0AB6|0AB7|0AB8|0AB9|E002|E003|E004|E005|E006|E007|E008|E009|E00A|E00B|E00C|E00D|E00E|E00F|E010|E011|E012|E013|E014|E015|E016|E017|E018|E019|E01A|E01B|E01C|E01D|E01E|E01F|E020|E021|E022|E023|E024|E025|E026|E027|E05E|E05F|E060|E061|E062|E063|E064|E065|E066|E067|E068|E069|E06A|E06B|E06C|E06D|E06E|E06F|E070|E071|E072|E073|E074|E075|E076|E077|E078|E079|E07A|E07B|E07C|E07D|E07E|E07F|E080|E081|E082|E083|E084|E085|E086|E087|E088|E089|E08A|E08B|E08C|E08D|E08E|E08F|E090|E091|E092|E093|E094|E095|E096|E097|E098|E099|E09A|E09B|E09C|E09D|E09E|E09F|E0A0|E0A1|E0A2|E0A3|E0A4|E0A5"; | ||
294 | $vstr = preg_replace('/E032 ('.$gufullforms.')/', '\\1 E032', $vstr); | ||
295 | // Now shift it beyond post-based vowels // ??? Need to add others e.g. 0949,094A,094B,094C + presentation forms like E198 | ||
296 | // ? Need to shift it beyond post-base vowels 0ABE, 0AC0 haven't found so can't test?? | ||
297 | $vstr = preg_replace('/E032 (0ABE|0AC0)/', '\\1 E032', $vstr); | ||
298 | } | ||
299 | |||
300 | |||
301 | // TELUGU Shift Reph to LEFT [E046|E069|E077] [TelRaSmallOne] => E046 [TelRaSmallTwo] => E069 [TelRaSmallThree] => E077 | ||
302 | else if ($lang=='te') { | ||
303 | // tefullforms defined earlier | ||
304 | $tepartialforms = "E00D|E00E|E00F|E010|E011|E012|E013|E014|E015|E016|E017|E018|E019|E01A|E01B|E01C|E01D|E01E|E01F|E020|E021|E022|E023|E024|E025|E026|E027|E07C|E07D|E07E"; | ||
305 | $matraligs = "E07F|E080|E081|E082|E083|E084|E085|E086|E087|E088|E089|E08A|E08B|E08C|E08D|E08E|E08F|E090|E091|E092|E093|E094|E095|E096|E097|E098|E099|E09A|E09B|E09C|E09D|E09E|E09F|E0A0|E0A1|E0A2|E0A3|E0A4|E0A5|E0A6|E0A7|E0A8|E0A9|E0AA|E0AB|E0AC|E0AD|E0AE|E0AF"; | ||
306 | $tevowels = "0C3E|0C3F|0C40|0C46|0C47|0C56|0C4A|0C4B|0C4C" | ||
307 | ."|0C41|0C42|0C43|0C44"; // post matras | ||
308 | $vstr = preg_replace('/('.$tevowels.') (E046|E069|E077)/', '\\2 \\1', $vstr); | ||
309 | while(preg_match('/('.$tepartialforms.') (E046|E069|E077)/', $vstr)) { | ||
310 | $vstr = preg_replace('/('.$tepartialforms.') (E046|E069|E077)/', '\\2 \\1', $vstr); | ||
311 | } | ||
312 | $vstr = preg_replace('/('.$tefullforms .'|'.$matraligs.') (E046|E069|E077)/', '\\2 \\1', $vstr); | ||
313 | } | ||
314 | |||
315 | |||
316 | // KANNADA Shift Reph to RIGHT [E00B] | ||
317 | else if ($lang=='kn') { | ||
318 | $knfullforms = "0C95|0C96|0C97|0C98|0C99|0C9A|0C9B|0C9C|0C9D|0C9E|0C9F|0CA0|0CA1|0CA2|0CA3|0CA4|0CA5|0CA6|0CA7|0CA8|0CAA|0CAB|0CAC|0CAD|0CAE|0CAF|0CB0|0CB1|0CB2|0CB3|0CB5|0CB6|0CB7|0CB8|0CB9|E07D|E07E|E0A3"; | ||
319 | $knpartialforms = "E00C|E00D|E00E|E00F|E010|E011|E012|E013|E014|0C9E|E015|E016|E017|E018|E019|E01A|E01B|E01C|E01D|E01E|E01F|E020|E021|E022|E023|E024|E025|E026|E027|E028|E029|E02A|E02B|E02C|E02D|E07F"; | ||
320 | while(preg_match('/E00B ('.$knpartialforms.')/', $vstr)) { | ||
321 | $vstr = preg_replace('/E00B ('.$knpartialforms.')/', '\\1 E00B', $vstr); | ||
322 | } | ||
323 | // mPDF 5.3.47 Also move Reph to right of matraIligatures | ||
324 | $knfullforms .= "|E082|E083|E084|E085|E086|E087|E088|E089|E08A|E08B|E08C|E08D|E08E|E08F|E090|E091|E092|E093|E094|E095|E096|E097|E098|E099|E09A|E09B|E09C|E09D|E09E|E09F|E0A0|E0A4|E0A1|E0A2"; | ||
325 | $vstr = preg_replace('/E00B ('.$knfullforms.')/', '\\1 E00B', $vstr); | ||
326 | |||
327 | // ? Need to shift it beyond base or below-base forms - haven't found so can't test?? | ||
328 | // mPDF 5.3.87 | ||
329 | // E004 added to list (which is a transformed version of 0CBE) | ||
330 | $knvowels = "0CBE|0CC0|0CC1|0CC2|0CC3|0CC4|0CC7|0CC8|0CCA|0CCB|0CD5|0CD6|E004"; | ||
331 | $vstr = preg_replace('/E00B ('.$knvowels.')/', '\\1 E00B', $vstr); | ||
332 | } | ||
333 | |||
334 | |||
335 | // ORIYA Shift Reph to RIGHT [E069|E06A|E06B|E06C] | ||
336 | else if ($lang=='or') { | ||
337 | $orrephs = "E069|E06A|E06B|E06C"; | ||
338 | $orfullforms = "0B15|0B16|0B17|0B18|0B19|0B1A|0B1B|0B1C|0B1D|0B1E|0B1F|0B20|0B21|0B22|0B23|0B24|0B25|0B26|0B27|0B28|0B29|0B2A|0B2B|0B2C|0B2D|0B2E|0B2F|0B30|0B31|0B32|0B33|0B34|0B35|0B36|0B37|0B38|E003|E004|E005|E006|E007|E008|E009|E00A|E00B|E00C|E00D|E00E|E00F|E010|E011|E012|E013|E014|E015|E016|E017|E018|E019|E01A|E01B|E01C|E01D|E01E|E01F|E020|E021|E022|E023|E024|E025|E026|E027|E028|E029|E02A|E02B|E02C|E02D|E02E|E02F|E030|E031|E032|E033|E034|E035|E036|E037"; | ||
339 | // E123 - E147 FullHalant forms ? add to FullForms | ||
340 | $orpartialforms = "E090|E091|E092|E093|E094|E095|E096|E097|E098|E099|E09A|E09B|E09C|E09D|E09E|E09F|E0A0|E0A1|E0A2|E0A3|E0A4|E0A5|E0A6|E0A7|E0A8|E0A9|E0AA|E0AB|E0AC|E0AD|E0AE|E0AF|E0B0|E0B1|E0B2|E0B3|E0B4|E0B5|E0B6|E0B7|E0B8|E0B9|E0BA|E0BB|E0BC|E0BD|E0BE|E0BF|E0C0|E0C1|E0C2|E0C3|E0C4|E0C5|E0C6|E0C7|E0C8|E0C9|E0CA|E0CB|E0CC|E0CD|E0CE|E0CF|E0D0|E0D1|E0D2|E0D3|E0D4|E0D5|E0D6|E0D7|E0D8|E0D9|E0DA|E0DB|E0DC|E0DD|E0DE|E0DF|E0E0|E0E1|E0E2|E0E3|E0E4|E0E5|E0E6|E0E7|E0E8|E0E9|E0EA|E0EB|E0EC|E0ED|E0EE|E0EF|E0F0|E0F1|E0F2|E0F3|E0F4|E0F5"; | ||
341 | |||
342 | // Combined MatraIReph[E06D] split [0B3F & E069] to allow reph to be shifted forwards | ||
343 | $vstr = preg_replace('/('.$orfullforms.') E06D ('.$orfullforms.') 0B3E/', '\\1 0B3F E069 \\2 0B3E', $vstr); | ||
344 | |||
345 | |||
346 | while(preg_match('/('.$orrephs.') ('.$orpartialforms.')/', $vstr)) { | ||
347 | $vstr = preg_replace('/('.$orrephs.') ('.$orpartialforms.')/', '\\2 \\1', $vstr); | ||
348 | } | ||
349 | $vstr = preg_replace('/('.$orrephs.') ('.$orfullforms.')/', '\\2 \\1', $vstr); | ||
350 | |||
351 | |||
352 | // Combine Reph and MatraI | ||
353 | $vstr = str_replace('E069 0B3F', 'E06D', $vstr); // Reph and MatraI -> MatraIReph | ||
354 | $vstr = str_replace('E06A 0B3F', 'E06E', $vstr); // Reph and MatraI -> MatraIReph | ||
355 | $vstr = str_replace('E06B 0B3F', 'E06F', $vstr); // Reph and MatraI -> MatraIReph | ||
356 | } | ||
357 | |||
358 | |||
359 | // MALAYALAM Shift Reph to LEFT [E00E] (mlylmRaVattu) | ||
360 | else if ($lang=='ml') { | ||
361 | $halant = "0D4D"; | ||
362 | $vstr = preg_replace('/([A-F0-9]{4}) '.$halant.' 0D30/','E00E \\1', $vstr); // 0D30 = Ra | ||
363 | $vstr = preg_replace('/([A-F0-9]{4}) '.$halant.' '.$mlprebasedvowels .' 0D30/','\\2 E00E \\1', $vstr); // 0D30 = Ra | ||
364 | |||
365 | $mlfullforms = "0D15|0D16|0D17|0D18|0D19|0D1A|0D1B|0D1C|0D1D|0D1E|0D1F|0D20|0D21|0D22|0D23|0D24|0D25|0D26|0D27|0D28|0D2A|0D2B|0D2C|0D2D|0D2E|0D2F|0D30|0D31|0D32|0D33|0D34|0D35|0D36|0D37|0D38|0D39" | ||
366 | ."|E010|E011|E012|E013|E014|E015|E016|E017|E018|E019|E01A|E01B|E01C|E01D|E01E|E01F|E020|E021|E022|E023|E024|E025|E026|E027|E028|E029|E02A|E02B|E02C|E02D|E02E|E02F|E030|E031|E032|E033|E034|E035|E036|E037|E038|E039|E03A|E03B|E03C|E03D|E03E|E03F|E040|E041|E042|E043|E044|E045|E046|E047|E048|E049|E04A|E04B|E04C|E04D|E04E|E04F|E050|E051|E052|E053|E054|E055|E056|E057|E058|E059|E05A|E05B|E05C|E05D|E05E|E05F|E060|E061|E062|E063|E064|E065|E066|E067|E068|E069|E06A|E06B|E06C|E06D|E06E|E06F|E070|E071|E072|E073|E074|E075|E076|E077|E078|E079|E07A|E07B|E07C|E07D"; | ||
367 | // = FullConsonants + FullConjuncts | ||
368 | |||
369 | // = Add Chillu characters // mPDF 5.0.024 | ||
370 | $mlfullforms .= "|E004|E005|E006|E007|E008|E009"; | ||
371 | while(preg_match('/('.$mlfullforms.') E00E/', $vstr)) | ||
372 | $vstr = preg_replace('/('.$mlfullforms.') E00E/', 'E00E \\1', $vstr); | ||
373 | } | ||
374 | |||
375 | //============================ | ||
376 | |||
377 | // SHIFT post-based vowels to Left of SmallForms (NOT to left of full forms) | ||
378 | |||
379 | // TELUGU Shift | ||
380 | if ($lang=='te') { | ||
381 | // NB $tevowels defined above | ||
382 | // NB $tefullforms defined above | ||
383 | $tebelowbase1 = "E02C|E02D|E02E|E02F|E030|E031|E032|E033|E034|E035|E036|E037|E038|E039|E03A|E03B|E03C|E03D|E03E|E03F|E040|E041|E042|E043|E044|E045|E046|E047|E048|E049|E04A|E04B|E04C|E04D|E04E"; //'Small1KaToHa' | ||
384 | $tebelowbase2 = "E04F|E050|E051|E052|E053|E054|E055|E056|E057|E058|E059|E05A|E05B|E05C|E05D|E05E|E05F|E060|E061|E062|E063|E064|E065|E066|E067|E068|E069|E06A|E06B|E06C|E06D|E06E|E06F|E070|E071"; // 'Small2KaToHa' | ||
385 | $vstr = preg_replace('/('.$tebelowbase2.') ('.$tevowels.')/', '\\2 \\1', $vstr); | ||
386 | $vstr = preg_replace('/('.$tebelowbase1.') ('.$tevowels.')/', '\\2 \\1', $vstr); | ||
387 | } | ||
388 | |||
389 | |||
390 | // KANNADA Shift | ||
391 | else if ($lang=='kn') { | ||
392 | $knvowels = "0CBE|0CC0|0CC1|0CC2|0CC3|0CC4|0CC7|0CC8|0CCA|0CCB|0CD5|0CD6" | ||
393 | // mPDF 5.3.87 Shouldn't swop E082 and E047 (belowbase1) below | ||
394 | // E082 is a matraIligature | ||
395 | // ."|E082|E083|E084|E085|E086|E087|E088|E089|E08A|E08B|E08C|E08D|E08E|E08F|E090|E091|E092|E093|E094|E095|E096|E097|E098|E099|E09A|E09B|E09C|E09D|E09E|E09F|E0A0|E0A1|E0A2|E0A3|E0A4|E0A5|E0A6|E0A7|E0A8|E0A9|E0AA|E0AB" | ||
396 | ."|E004|E007|E008|E009|E00A"; | ||
397 | |||
398 | |||
399 | // NB $knvowels defined above | ||
400 | // NB $fullforms defined above | ||
401 | // $belowbase1/2 defined above | ||
402 | $vstr = preg_replace('/('.$belowbase2.') ('.$knvowels.')/', '\\2 \\1', $vstr); | ||
403 | // mPDF 5.3.87 | ||
404 | $vstr = preg_replace('/('.$belowbase1.') ('.$knvowels.')/', '\\2 \\1', $vstr); | ||
405 | |||
406 | //$vstr = preg_replace('/('.$fullforms.') ('.$knvowels.')/', '\\2 \\1', $vstr); | ||
407 | } | ||
408 | |||
409 | //============================ | ||
410 | // Clear unwanted ZWJ, ZWNJ | ||
411 | // MALAYALAM | ||
412 | if ($lang=='ml') { | ||
413 | $vstr = preg_replace('/(200C|200D) /','', $vstr); | ||
414 | } | ||
415 | |||
416 | //============================ | ||
417 | // END & PUT IT BACK TOGETHER | ||
418 | $vstr = preg_replace('/^0020 (.*) 0020$/', '\\1', $vstr); | ||
419 | |||
420 | $varr = explode(" ",$vstr); | ||
421 | $e = ''; | ||
422 | foreach($varr AS $v) { | ||
423 | $e.=code2utf(hexdec($v)); | ||
424 | } | ||
425 | //============================ | ||
426 | |||
427 | return $e; | ||
428 | } | ||
429 | |||
430 | |||
431 | } | ||
432 | |||
433 | ?> \ No newline at end of file | ||
diff --git a/inc/3rdparty/libraries/mpdf/classes/meter.php b/inc/3rdparty/libraries/mpdf/classes/meter.php new file mode 100644 index 00000000..46fa9d5a --- /dev/null +++ b/inc/3rdparty/libraries/mpdf/classes/meter.php | |||
@@ -0,0 +1,224 @@ | |||
1 | <?php | ||
2 | |||
3 | class meter { | ||
4 | |||
5 | |||
6 | function __construct() { | ||
7 | |||
8 | } | ||
9 | |||
10 | function makeSVG($tag, $type, $value, $max, $min, $optimum, $low, $high) { | ||
11 | $svg = ''; | ||
12 | if ($tag == 'meter') { | ||
13 | |||
14 | if ($type=='2') { | ||
15 | ///////////////////////////////////////////////////////////////////////////////////// | ||
16 | ///////// CUSTOM <meter type="2"> | ||
17 | ///////////////////////////////////////////////////////////////////////////////////// | ||
18 | $h = 10; | ||
19 | $w = 160; | ||
20 | $border_radius = 0.143; // Factor of Height | ||
21 | |||
22 | $svg = '<?xml version="1.0" encoding="UTF-8"?> | ||
23 | <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||
24 | <svg width="'.$w.'px" height="'.$h.'px" viewBox="0 0 '.$w.' '.$h.'" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ><g> | ||
25 | |||
26 | |||
27 | <defs> | ||
28 | <linearGradient id="GrGRAY" x1="0" y1="0" x2="0" y2="1" gradientUnits="boundingBox"> | ||
29 | <stop offset="0%" stop-color="rgb(222, 222, 222)" /> | ||
30 | <stop offset="20%" stop-color="rgb(232, 232, 232)" /> | ||
31 | <stop offset="25%" stop-color="rgb(232, 232, 232)" /> | ||
32 | <stop offset="100%" stop-color="rgb(182, 182, 182)" /> | ||
33 | </linearGradient> | ||
34 | |||
35 | </defs> | ||
36 | '; | ||
37 | $svg .= '<rect x="0" y="0" width="'.$w.'" height="'.$h.'" fill="#f4f4f4" stroke="none" />'; | ||
38 | |||
39 | // LOW to HIGH region | ||
40 | //if ($low && $high && ($low != $min || $high != $max)) { | ||
41 | if ($low && $high) { | ||
42 | $barx = (($low-$min) / ($max-$min) ) * $w; | ||
43 | $barw = (($high-$low) / ($max-$min) ) * $w; | ||
44 | $svg .= '<rect x="'.$barx.'" y="0" width="'.$barw.'" height="'.$h.'" fill="url(#GrGRAY)" stroke="#888888" stroke-width="0.5px" />'; | ||
45 | } | ||
46 | |||
47 | // OPTIMUM Marker (? AVERAGE) | ||
48 | if ($optimum) { | ||
49 | $barx = (($optimum-$min) / ($max-$min) ) * $w; | ||
50 | $barw = $h/2; | ||
51 | $barcol = '#888888'; | ||
52 | $svg .= '<rect x="'.$barx.'" y="0" rx="'.($h*$border_radius).'px" ry="'.($h*$border_radius).'px" width="'.$barw.'" height="'.$h.'" fill="'.$barcol.'" stroke="none" />'; | ||
53 | } | ||
54 | |||
55 | // VALUE Marker | ||
56 | if ($value) { | ||
57 | if ($min != $low && $value < $low) { $col = 'orange'; } | ||
58 | else if ($max != $high && $value > $high) { $col = 'orange'; } | ||
59 | else { $col = '#008800'; } | ||
60 | $cx = (($value-$min) / ($max-$min) ) * $w; | ||
61 | $cy = $h/2; | ||
62 | $rx = $h/3.5; | ||
63 | $ry = $h/2.2; | ||
64 | $svg .= '<ellipse fill="'.$col.'" stroke="#000000" stroke-width="0.5px" cx="'.$cx.'" cy="'.$cy.'" rx="'.$rx.'" ry="'.$ry.'"/>'; | ||
65 | } | ||
66 | |||
67 | // BoRDER | ||
68 | $svg .= '<rect x="0" y="0" width="'.$w.'" height="'.$h.'" fill="none" stroke="#888888" stroke-width="0.5px" />'; | ||
69 | |||
70 | $svg .= '</g></svg>'; | ||
71 | } | ||
72 | else { | ||
73 | ///////////////////////////////////////////////////////////////////////////////////// | ||
74 | ///////// DEFAULT <meter> | ||
75 | ///////////////////////////////////////////////////////////////////////////////////// | ||
76 | $h = 10; | ||
77 | $w = 50; | ||
78 | $border_radius = 0.143; // Factor of Height | ||
79 | |||
80 | $svg = '<?xml version="1.0" encoding="UTF-8"?> | ||
81 | <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||
82 | <svg width="'.$w.'px" height="'.$h.'px" viewBox="0 0 '.$w.' '.$h.'" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ><g> | ||
83 | |||
84 | <defs> | ||
85 | <linearGradient id="GrGRAY" x1="0" y1="0" x2="0" y2="1" gradientUnits="boundingBox"> | ||
86 | <stop offset="0%" stop-color="rgb(222, 222, 222)" /> | ||
87 | <stop offset="20%" stop-color="rgb(232, 232, 232)" /> | ||
88 | <stop offset="25%" stop-color="rgb(232, 232, 232)" /> | ||
89 | <stop offset="100%" stop-color="rgb(182, 182, 182)" /> | ||
90 | </linearGradient> | ||
91 | |||
92 | <linearGradient id="GrRED" x1="0" y1="0" x2="0" y2="1" gradientUnits="boundingBox"> | ||
93 | <stop offset="0%" stop-color="rgb(255, 162, 162)" /> | ||
94 | <stop offset="20%" stop-color="rgb(255, 218, 218)" /> | ||
95 | <stop offset="25%" stop-color="rgb(255, 218, 218)" /> | ||
96 | <stop offset="100%" stop-color="rgb(255, 0, 0)" /> | ||
97 | </linearGradient> | ||
98 | |||
99 | <linearGradient id="GrGREEN" x1="0" y1="0" x2="0" y2="1" gradientUnits="boundingBox"> | ||
100 | <stop offset="0%" stop-color="rgb(102, 230, 102)" /> | ||
101 | <stop offset="20%" stop-color="rgb(218, 255, 218)" /> | ||
102 | <stop offset="25%" stop-color="rgb(218, 255, 218)" /> | ||
103 | <stop offset="100%" stop-color="rgb(0, 148, 0)" /> | ||
104 | </linearGradient> | ||
105 | |||
106 | <linearGradient id="GrBLUE" x1="0" y1="0" x2="0" y2="1" gradientUnits="boundingBox"> | ||
107 | <stop offset="0%" stop-color="rgb(102, 102, 230)" /> | ||
108 | <stop offset="20%" stop-color="rgb(238, 238, 238)" /> | ||
109 | <stop offset="25%" stop-color="rgb(238, 238, 238)" /> | ||
110 | <stop offset="100%" stop-color="rgb(0, 0, 128)" /> | ||
111 | </linearGradient> | ||
112 | |||
113 | <linearGradient id="GrORANGE" x1="0" y1="0" x2="0" y2="1" gradientUnits="boundingBox"> | ||
114 | <stop offset="0%" stop-color="rgb(255, 186, 0)" /> | ||
115 | <stop offset="20%" stop-color="rgb(255, 238, 168)" /> | ||
116 | <stop offset="25%" stop-color="rgb(255, 238, 168)" /> | ||
117 | <stop offset="100%" stop-color="rgb(255, 155, 0)" /> | ||
118 | </linearGradient> | ||
119 | </defs> | ||
120 | |||
121 | <rect x="0" y="0" rx="'.($h*$border_radius).'px" ry="'.($h*$border_radius).'px" width="'.$w.'" height="'.$h.'" fill="url(#GrGRAY)" stroke="none" /> | ||
122 | '; | ||
123 | |||
124 | if ($value) { | ||
125 | $barw = (($value-$min) / ($max-$min) ) * $w; | ||
126 | if ($optimum < $low) { | ||
127 | if ($value < $low) { $barcol = 'url(#GrGREEN)'; } | ||
128 | else if ($value > $high) { $barcol = 'url(#GrRED)'; } | ||
129 | else { $barcol = 'url(#GrORANGE)'; } | ||
130 | } | ||
131 | else if ($optimum > $high) { | ||
132 | if ($value < $low) { $barcol = 'url(#GrRED)'; } | ||
133 | else if ($value > $high) { $barcol = 'url(#GrGREEN)'; } | ||
134 | else { $barcol = 'url(#GrORANGE)'; } | ||
135 | } | ||
136 | else { | ||
137 | if ($value < $low) { $barcol = 'url(#GrORANGE)'; } | ||
138 | else if ($value > $high) { $barcol = 'url(#GrORANGE)'; } | ||
139 | else { $barcol = 'url(#GrGREEN)'; } | ||
140 | } | ||
141 | $svg .= '<rect x="0" y="0" rx="'.($h*$border_radius).'px" ry="'.($h*$border_radius).'px" width="'.$barw.'" height="'.$h.'" fill="'.$barcol.'" stroke="none" />'; | ||
142 | } | ||
143 | |||
144 | |||
145 | // Borders | ||
146 | //$svg .= '<rect x="0" y="0" rx="'.($h*$border_radius).'px" ry="'.($h*$border_radius).'px" width="'.$w.'" height="'.$h.'" fill="none" stroke="#888888" stroke-width="0.5px" />'; | ||
147 | if ($value) { | ||
148 | // $svg .= '<rect x="0" y="0" rx="'.($h*$border_radius).'px" ry="'.($h*$border_radius).'px" width="'.$barw.'" height="'.$h.'" fill="none" stroke="#888888" stroke-width="0.5px" />'; | ||
149 | } | ||
150 | |||
151 | |||
152 | $svg .= '</g></svg>'; | ||
153 | } | ||
154 | } | ||
155 | else { // $tag == 'progress' | ||
156 | |||
157 | if ($type=='2') { | ||
158 | ///////////////////////////////////////////////////////////////////////////////////// | ||
159 | ///////// CUSTOM <progress type="2"> | ||
160 | ///////////////////////////////////////////////////////////////////////////////////// | ||
161 | } | ||
162 | else { | ||
163 | ///////////////////////////////////////////////////////////////////////////////////// | ||
164 | ///////// DEFAULT <progress> | ||
165 | ///////////////////////////////////////////////////////////////////////////////////// | ||
166 | $h = 10; | ||
167 | $w = 100; | ||
168 | $border_radius = 0.143; // Factor of Height | ||
169 | |||
170 | if ($value or $value==='0') { | ||
171 | $fill = 'url(#GrGRAY)'; | ||
172 | } | ||
173 | else { | ||
174 | $fill = '#f8f8f8'; | ||
175 | } | ||
176 | |||
177 | $svg = '<svg width="'.$w.'px" height="'.$h.'px" viewBox="0 0 '.$w.' '.$h.'"><g> | ||
178 | |||
179 | <defs> | ||
180 | <linearGradient id="GrGRAY" x1="0" y1="0" x2="0" y2="1" gradientUnits="boundingBox"> | ||
181 | <stop offset="0%" stop-color="rgb(222, 222, 222)" /> | ||
182 | <stop offset="20%" stop-color="rgb(232, 232, 232)" /> | ||
183 | <stop offset="25%" stop-color="rgb(232, 232, 232)" /> | ||
184 | <stop offset="100%" stop-color="rgb(182, 182, 182)" /> | ||
185 | </linearGradient> | ||
186 | |||
187 | <linearGradient id="GrGREEN" x1="0" y1="0" x2="0" y2="1" gradientUnits="boundingBox"> | ||
188 | <stop offset="0%" stop-color="rgb(102, 230, 102)" /> | ||
189 | <stop offset="20%" stop-color="rgb(218, 255, 218)" /> | ||
190 | <stop offset="25%" stop-color="rgb(218, 255, 218)" /> | ||
191 | <stop offset="100%" stop-color="rgb(0, 148, 0)" /> | ||
192 | </linearGradient> | ||
193 | |||
194 | </defs> | ||
195 | |||
196 | <rect x="0" y="0" rx="'.($h*$border_radius).'px" ry="'.($h*$border_radius).'px" width="'.$w.'" height="'.$h.'" fill="'.$fill.'" stroke="none" /> | ||
197 | '; | ||
198 | |||
199 | if ($value) { | ||
200 | $barw = (($value-$min) / ($max-$min) ) * $w; | ||
201 | $barcol = 'url(#GrGREEN)'; | ||
202 | $svg .= '<rect x="0" y="0" rx="'.($h*$border_radius).'px" ry="'.($h*$border_radius).'px" width="'.$barw.'" height="'.$h.'" fill="'.$barcol.'" stroke="none" />'; | ||
203 | } | ||
204 | |||
205 | |||
206 | // Borders | ||
207 | $svg .= '<rect x="0" y="0" rx="'.($h*$border_radius).'px" ry="'.($h*$border_radius).'px" width="'.$w.'" height="'.$h.'" fill="none" stroke="#888888" stroke-width="0.5px" />'; | ||
208 | if ($value) { | ||
209 | // $svg .= '<rect x="0" y="0" rx="'.($h*$border_radius).'px" ry="'.($h*$border_radius).'px" width="'.$barw.'" height="'.$h.'" fill="none" stroke="#888888" stroke-width="0.5px" />'; | ||
210 | } | ||
211 | |||
212 | |||
213 | $svg .= '</g></svg>'; | ||
214 | |||
215 | } | ||
216 | } | ||
217 | |||
218 | return $svg; | ||
219 | } | ||
220 | |||
221 | |||
222 | } // end of class | ||
223 | |||
224 | ?> \ No newline at end of file | ||
diff --git a/inc/3rdparty/libraries/mpdf/classes/svg.php b/inc/3rdparty/libraries/mpdf/classes/svg.php new file mode 100644 index 00000000..3efe50f9 --- /dev/null +++ b/inc/3rdparty/libraries/mpdf/classes/svg.php | |||
@@ -0,0 +1,2600 @@ | |||
1 | <?php | ||
2 | // svg class modified for mPDF version 4.4.003 by Ian Back: based on - | ||
3 | // svg2pdf fpdf class | ||
4 | // sylvain briand (syb@godisaduck.com), modified by rick trevino (rtrevino1@yahoo.com) | ||
5 | // http://www.godisaduck.com/svg2pdf_with_fpdf | ||
6 | // http://rhodopsin.blogspot.com | ||
7 | // | ||
8 | // cette class etendue est open source, toute modification devra cependant etre repertoriée~ | ||
9 | |||
10 | |||
11 | // NB UNITS - Works in pixels as main units - converting to PDF units when outputing to PDF string | ||
12 | // and on returning size | ||
13 | |||
14 | class SVG { | ||
15 | |||
16 | var $svg_gradient; // array - contient les infos sur les gradient fill du svg classé par id du svg | ||
17 | var $svg_shadinglist; // array - contient les ids des objet shading | ||
18 | var $svg_info; // array contenant les infos du svg voulue par l'utilisateur | ||
19 | var $svg_attribs; // array - holds all attributes of root <svg> tag | ||
20 | var $svg_style; // array contenant les style de groupes du svg | ||
21 | var $svg_string; // String contenant le tracage du svg en lui même. | ||
22 | var $txt_data; // array - holds string info to write txt to image | ||
23 | var $txt_style; // array - current text style | ||
24 | var $mpdf_ref; | ||
25 | var $xbase; // mPDF 4.4.003 | ||
26 | var $ybase; // mPDF 4.4.003 | ||
27 | var $svg_error; // mPDF 4.4.003 | ||
28 | var $subPathInit; // mPDF 4.4.003 | ||
29 | var $spxstart; // mPDF 4.4.003 | ||
30 | var $spystart; // mPDF 4.4.003 | ||
31 | var $kp; // mPDF 4.4.003 convert pixels to PDF units | ||
32 | var $pathBBox; // mPDF 5.0.039 | ||
33 | |||
34 | function SVG(&$mpdf){ | ||
35 | $this->svg_gradient = array(); | ||
36 | $this->svg_shadinglist = array(); | ||
37 | $this->txt_data = array(); | ||
38 | $this->svg_string = ''; | ||
39 | $this->svg_info = array(); | ||
40 | $this->svg_attribs = array(); | ||
41 | $this->xbase = 0; | ||
42 | $this->ybase = 0; | ||
43 | $this->svg_error = false; | ||
44 | $this->subPathInit = false; // mPDF 4.4.003 | ||
45 | $this->dashesUsed = false; // mPDF 5.0 | ||
46 | $this->mpdf_ref =& $mpdf; | ||
47 | |||
48 | $this->kp = 72 / $mpdf->img_dpi; // mPDF 4.4.003 constant To convert pixels to pts/PDF units | ||
49 | $this->kf = 1; // mPDF 5.0.039 constant To convert font size if re-mapped | ||
50 | $this->pathBBox = array(); // mPDF 5.0.039 | ||
51 | |||
52 | $this->svg_style = array( | ||
53 | array( | ||
54 | 'fill' => 'black', // mPDF 4.4.008 | ||
55 | 'fill-opacity' => 1, // remplissage opaque par defaut | ||
56 | 'fill-rule' => 'nonzero', // mode de remplissage par defaut | ||
57 | 'stroke' => 'none', // pas de trait par defaut | ||
58 | 'stroke-linecap' => 'butt', // style de langle par defaut | ||
59 | 'stroke-linejoin' => 'miter', // | ||
60 | 'stroke-miterlimit' => 4, // limite de langle par defaut | ||
61 | 'stroke-opacity' => 1, // trait opaque par defaut | ||
62 | 'stroke-width' => 1, // mPDF 4.4.011 | ||
63 | 'stroke-dasharray' => 0, // mPDF 4.4.003 | ||
64 | 'stroke-dashoffset' => 0, // mPDF 4.4.003 | ||
65 | 'color' => '' // mPDF 4.4.005 | ||
66 | ) | ||
67 | ); | ||
68 | |||
69 | $this->txt_style = array( | ||
70 | array( | ||
71 | 'fill' => 'black', // pas de remplissage par defaut | ||
72 | 'font-family' => $mpdf->default_font, | ||
73 | 'font-size' => $mpdf->default_font_size, // ****** this is pts | ||
74 | 'font-weight' => 'normal', // normal | bold | ||
75 | 'font-style' => 'normal', // italic | normal | ||
76 | 'text-anchor' => 'start', // alignment: start, middle, end | ||
77 | /* mPDF 5.0.041 */ | ||
78 | 'fill-opacity' => 1, // remplissage opaque par defaut | ||
79 | 'fill-rule' => 'nonzero', // mode de remplissage par defaut | ||
80 | 'stroke' => 'none', // pas de trait par defaut | ||
81 | 'stroke-opacity' => 1, // trait opaque par defaut | ||
82 | 'stroke-width' => 1, // mPDF 4.4.011 | ||
83 | 'color' => '' // mPDF 4.4.005 | ||
84 | ) | ||
85 | ); | ||
86 | |||
87 | |||
88 | |||
89 | } | ||
90 | |||
91 | function svgGradient($gradient_info, $attribs, $element){ | ||
92 | $n = count($this->mpdf_ref->gradients)+1; | ||
93 | |||
94 | // Get bounding dimensions of element | ||
95 | $w = 100; | ||
96 | $h = 100; | ||
97 | $x_offset = 0; | ||
98 | $y_offset = 0; | ||
99 | if ($element=='rect') { | ||
100 | $w = $attribs['width']; | ||
101 | $h = $attribs['height']; | ||
102 | $x_offset = $attribs['x']; | ||
103 | $y_offset = $attribs['y']; | ||
104 | } | ||
105 | else if ($element=='ellipse') { | ||
106 | $w = $attribs['rx']*2; | ||
107 | $h = $attribs['ry']*2; | ||
108 | $x_offset = $attribs['cx']-$attribs['rx']; | ||
109 | $y_offset = $attribs['cy']-$attribs['ry']; | ||
110 | } | ||
111 | else if ($element=='circle') { | ||
112 | $w = $attribs['r']*2; | ||
113 | $h = $attribs['r']*2; | ||
114 | $x_offset = $attribs['cx']-$attribs['r']; | ||
115 | $y_offset = $attribs['cy']-$attribs['r']; | ||
116 | } | ||
117 | else if ($element=='polygon') { | ||
118 | $pts = preg_split('/[ ,]+/', trim($attribs['points'])); | ||
119 | $maxr=$maxb=0; | ||
120 | $minl=$mint=999999; | ||
121 | for ($i=0;$i<count($pts); $i++) { | ||
122 | if ($i % 2 == 0) { // x values | ||
123 | $minl = min($minl,$pts[$i]); | ||
124 | $maxr = max($maxr,$pts[$i]); | ||
125 | } | ||
126 | else { // y values | ||
127 | $mint = min($mint,$pts[$i]); | ||
128 | $maxb = max($maxb,$pts[$i]); | ||
129 | } | ||
130 | } | ||
131 | $w = $maxr-$minl; | ||
132 | $h = $maxb-$mint; | ||
133 | $x_offset = $minl; | ||
134 | $y_offset = $mint; | ||
135 | } | ||
136 | else if ($element=='path') { | ||
137 | // mPDF 5.0.039 | ||
138 | if (is_array($this->pathBBox) && $this->pathBBox[2]>0) { | ||
139 | $w = $this->pathBBox[2]; | ||
140 | $h = $this->pathBBox[3]; | ||
141 | $x_offset = $this->pathBBox[0]; | ||
142 | $y_offset = $this->pathBBox[1]; | ||
143 | } | ||
144 | else { | ||
145 | preg_match_all('/([a-z]|[A-Z])([ ,\-.\d]+)*/', $attribs['d'], $commands, PREG_SET_ORDER); | ||
146 | $maxr=$maxb=0; | ||
147 | $minl=$mint=999999; | ||
148 | foreach($commands as $c){ | ||
149 | if(count($c)==3){ | ||
150 | list($tmp, $cmd, $arg) = $c; | ||
151 | if ($cmd=='M' || $cmd=='L' || $cmd=='C' || $cmd=='S' || $cmd=='Q' || $cmd=='T') { | ||
152 | $pts = preg_split('/[ ,]+/', trim($arg)); | ||
153 | for ($i=0;$i<count($pts); $i++) { | ||
154 | if ($i % 2 == 0) { // x values | ||
155 | $minl = min($minl,$pts[$i]); | ||
156 | $maxr = max($maxr,$pts[$i]); | ||
157 | } | ||
158 | else { // y values | ||
159 | $mint = min($mint,$pts[$i]); | ||
160 | $maxb = max($maxb,$pts[$i]); | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | if ($cmd=='H') { // sets new x | ||
165 | $minl = min($minl,$arg); | ||
166 | $maxr = max($maxr,$arg); | ||
167 | } | ||
168 | if ($cmd=='V') { // sets new y | ||
169 | $mint = min($mint,$arg); | ||
170 | $maxb = max($maxb,$arg); | ||
171 | } | ||
172 | } | ||
173 | } | ||
174 | $w = $maxr-$minl; | ||
175 | $h = $maxb-$mint; | ||
176 | $x_offset = $minl; | ||
177 | $y_offset = $mint; | ||
178 | } | ||
179 | } | ||
180 | if (!$w || $w==-999999) { $w = 100; } | ||
181 | if (!$h || $h==-999999) { $h = 100; } | ||
182 | if ($x_offset==999999) { $x_offset = 0; } | ||
183 | if ($y_offset==999999) { $y_offset = 0; } | ||
184 | |||
185 | // mPDF 4.5.010 | ||
186 | // TRANSFORMATIONS | ||
187 | $transformations = ''; | ||
188 | if (isset($gradient_info['transform'])){ | ||
189 | preg_match_all('/(matrix|translate|scale|rotate|skewX|skewY)\((.*?)\)/is',$gradient_info['transform'],$m); | ||
190 | if (count($m[0])) { | ||
191 | for($i=0; $i<count($m[0]); $i++) { | ||
192 | $c = strtolower($m[1][$i]); | ||
193 | $v = trim($m[2][$i]); | ||
194 | $vv = preg_split('/[ ,]+/',$v); | ||
195 | if ($c=='matrix' && count($vv)==6) { | ||
196 | // mPDF 5.0.039 | ||
197 | // Note angle of rotation is reversed (from SVG to PDF), so vv[1] and vv[2] are negated | ||
198 | // cf svgDefineStyle() | ||
199 | $transformations .= sprintf(' %.3F %.3F %.3F %.3F %.3F %.3F cm ', $vv[0], -$vv[1], -$vv[2], $vv[3], $vv[4]*$this->kp, -$vv[5]*$this->kp); | ||
200 | } | ||
201 | else if ($c=='translate' && count($vv)) { | ||
202 | $tm[4] = $vv[0]; | ||
203 | if (count($vv)==2) { $t_y = -$vv[1]; } | ||
204 | else { $t_y = 0; } | ||
205 | $tm[5] = $t_y; | ||
206 | $transformations .= sprintf(' 1 0 0 1 %.3F %.3F cm ', $tm[4]*$this->kp, $tm[5]*$this->kp); | ||
207 | } | ||
208 | else if ($c=='scale' && count($vv)) { | ||
209 | if (count($vv)==2) { $s_y = $vv[1]; } | ||
210 | else { $s_y = $vv[0]; } | ||
211 | $tm[0] = $vv[0]; | ||
212 | $tm[3] = $s_y; | ||
213 | $transformations .= sprintf(' %.3F 0 0 %.3F 0 0 cm ', $tm[0], $tm[3]); | ||
214 | } | ||
215 | else if ($c=='rotate' && count($vv)) { | ||
216 | $tm[0] = cos(deg2rad(-$vv[0])); | ||
217 | $tm[1] = sin(deg2rad(-$vv[0])); | ||
218 | $tm[2] = -$tm[1]; | ||
219 | $tm[3] = $tm[0]; | ||
220 | if (count($vv)==3) { | ||
221 | $transformations .= sprintf(' 1 0 0 1 %.3F %.3F cm ', $vv[1]*$this->kp, -$vv[2]*$this->kp); | ||
222 | } | ||
223 | $transformations .= sprintf(' %.3F %.3F %.3F %.3F 0 0 cm ', $tm[0], $tm[1], $tm[2], $tm[3]); | ||
224 | if (count($vv)==3) { | ||
225 | $transformations .= sprintf(' 1 0 0 1 %.3F %.3F cm ', -$vv[1]*$this->kp, $vv[2]*$this->kp); | ||
226 | } | ||
227 | } | ||
228 | else if ($c=='skewx' && count($vv)) { | ||
229 | $tm[2] = tan(deg2rad(-$vv[0])); | ||
230 | $transformations .= sprintf(' 1 0 %.3F 1 0 0 cm ', $tm[2]); | ||
231 | } | ||
232 | else if ($c=='skewy' && count($vv)) { | ||
233 | $tm[1] = tan(deg2rad(-$vv[0])); | ||
234 | $transformations .= sprintf(' 1 %.3F 0 1 0 0 cm ', $tm[1]); | ||
235 | } | ||
236 | |||
237 | } | ||
238 | } | ||
239 | } | ||
240 | |||
241 | |||
242 | $return = ""; | ||
243 | |||
244 | // mPDF 5.0.039 | ||
245 | if (isset($gradient_info['units']) && strtolower($gradient_info['units'])=='userspaceonuse') { | ||
246 | if ($transformations) { $return .= $transformations; } | ||
247 | } | ||
248 | // mPDF 5.0.040 | ||
249 | $spread = 'P'; // pad | ||
250 | if (isset($gradient_info['spread'])) { | ||
251 | if (strtolower($gradient_info['spread'])=='reflect') { $spread = 'F'; } // reflect | ||
252 | else if (strtolower($gradient_info['spread'])=='repeat') { $spread = 'R'; } // repeat | ||
253 | } | ||
254 | |||
255 | |||
256 | for ($i=0; $i<(count($gradient_info['color'])); $i++) { | ||
257 | if (stristr($gradient_info['color'][$i]['offset'], '%')!== false) { $gradient_info['color'][$i]['offset'] = ($gradient_info['color'][$i]['offset']+0)/100; } | ||
258 | if (stristr($gradient_info['color'][($i+1)]['offset'], '%')!== false) { $gradient_info['color'][($i+1)]['offset'] = ($gradient_info['color'][($i+1)]['offset']+0)/100; } | ||
259 | if ($gradient_info['color'][$i]['offset']<0) { $gradient_info['color'][$i]['offset'] = 0; } | ||
260 | if ($gradient_info['color'][$i]['offset']>1) { $gradient_info['color'][$i]['offset'] = 1; } | ||
261 | if ($i>0) { | ||
262 | if ($gradient_info['color'][$i]['offset']<$gradient_info['color'][($i-1)]['offset']) { | ||
263 | $gradient_info['color'][$i]['offset']=$gradient_info['color'][($i-1)]['offset']; | ||
264 | } | ||
265 | } | ||
266 | } | ||
267 | |||
268 | if ($gradient_info['color'][0]['offset']>0) { | ||
269 | array_unshift($gradient_info['color'], $gradient_info['color'][0]); | ||
270 | $gradient_info['color'][0]['offset'] = 0; | ||
271 | } | ||
272 | $ns = count($gradient_info['color']); | ||
273 | if ($gradient_info['color'][($ns-1)]['offset']<1) { | ||
274 | $gradient_info['color'][] = $gradient_info['color'][($ns-1)]; | ||
275 | $gradient_info['color'][($ns)]['offset'] = 1; | ||
276 | } | ||
277 | $ns = count($gradient_info['color']); | ||
278 | |||
279 | |||
280 | |||
281 | |||
282 | if ($gradient_info['type'] == 'linear'){ | ||
283 | // mPDF 4.4.003 | ||
284 | if (isset($gradient_info['units']) && strtolower($gradient_info['units'])=='userspaceonuse') { | ||
285 | if (isset($gradient_info['info']['x1'])) { $gradient_info['info']['x1'] = ($gradient_info['info']['x1']-$x_offset) / $w; } | ||
286 | if (isset($gradient_info['info']['y1'])) { $gradient_info['info']['y1'] = ($gradient_info['info']['y1']-$y_offset) / $h; } | ||
287 | if (isset($gradient_info['info']['x2'])) { $gradient_info['info']['x2'] = ($gradient_info['info']['x2']-$x_offset) / $w; } | ||
288 | if (isset($gradient_info['info']['y2'])) { $gradient_info['info']['y2'] = ($gradient_info['info']['y2']-$y_offset) / $h; } | ||
289 | } | ||
290 | if (isset($gradient_info['info']['x1'])) { $x1 = $gradient_info['info']['x1']; } | ||
291 | else { $x1 = 0; } | ||
292 | if (isset($gradient_info['info']['y1'])) { $y1 = $gradient_info['info']['y1']; } | ||
293 | else { $y1 = 0; } | ||
294 | if (isset($gradient_info['info']['x2'])) { $x2 = $gradient_info['info']['x2']; } | ||
295 | else { $x2 = 1; } | ||
296 | if (isset($gradient_info['info']['y2'])) { $y2 = $gradient_info['info']['y2']; } | ||
297 | else { $y2 = 0; } | ||
298 | |||
299 | if (stristr($x1, '%')!== false) { $x1 = ($x1+0)/100; } | ||
300 | if (stristr($x2, '%')!== false) { $x2 = ($x2+0)/100; } | ||
301 | if (stristr($y1, '%')!== false) { $y1 = ($y1+0)/100; } | ||
302 | if (stristr($y2, '%')!== false) { $y2 = ($y2+0)/100; } | ||
303 | |||
304 | // mPDF 5.0.042 | ||
305 | $bboxw = $w; | ||
306 | $bboxh = $h; | ||
307 | $usex = $x_offset; | ||
308 | $usey = $y_offset; | ||
309 | $usew = $bboxw; | ||
310 | $useh = $bboxh; | ||
311 | if (isset($gradient_info['units']) && strtolower($gradient_info['units'])=='userspaceonuse') { | ||
312 | $angle = rad2deg(atan2(($gradient_info['info']['y2']-$gradient_info['info']['y1']), ($gradient_info['info']['x2']-$gradient_info['info']['x1']))); | ||
313 | if ($angle < 0) { $angle += 360; } | ||
314 | else if ($angle > 360) { $angle -= 360; } | ||
315 | if ($angle!=0 && $angle!=360 && $angle!=90 && $angle!=180 && $angle!=270) { | ||
316 | if ($w >= $h) { | ||
317 | $y1 *= $h/$w ; | ||
318 | $y2 *= $h/$w ; | ||
319 | $usew = $useh = $bboxw; | ||
320 | } | ||
321 | else { | ||
322 | $x1 *= $w/$h ; | ||
323 | $x2 *= $w/$h ; | ||
324 | $usew = $useh = $bboxh; | ||
325 | } | ||
326 | } | ||
327 | } | ||
328 | $a = $usew; // width | ||
329 | $d = -$useh; // height | ||
330 | $e = $usex; // x- offset | ||
331 | $f = -$usey; // -y-offset | ||
332 | |||
333 | $return .= sprintf('%.3F 0 0 %.3F %.3F %.3F cm ', $a*$this->kp, $d*$this->kp, $e*$this->kp, $f*$this->kp); | ||
334 | |||
335 | // mPDF 5.0.039 | ||
336 | if (isset($gradient_info['units']) && strtolower($gradient_info['units'])=='objectboundingbox') { | ||
337 | if ($transformations) { $return .= $transformations; } | ||
338 | } | ||
339 | |||
340 | // mPDF 5.0.020 | ||
341 | $trans = false; | ||
342 | |||
343 | // mPDF 5.0.040 | ||
344 | if ($spread=='R' || $spread=='F') { // Repeat / Reflect | ||
345 | $offs = array(); | ||
346 | for($i=0;$i<$ns;$i++) { | ||
347 | $offs[$i] = $gradient_info['color'][$i]['offset']; | ||
348 | } | ||
349 | $gp = 0; | ||
350 | $inside=true; | ||
351 | while($inside) { | ||
352 | $gp++; | ||
353 | for($i=0;$i<$ns;$i++) { | ||
354 | if ($spread=='F' && ($gp % 2) == 1) { // Reflect | ||
355 | $gradient_info['color'][(($ns*$gp)+$i)] = $gradient_info['color'][(($ns*($gp-1))+($ns-$i-1))]; | ||
356 | $tmp = $gp+(1-$offs[($ns-$i-1)]) ; | ||
357 | $gradient_info['color'][(($ns*$gp)+$i)]['offset'] = $tmp; | ||
358 | } | ||
359 | else { // Reflect | ||
360 | $gradient_info['color'][(($ns*$gp)+$i)] = $gradient_info['color'][$i]; | ||
361 | $tmp = $gp+$offs[$i] ; | ||
362 | $gradient_info['color'][(($ns*$gp)+$i)]['offset'] = $tmp; | ||
363 | } | ||
364 | // IF STILL INSIDE BOX OR STILL VALID | ||
365 | // Point on axis to test | ||
366 | $px1 = $x1 + ($x2-$x1)*$tmp; | ||
367 | $py1 = $y1 + ($y2-$y1)*$tmp; | ||
368 | // Get perpendicular axis | ||
369 | $alpha = atan2($y2-$y1, $x2-$x1); | ||
370 | $alpha += M_PI/2; // rotate 90 degrees | ||
371 | // Get arbitrary point to define line perpendicular to axis | ||
372 | $px2 = $px1+cos($alpha); | ||
373 | $py2 = $py1+sin($alpha); | ||
374 | |||
375 | $res1 = _testIntersect($px1, $py1, $px2, $py2, 0, 0, 0, 1); // $x=0 vert axis | ||
376 | $res2 = _testIntersect($px1, $py1, $px2, $py2, 1, 0, 1, 1); // $x=1 vert axis | ||
377 | $res3 = _testIntersect($px1, $py1, $px2, $py2, 0, 0, 1, 0); // $y=0 horiz axis | ||
378 | $res4 = _testIntersect($px1, $py1, $px2, $py2, 0, 1, 1, 1); // $y=1 horiz axis | ||
379 | if (!$res1 && !$res2 && !$res3 && !$res4) { $inside = false; } | ||
380 | } | ||
381 | } | ||
382 | |||
383 | $inside=true; | ||
384 | $gp = 0; | ||
385 | while($inside) { | ||
386 | $gp++; | ||
387 | $newarr = array(); | ||
388 | for($i=0;$i<$ns;$i++) { | ||
389 | if ($spread=='F') { // Reflect | ||
390 | $newarr[$i] = $gradient_info['color'][($ns-$i-1)]; | ||
391 | if (($gp % 2) == 1) { | ||
392 | $tmp = -$gp+(1-$offs[($ns-$i-1)]); | ||
393 | $newarr[$i]['offset'] = $tmp; | ||
394 | } | ||
395 | else { | ||
396 | $tmp = -$gp+$offs[$i]; | ||
397 | $newarr[$i]['offset'] = $tmp; | ||
398 | } | ||
399 | } | ||
400 | else { // Reflect | ||
401 | $newarr[$i] = $gradient_info['color'][$i]; | ||
402 | $tmp = -$gp+$offs[$i]; | ||
403 | $newarr[$i]['offset'] = $tmp; | ||
404 | } | ||
405 | |||
406 | // IF STILL INSIDE BOX OR STILL VALID | ||
407 | // Point on axis to test | ||
408 | $px1 = $x1 + ($x2-$x1)*$tmp; | ||
409 | $py1 = $y1 + ($y2-$y1)*$tmp; | ||
410 | // Get perpendicular axis | ||
411 | $alpha = atan2($y2-$y1, $x2-$x1); | ||
412 | $alpha += M_PI/2; // rotate 90 degrees | ||
413 | // Get arbitrary point to define line perpendicular to axis | ||
414 | $px2 = $px1+cos($alpha); | ||
415 | $py2 = $py1+sin($alpha); | ||
416 | |||
417 | $res1 = _testIntersect($px1, $py1, $px2, $py2, 0, 0, 0, 1); // $x=0 vert axis | ||
418 | $res2 = _testIntersect($px1, $py1, $px2, $py2, 1, 0, 1, 1); // $x=1 vert axis | ||
419 | $res3 = _testIntersect($px1, $py1, $px2, $py2, 0, 0, 1, 0); // $y=0 horiz axis | ||
420 | $res4 = _testIntersect($px1, $py1, $px2, $py2, 0, 1, 1, 1); // $y=1 horiz axis | ||
421 | if (!$res1 && !$res2 && !$res3 && !$res4) { $inside = false; } | ||
422 | } | ||
423 | for($i=($ns-1);$i>=0;$i--) { | ||
424 | if (isset($newarr[$i]['offset'])) array_unshift($gradient_info['color'], $newarr[$i]); | ||
425 | } | ||
426 | } | ||
427 | } | ||
428 | |||
429 | // mPDF 4.4.007 Gradient STOPs | ||
430 | $stops = count($gradient_info['color']); | ||
431 | if ($stops < 2) { return ''; } | ||
432 | |||
433 | // mPDF 5.0.042 | ||
434 | $range = $gradient_info['color'][count($gradient_info['color'])-1]['offset']-$gradient_info['color'][0]['offset']; | ||
435 | $min = $gradient_info['color'][0]['offset']; | ||
436 | |||
437 | for ($i=0; $i<($stops); $i++) { | ||
438 | // mPDF 5.0.051 | ||
439 | if (!$gradient_info['color'][$i]['color']) { | ||
440 | if ($gradient_info['colorspace']=='RGB') $gradient_info['color'][$i]['color'] = '0 0 0'; | ||
441 | else if ($gradient_info['colorspace']=='Gray') $gradient_info['color'][$i]['color'] = '0'; | ||
442 | else if ($gradient_info['colorspace']=='CMYK') $gradient_info['color'][$i]['color'] = '1 1 1 1'; | ||
443 | } | ||
444 | $offset = ($gradient_info['color'][$i]['offset'] - $min)/$range; | ||
445 | $this->mpdf_ref->gradients[$n]['stops'][] = array( | ||
446 | 'col' => $gradient_info['color'][$i]['color'], | ||
447 | 'opacity' => $gradient_info['color'][$i]['opacity'], | ||
448 | 'offset' => $offset); | ||
449 | if ($gradient_info['color'][$i]['opacity']<1) { $trans = true; } | ||
450 | } | ||
451 | $grx1 = $x1 + ($x2-$x1)*$gradient_info['color'][0]['offset']; | ||
452 | $gry1 = $y1 + ($y2-$y1)*$gradient_info['color'][0]['offset']; | ||
453 | $grx2 = $x1 + ($x2-$x1)*$gradient_info['color'][count($gradient_info['color'])-1]['offset']; | ||
454 | $gry2 = $y1 + ($y2-$y1)*$gradient_info['color'][count($gradient_info['color'])-1]['offset']; | ||
455 | |||
456 | $this->mpdf_ref->gradients[$n]['coords']=array($grx1, $gry1, $grx2, $gry2); | ||
457 | |||
458 | $this->mpdf_ref->gradients[$n]['colorspace'] = $gradient_info['colorspace']; // mPDF 5.0.051 | ||
459 | |||
460 | $this->mpdf_ref->gradients[$n]['type'] = 2; | ||
461 | $this->mpdf_ref->gradients[$n]['fo'] = true; | ||
462 | |||
463 | $this->mpdf_ref->gradients[$n]['extend']=array('true','true'); | ||
464 | if ($trans) { | ||
465 | $this->mpdf_ref->gradients[$n]['trans'] = true; | ||
466 | $return .= ' /TGS'.($n).' gs '; | ||
467 | } | ||
468 | $return .= ' /Sh'.($n).' sh '; | ||
469 | $return .= " Q\n"; | ||
470 | } | ||
471 | else if ($gradient_info['type'] == 'radial'){ | ||
472 | // mPDF 4.4.003 | ||
473 | if (isset($gradient_info['units']) && strtolower($gradient_info['units'])=='userspaceonuse') { | ||
474 | if ($w > $h) { $h = $w; } | ||
475 | else { $w = $h; } | ||
476 | if (isset($gradient_info['info']['x0'])) { $gradient_info['info']['x0'] = ($gradient_info['info']['x0']-$x_offset) / $w; } | ||
477 | if (isset($gradient_info['info']['y0'])) { $gradient_info['info']['y0'] = ($gradient_info['info']['y0']-$y_offset) / $h; } | ||
478 | if (isset($gradient_info['info']['x1'])) { $gradient_info['info']['x1'] = ($gradient_info['info']['x1']-$x_offset) / $w; } | ||
479 | if (isset($gradient_info['info']['y1'])) { $gradient_info['info']['y1'] = ($gradient_info['info']['y1']-$y_offset) / $h; } | ||
480 | if (isset($gradient_info['info']['r'])) { $gradient_info['info']['rx'] = $gradient_info['info']['r'] / $w; } | ||
481 | if (isset($gradient_info['info']['r'])) { $gradient_info['info']['ry'] = $gradient_info['info']['r'] / $h; } | ||
482 | } | ||
483 | |||
484 | if ($gradient_info['info']['x0'] || $gradient_info['info']['x0']===0) { $x0 = $gradient_info['info']['x0']; } | ||
485 | else { $x0 = 0.5; } | ||
486 | if ($gradient_info['info']['y0'] || $gradient_info['info']['y0']===0) { $y0 = $gradient_info['info']['y0']; } | ||
487 | else { $y0 = 0.5; } | ||
488 | if ($gradient_info['info']['rx'] || $gradient_info['info']['rx']===0) { $rx = $gradient_info['info']['rx']; } | ||
489 | else if ($gradient_info['info']['r'] || $gradient_info['info']['r']===0) { $rx = $gradient_info['info']['r']; } | ||
490 | else { $rx = 0.5; } | ||
491 | if ($gradient_info['info']['ry'] || $gradient_info['info']['ry']===0) { $ry = $gradient_info['info']['ry']; } | ||
492 | else if ($gradient_info['info']['r'] || $gradient_info['info']['r']===0) { $ry = $gradient_info['info']['r']; } | ||
493 | else { $ry = 0.5; } | ||
494 | if ($gradient_info['info']['x1'] || $gradient_info['info']['x1']===0) { $x1 = $gradient_info['info']['x1']; } | ||
495 | else { $x1 = $x0; } | ||
496 | if ($gradient_info['info']['y1'] || $gradient_info['info']['y1']===0) { $y1 = $gradient_info['info']['y1']; } | ||
497 | else { $y1 = $y0; } | ||
498 | |||
499 | if (stristr($x1, '%')!== false) { $x1 = ($x1+0)/100; } | ||
500 | if (stristr($x0, '%')!== false) { $x0 = ($x0+0)/100; } | ||
501 | if (stristr($y1, '%')!== false) { $y1 = ($y1+0)/100; } | ||
502 | if (stristr($y0, '%')!== false) { $y0 = ($y0+0)/100; } | ||
503 | if (stristr($rx, '%')!== false) { $rx = ($rx+0)/100; } | ||
504 | if (stristr($ry, '%')!== false) { $ry = ($ry+0)/100; } | ||
505 | |||
506 | // mPDF 5.0.043 | ||
507 | $bboxw = $w; | ||
508 | $bboxh = $h; | ||
509 | $usex = $x_offset; | ||
510 | $usey = $y_offset; | ||
511 | $usew = $bboxw; | ||
512 | $useh = $bboxh; | ||
513 | if (isset($gradient_info['units']) && strtolower($gradient_info['units'])=='userspaceonuse') { | ||
514 | $angle = rad2deg(atan2(($gradient_info['info']['y0']-$gradient_info['info']['y1']), ($gradient_info['info']['x0']-$gradient_info['info']['x1']))); | ||
515 | if ($angle < 0) { $angle += 360; } | ||
516 | else if ($angle > 360) { $angle -= 360; } | ||
517 | if ($angle!=0 && $angle!=360 && $angle!=90 && $angle!=180 && $angle!=270) { | ||
518 | if ($w >= $h) { | ||
519 | $y1 *= $h/$w ; | ||
520 | $y0 *= $h/$w ; | ||
521 | $rx *= $h/$w ; | ||
522 | $ry *= $h/$w ; | ||
523 | $usew = $useh = $bboxw; | ||
524 | } | ||
525 | else { | ||
526 | $x1 *= $w/$h ; | ||
527 | $x0 *= $w/$h ; | ||
528 | $rx *= $w/$h ; | ||
529 | $ry *= $w/$h ; | ||
530 | $usew = $useh = $bboxh; | ||
531 | } | ||
532 | } | ||
533 | } | ||
534 | $a = $usew; // width | ||
535 | $d = -$useh; // height | ||
536 | $e = $usex; // x- offset | ||
537 | $f = -$usey; // -y-offset | ||
538 | |||
539 | $r = $rx; | ||
540 | |||
541 | |||
542 | $return .= sprintf('%.3F 0 0 %.3F %.3F %.3F cm ', $a*$this->kp, $d*$this->kp, $e*$this->kp, $f*$this->kp); | ||
543 | |||
544 | // mPDF 5.0.039 | ||
545 | if (isset($gradient_info['units']) && strtolower($gradient_info['units'])=='objectboundingbox') { | ||
546 | if ($transformations) { $return .= $transformations; } | ||
547 | } | ||
548 | |||
549 | // x1 and y1 (fx, fy) should be inside the circle defined by x0 y0 and r else error in mPDF | ||
550 | while (pow(($x1-$x0),2) + pow(($y1 - $y0),2) >= pow($r,2)) { $r += 0.05; } | ||
551 | |||
552 | // mPDF 5.0.040 | ||
553 | if ($spread=='R' || $spread=='F') { // Repeat / Reflect | ||
554 | $offs = array(); | ||
555 | for($i=0;$i<$ns;$i++) { | ||
556 | $offs[$i] = $gradient_info['color'][$i]['offset']; | ||
557 | } | ||
558 | $gp = 0; | ||
559 | $inside=true; | ||
560 | while($inside) { | ||
561 | $gp++; | ||
562 | for($i=0;$i<$ns;$i++) { | ||
563 | if ($spread=='F' && ($gp % 2) == 1) { // Reflect | ||
564 | $gradient_info['color'][(($ns*$gp)+$i)] = $gradient_info['color'][(($ns*($gp-1))+($ns-$i-1))]; | ||
565 | $tmp = $gp+(1-$offs[($ns-$i-1)]) ; | ||
566 | $gradient_info['color'][(($ns*$gp)+$i)]['offset'] = $tmp; | ||
567 | } | ||
568 | else { // Reflect | ||
569 | $gradient_info['color'][(($ns*$gp)+$i)] = $gradient_info['color'][$i]; | ||
570 | $tmp = $gp+$offs[$i] ; | ||
571 | $gradient_info['color'][(($ns*$gp)+$i)]['offset'] = $tmp; | ||
572 | } | ||
573 | // IF STILL INSIDE BOX OR STILL VALID | ||
574 | // TEST IF circle (perimeter) intersects with | ||
575 | // or is enclosed | ||
576 | // Point on axis to test | ||
577 | $px = $x1 + ($x0-$x1)*$tmp; | ||
578 | $py = $y1 + ($y0-$y1)*$tmp; | ||
579 | $pr = $r*$tmp; | ||
580 | $res = _testIntersectCircle($px, $py, $pr); | ||
581 | if (!$res) { $inside = false; } | ||
582 | } | ||
583 | } | ||
584 | } | ||
585 | |||
586 | // mPDF 4.4.007 Gradient STOPs | ||
587 | $stops = count($gradient_info['color']); | ||
588 | if ($stops < 2) { return ''; } | ||
589 | |||
590 | // mPDF 5.0.043 | ||
591 | $range = $gradient_info['color'][count($gradient_info['color'])-1]['offset']-$gradient_info['color'][0]['offset']; | ||
592 | $min = $gradient_info['color'][0]['offset']; | ||
593 | |||
594 | for ($i=0; $i<($stops); $i++) { | ||
595 | // mPDF 5.0.051 | ||
596 | if (!$gradient_info['color'][$i]['color']) { | ||
597 | if ($gradient_info['colorspace']=='RGB') $gradient_info['color'][$i]['color'] = '0 0 0'; | ||
598 | else if ($gradient_info['colorspace']=='Gray') $gradient_info['color'][$i]['color'] = '0'; | ||
599 | else if ($gradient_info['colorspace']=='CMYK') $gradient_info['color'][$i]['color'] = '1 1 1 1'; | ||
600 | } | ||
601 | $offset = ($gradient_info['color'][$i]['offset'] - $min)/$range; | ||
602 | $this->mpdf_ref->gradients[$n]['stops'][] = array( | ||
603 | 'col' => $gradient_info['color'][$i]['color'], | ||
604 | 'opacity' => $gradient_info['color'][$i]['opacity'], | ||
605 | 'offset' => $offset); | ||
606 | if ($gradient_info['color'][$i]['opacity']<1) { $trans = true; } | ||
607 | } | ||
608 | $grx1 = $x1 + ($x0-$x1)*$gradient_info['color'][0]['offset']; | ||
609 | $gry1 = $y1 + ($y0-$y1)*$gradient_info['color'][0]['offset']; | ||
610 | $grx2 = $x1 + ($x0-$x1)*$gradient_info['color'][count($gradient_info['color'])-1]['offset']; | ||
611 | $gry2 = $y1 + ($y0-$y1)*$gradient_info['color'][count($gradient_info['color'])-1]['offset']; | ||
612 | $grir = $r*$gradient_info['color'][0]['offset']; | ||
613 | $grr = $r*$gradient_info['color'][count($gradient_info['color'])-1]['offset']; | ||
614 | |||
615 | $this->mpdf_ref->gradients[$n]['coords']=array($grx1, $gry1, $grx2, $gry2, abs($grr), abs($grir) ); | ||
616 | |||
617 | $grx1 = $x1 + ($x0-$x1)*$first_stop; | ||
618 | $gry1 = $y1 + ($y0-$y1)*$first_stop; | ||
619 | $grx2 = $x1 + ($x0-$x1)*$last_stop; | ||
620 | $gry2 = $y1 + ($y0-$y1)*$last_stop; | ||
621 | $grir = $r*$first_stop; | ||
622 | $grr = $r*$last_stop; | ||
623 | $this->mpdf_ref->gradients[$n]['colorspace'] = $gradient_info['colorspace']; // mPDF 5.0.051 | ||
624 | |||
625 | $this->mpdf_ref->gradients[$n]['type'] = 3; | ||
626 | $this->mpdf_ref->gradients[$n]['fo'] = true; | ||
627 | |||
628 | $this->mpdf_ref->gradients[$n]['extend']=array('true','true'); | ||
629 | if ($trans) { | ||
630 | $this->mpdf_ref->gradients[$n]['trans'] = true; | ||
631 | $return .= ' /TGS'.($n).' gs '; | ||
632 | } | ||
633 | $return .= ' /Sh'.($n).' sh '; | ||
634 | $return .= " Q\n"; | ||
635 | |||
636 | |||
637 | } | ||
638 | |||
639 | return $return; | ||
640 | } | ||
641 | |||
642 | |||
643 | function svgOffset ($attribs){ | ||
644 | // save all <svg> tag attributes | ||
645 | $this->svg_attribs = $attribs; | ||
646 | if(isset($this->svg_attribs['viewBox'])) { | ||
647 | $vb = preg_split('/\s+/is', trim($this->svg_attribs['viewBox'])); | ||
648 | if (count($vb)==4) { | ||
649 | $this->svg_info['x'] = $vb[0]; | ||
650 | $this->svg_info['y'] = $vb[1]; | ||
651 | $this->svg_info['w'] = $vb[2]; | ||
652 | $this->svg_info['h'] = $vb[3]; | ||
653 | // return; // mPDF 5.0.005 | ||
654 | } | ||
655 | } | ||
656 | |||
657 | $svg_w = $this->mpdf_ref->ConvertSize($attribs['width']); // mm (interprets numbers as pixels) | ||
658 | $svg_h = $this->mpdf_ref->ConvertSize($attribs['height']); // mm | ||
659 | |||
660 | ///* | ||
661 | // mPDF 5.0.005 | ||
662 | if ($this->svg_info['w']) { // if 'w' set by viewBox | ||
663 | if ($svg_w) { // if width also set, use these values to determine to set size of "pixel" | ||
664 | $this->kp *= ($svg_w/0.2645) / $this->svg_info['w']; | ||
665 | $this->kf = ($svg_w/0.2645) / $this->svg_info['w']; // mPDF 5.0.039 | ||
666 | } | ||
667 | else if ($svg_h) { | ||
668 | $this->kp *= ($svg_h/0.2645) / $this->svg_info['h']; | ||
669 | $this->kf = ($svg_h/0.2645) / $this->svg_info['h']; // mPDF 5.0.039 | ||
670 | } | ||
671 | return; | ||
672 | } | ||
673 | //*/ | ||
674 | |||
675 | // Added to handle file without height or width specified | ||
676 | if (!$svg_w && !$svg_h) { $svg_w = $svg_h = $this->mpdf_ref->blk[$this->mpdf_ref->blklvl]['inner_width'] ; } // DEFAULT | ||
677 | if (!$svg_w) { $svg_w = $svg_h; } | ||
678 | if (!$svg_h) { $svg_h = $svg_w; } | ||
679 | |||
680 | $this->svg_info['x'] = 0; | ||
681 | $this->svg_info['y'] = 0; | ||
682 | $this->svg_info['w'] = $svg_w/0.2645; // mm->pixels | ||
683 | $this->svg_info['h'] = $svg_h/0.2645; // mm->pixels | ||
684 | |||
685 | } | ||
686 | |||
687 | |||
688 | // | ||
689 | // check if points are within svg, if not, set to max | ||
690 | function svg_overflow($x,$y) | ||
691 | { | ||
692 | $x2 = $x; | ||
693 | $y2 = $y; | ||
694 | if(isset($this->svg_attribs['overflow'])) | ||
695 | { | ||
696 | if($this->svg_attribs['overflow'] == 'hidden') | ||
697 | { | ||
698 | // Not sure if this is supposed to strip off units, but since I dont use any I will omlt this step | ||
699 | $svg_w = preg_replace("/([0-9\.]*)(.*)/i","$1",$this->svg_attribs['width']); | ||
700 | $svg_h = preg_replace("/([0-9\.]*)(.*)/i","$1",$this->svg_attribs['height']); | ||
701 | |||
702 | // $xmax = floor($this->svg_attribs['width']); | ||
703 | $xmax = floor($svg_w); | ||
704 | $xmin = 0; | ||
705 | // $ymax = floor(($this->svg_attribs['height'] * -1)); | ||
706 | $ymax = floor(($svg_h * -1)); | ||
707 | $ymin = 0; | ||
708 | |||
709 | if($x > $xmax) $x2 = $xmax; // right edge | ||
710 | if($x < $xmin) $x2 = $xmin; // left edge | ||
711 | if($y < $ymax) $y2 = $ymax; // bottom | ||
712 | if($y > $ymin) $y2 = $ymin; // top | ||
713 | |||
714 | } | ||
715 | } | ||
716 | |||
717 | |||
718 | return array( 'x' => $x2, 'y' => $y2); | ||
719 | } | ||
720 | |||
721 | |||
722 | |||
723 | function svgDefineStyle($critere_style){ | ||
724 | |||
725 | $tmp = count($this->svg_style)-1; | ||
726 | $current_style = $this->svg_style[$tmp]; | ||
727 | |||
728 | unset($current_style['transformations']); | ||
729 | |||
730 | // TRANSFORM SCALE | ||
731 | $transformations = ''; | ||
732 | if (isset($critere_style['transform'])){ | ||
733 | preg_match_all('/(matrix|translate|scale|rotate|skewX|skewY)\((.*?)\)/is',$critere_style['transform'],$m); | ||
734 | if (count($m[0])) { | ||
735 | for($i=0; $i<count($m[0]); $i++) { | ||
736 | $c = strtolower($m[1][$i]); | ||
737 | $v = trim($m[2][$i]); | ||
738 | $vv = preg_split('/[ ,]+/',$v); | ||
739 | if ($c=='matrix' && count($vv)==6) { | ||
740 | // mPDF 5.0.039 | ||
741 | // Note angle of rotation is reversed (from SVG to PDF), so vv[1] and vv[2] are negated | ||
742 | $transformations .= sprintf(' %.3F %.3F %.3F %.3F %.3F %.3F cm ', $vv[0], -$vv[1], -$vv[2], $vv[3], $vv[4]*$this->kp, -$vv[5]*$this->kp); | ||
743 | |||
744 | /* | ||
745 | // The long way of doing this?? | ||
746 | // need to reverse angle of rotation from SVG to PDF | ||
747 | $sx=sqrt(pow($vv[0],2)+pow($vv[2],2)); | ||
748 | if ($vv[0] < 0) { $sx *= -1; } // change sign | ||
749 | $sy=sqrt(pow($vv[1],2)+pow($vv[3],2)); | ||
750 | if ($vv[3] < 0) { $sy *= -1; } // change sign | ||
751 | |||
752 | // rotation angle is | ||
753 | $t=atan2($vv[1],$vv[3]); | ||
754 | $t=atan2(-$vv[2],$vv[0]); // Should be the same value or skew has been applied | ||
755 | |||
756 | // Reverse angle | ||
757 | $t *= -1; | ||
758 | |||
759 | // Rebuild matrix | ||
760 | $ma = $sx * cos($t); | ||
761 | $mb = $sy * sin($t); | ||
762 | $mc = -$sx * sin($t); | ||
763 | $md = $sy * cos($t); | ||
764 | |||
765 | // $transformations .= sprintf(' %.3F %.3F %.3F %.3F %.3F %.3F cm ', $ma, $mb, $mc, $md, $vv[4]*$this->kp, -$vv[5]*$this->kp); | ||
766 | */ | ||
767 | |||
768 | } | ||
769 | else if ($c=='translate' && count($vv)) { | ||
770 | $tm[4] = $vv[0]; | ||
771 | if (count($vv)==2) { $t_y = -$vv[1]; } | ||
772 | else { $t_y = 0; } | ||
773 | $tm[5] = $t_y; | ||
774 | $transformations .= sprintf(' 1 0 0 1 %.3F %.3F cm ', $tm[4]*$this->kp, $tm[5]*$this->kp); | ||
775 | } | ||
776 | else if ($c=='scale' && count($vv)) { | ||
777 | if (count($vv)==2) { $s_y = $vv[1]; } | ||
778 | else { $s_y = $vv[0]; } | ||
779 | $tm[0] = $vv[0]; | ||
780 | $tm[3] = $s_y; | ||
781 | $transformations .= sprintf(' %.3F 0 0 %.3F 0 0 cm ', $tm[0], $tm[3]); | ||
782 | } | ||
783 | else if ($c=='rotate' && count($vv)) { | ||
784 | $tm[0] = cos(deg2rad(-$vv[0])); | ||
785 | $tm[1] = sin(deg2rad(-$vv[0])); | ||
786 | $tm[2] = -$tm[1]; | ||
787 | $tm[3] = $tm[0]; | ||
788 | if (count($vv)==3) { | ||
789 | $transformations .= sprintf(' 1 0 0 1 %.3F %.3F cm ', $vv[1]*$this->kp, -$vv[2]*$this->kp); | ||
790 | } | ||
791 | $transformations .= sprintf(' %.3F %.3F %.3F %.3F 0 0 cm ', $tm[0], $tm[1], $tm[2], $tm[3]); | ||
792 | if (count($vv)==3) { | ||
793 | $transformations .= sprintf(' 1 0 0 1 %.3F %.3F cm ', -$vv[1]*$this->kp, $vv[2]*$this->kp); | ||
794 | } | ||
795 | } | ||
796 | else if ($c=='skewx' && count($vv)) { | ||
797 | $tm[2] = tan(deg2rad(-$vv[0])); | ||
798 | $transformations .= sprintf(' 1 0 %.3F 1 0 0 cm ', $tm[2]); | ||
799 | } | ||
800 | else if ($c=='skewy' && count($vv)) { | ||
801 | $tm[1] = tan(deg2rad(-$vv[0])); | ||
802 | $transformations .= sprintf(' 1 %.3F 0 1 0 0 cm ', $tm[1]); | ||
803 | } | ||
804 | |||
805 | } | ||
806 | } | ||
807 | $current_style['transformations'] = $transformations; | ||
808 | } | ||
809 | |||
810 | if (isset($critere_style['style'])){ | ||
811 | if (preg_match('/fill:\s*rgb\((\d+),\s*(\d+),\s*(\d+)\)/',$critere_style['style'], $m)) { | ||
812 | $current_style['fill'] = '#'.str_pad(dechex($m[1]), 2, "0", STR_PAD_LEFT).str_pad(dechex($m[2]), 2, "0", STR_PAD_LEFT).str_pad(dechex($m[3]), 2, "0", STR_PAD_LEFT); | ||
813 | } | ||
814 | else { $tmp = preg_replace("/(.*)fill:\s*([a-z0-9#_()]*|none)(.*)/i","$2",$critere_style['style']); // mPDF 4.4.003 | ||
815 | if ($tmp != $critere_style['style']){ $current_style['fill'] = $tmp; } | ||
816 | } | ||
817 | |||
818 | $tmp = preg_replace("/(.*)fill-opacity:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']); | ||
819 | if ($tmp != $critere_style['style']){ $current_style['fill-opacity'] = $tmp;} | ||
820 | |||
821 | $tmp = preg_replace("/(.*)fill-rule:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']); | ||
822 | if ($tmp != $critere_style['style']){ $current_style['fill-rule'] = $tmp;} | ||
823 | |||
824 | if (preg_match('/stroke:\s*rgb\((\d+),\s*(\d+),\s*(\d+)\)/',$critere_style['style'], $m)) { | ||
825 | $current_style['stroke'] = '#'.str_pad(dechex($m[1]), 2, "0", STR_PAD_LEFT).str_pad(dechex($m[2]), 2, "0", STR_PAD_LEFT).str_pad(dechex($m[3]), 2, "0", STR_PAD_LEFT); | ||
826 | } | ||
827 | else { $tmp = preg_replace("/(.*)stroke:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']); | ||
828 | if ($tmp != $critere_style['style']){ $current_style['stroke'] = $tmp; } | ||
829 | } | ||
830 | |||
831 | $tmp = preg_replace("/(.*)stroke-linecap:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']); | ||
832 | if ($tmp != $critere_style['style']){ $current_style['stroke-linecap'] = $tmp;} | ||
833 | |||
834 | $tmp = preg_replace("/(.*)stroke-linejoin:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']); | ||
835 | if ($tmp != $critere_style['style']){ $current_style['stroke-linejoin'] = $tmp;} | ||
836 | |||
837 | $tmp = preg_replace("/(.*)stroke-miterlimit:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']); | ||
838 | if ($tmp != $critere_style['style']){ $current_style['stroke-miterlimit'] = $tmp;} | ||
839 | |||
840 | $tmp = preg_replace("/(.*)stroke-opacity:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']); | ||
841 | if ($tmp != $critere_style['style']){ $current_style['stroke-opacity'] = $tmp; } | ||
842 | |||
843 | $tmp = preg_replace("/(.*)stroke-width:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']); | ||
844 | if ($tmp != $critere_style['style']){ $current_style['stroke-width'] = $tmp;} | ||
845 | |||
846 | // mPDF 4.4.003 | ||
847 | $tmp = preg_replace("/(.*)stroke-dasharray:\s*([a-z0-9., ]*|none)(.*)/i","$2",$critere_style['style']); | ||
848 | if ($tmp != $critere_style['style']){ $current_style['stroke-dasharray'] = $tmp;} | ||
849 | |||
850 | // mPDF 4.4.003 | ||
851 | $tmp = preg_replace("/(.*)stroke-dashoffset:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']); | ||
852 | if ($tmp != $critere_style['style']){ $current_style['stroke-dashoffset'] = $tmp;} | ||
853 | |||
854 | } | ||
855 | if(isset($critere_style['fill'])){ | ||
856 | $current_style['fill'] = $critere_style['fill']; | ||
857 | } | ||
858 | |||
859 | if(isset($critere_style['fill-opacity'])){ | ||
860 | $current_style['fill-opacity'] = $critere_style['fill-opacity']; | ||
861 | } | ||
862 | |||
863 | if(isset($critere_style['fill-rule'])){ | ||
864 | $current_style['fill-rule'] = $critere_style['fill-rule']; | ||
865 | } | ||
866 | |||
867 | if(isset($critere_style['stroke'])){ | ||
868 | $current_style['stroke'] = $critere_style['stroke']; | ||
869 | } | ||
870 | |||
871 | if(isset($critere_style['stroke-linecap'])){ | ||
872 | $current_style['stroke-linecap'] = $critere_style['stroke-linecap']; | ||
873 | } | ||
874 | |||
875 | if(isset($critere_style['stroke-linejoin'])){ | ||
876 | $current_style['stroke-linejoin'] = $critere_style['stroke-linejoin']; | ||
877 | } | ||
878 | |||
879 | if(isset($critere_style['stroke-miterlimit'])){ | ||
880 | $current_style['stroke-miterlimit'] = $critere_style['stroke-miterlimit']; | ||
881 | } | ||
882 | |||
883 | if(isset($critere_style['stroke-opacity'])){ | ||
884 | $current_style['stroke-opacity'] = $critere_style['stroke-opacity']; | ||
885 | } | ||
886 | |||
887 | if(isset($critere_style['stroke-width'])){ | ||
888 | $current_style['stroke-width'] = $critere_style['stroke-width']; | ||
889 | } | ||
890 | |||
891 | // mPDF 4.4.003 | ||
892 | if(isset($critere_style['stroke-dasharray'])){ | ||
893 | $current_style['stroke-dasharray'] = $critere_style['stroke-dasharray']; | ||
894 | } | ||
895 | if(isset($critere_style['stroke-dashoffset'])){ | ||
896 | $current_style['stroke-dashoffset'] = $critere_style['stroke-dashoffset']; | ||
897 | } | ||
898 | |||
899 | // mPDF 4.4.005 Used as indirect setting for currentColor | ||
900 | if(isset($critere_style['color']) && $critere_style['color'] != 'inherit'){ | ||
901 | $current_style['color'] = $critere_style['color']; | ||
902 | } | ||
903 | |||
904 | return $current_style; | ||
905 | |||
906 | } | ||
907 | |||
908 | // | ||
909 | // Cette fonction ecrit le style dans le stream svg. | ||
910 | function svgStyle($critere_style, $attribs, $element){ | ||
911 | $path_style = ''; | ||
912 | if (substr_count($critere_style['fill'],'url')>0){ | ||
913 | // | ||
914 | // couleur degradé | ||
915 | $id_gradient = preg_replace("/url\(#([\w_]*)\)/i","$1",$critere_style['fill']); | ||
916 | if ($id_gradient != $critere_style['fill']) { | ||
917 | if (isset($this->svg_gradient[$id_gradient])) { | ||
918 | $fill_gradient = $this->svgGradient($this->svg_gradient[$id_gradient], $attribs, $element); | ||
919 | if ($fill_gradient) { // mPDF 4.4.003 | ||
920 | $path_style = "q "; | ||
921 | $w = "W"; | ||
922 | $style .= 'N'; | ||
923 | } | ||
924 | } | ||
925 | } | ||
926 | |||
927 | } | ||
928 | // mPDF 4.4.005 Used as indirect setting for currentColor | ||
929 | else if (strtolower($critere_style['fill']) == 'currentcolor'){ | ||
930 | $col = $this->mpdf_ref->ConvertColor($critere_style['color']); | ||
931 | if ($col) { | ||
932 | // mPDF 5.0.051 | ||
933 | // mPDF 5.3.74 | ||
934 | if ($col{0}==5) { $critere_style['fill-opacity'] = ord($col{4}/100); } // RGBa | ||
935 | if ($col{0}==6) { $critere_style['fill-opacity'] = ord($col{5}/100); } // CMYKa | ||
936 | $path_style .= $this->mpdf_ref->SetFColor($col, true).' '; // mPDF 5.0.051 | ||
937 | $style .= 'F'; | ||
938 | } | ||
939 | } | ||
940 | else if ($critere_style['fill'] != 'none'){ | ||
941 | $col = $this->mpdf_ref->ConvertColor($critere_style['fill']); | ||
942 | if ($col) { | ||
943 | // mPDF 5.0.051 | ||
944 | // mPDF 5.3.74 | ||
945 | if ($col{0}==5) { $critere_style['fill-opacity'] = ord($col{4}/100); } // RGBa | ||
946 | if ($col{0}==6) { $critere_style['fill-opacity'] = ord($col{5}/100); } // CMYKa | ||
947 | $path_style .= $this->mpdf_ref->SetFColor($col, true).' '; // mPDF 5.0.051 | ||
948 | $style .= 'F'; | ||
949 | } | ||
950 | } | ||
951 | |||
952 | // mPDF 5.0.040 | ||
953 | if (substr_count($critere_style['stroke'],'url')>0){ | ||
954 | /* | ||
955 | // Cannot put a gradient on a "stroke" in PDF? | ||
956 | $id_gradient = preg_replace("/url\(#([\w_]*)\)/i","$1",$critere_style['stroke']); | ||
957 | if ($id_gradient != $critere_style['stroke']) { | ||
958 | if (isset($this->svg_gradient[$id_gradient])) { | ||
959 | $fill_gradient = $this->svgGradient($this->svg_gradient[$id_gradient], $attribs, $element); | ||
960 | if ($fill_gradient) { | ||
961 | $path_style = "q "; | ||
962 | $w = "W"; | ||
963 | $style .= 'D'; | ||
964 | } | ||
965 | } | ||
966 | } | ||
967 | */ | ||
968 | } | ||
969 | // mPDF 4.4.005 Used as indirect setting for currentColor | ||
970 | else if (strtolower($critere_style['stroke']) == 'currentcolor'){ | ||
971 | $col = $this->mpdf_ref->ConvertColor($critere_style['color']); | ||
972 | if ($col) { | ||
973 | // mPDF 5.0.051 | ||
974 | // mPDF 5.3.74 | ||
975 | if ($col{0}==5) { $critere_style['stroke-opacity'] = ord($col{4}/100); } // RGBa | ||
976 | if ($col{0}==6) { $critere_style['stroke-opacity'] = ord($col{5}/100); } // CMYKa | ||
977 | $path_style .= $this->mpdf_ref->SetDColor($col, true).' '; // mPDF 5.0.051 | ||
978 | $style .= 'D'; | ||
979 | $lw = $this->ConvertSVGSizePixels($critere_style['stroke-width']); | ||
980 | $path_style .= sprintf('%.3F w ',$lw*$this->kp); | ||
981 | } | ||
982 | } | ||
983 | else if ($critere_style['stroke'] != 'none'){ | ||
984 | $col = $this->mpdf_ref->ConvertColor($critere_style['stroke']); | ||
985 | if ($col) { | ||
986 | // mPDF 5.0.051 | ||
987 | // mPDF 5.3.74 | ||
988 | if ($col{0}==5) { $critere_style['stroke-opacity'] = ord($col{4}/100); } // RGBa | ||
989 | if ($col{0}==6) { $critere_style['stroke-opacity'] = ord($col{5}/100); } // CMYKa | ||
990 | $path_style .= $this->mpdf_ref->SetDColor($col, true).' '; // mPDF 5.0.051 | ||
991 | $style .= 'D'; | ||
992 | $lw = $this->ConvertSVGSizePixels($critere_style['stroke-width']); // mPDF 4.4.003 | ||
993 | $path_style .= sprintf('%.3F w ',$lw*$this->kp); | ||
994 | } | ||
995 | } | ||
996 | |||
997 | |||
998 | if ($critere_style['stroke'] != 'none'){ | ||
999 | if ($critere_style['stroke-linejoin'] == 'miter'){ | ||
1000 | $path_style .= ' 0 j '; | ||
1001 | } | ||
1002 | else if ($critere_style['stroke-linejoin'] == 'round'){ | ||
1003 | $path_style .= ' 1 j '; | ||
1004 | } | ||
1005 | else if ($critere_style['stroke-linejoin'] == 'bevel'){ | ||
1006 | $path_style .= ' 2 j '; | ||
1007 | } | ||
1008 | |||
1009 | if ($critere_style['stroke-linecap'] == 'butt'){ | ||
1010 | $path_style .= ' 0 J '; | ||
1011 | } | ||
1012 | else if ($critere_style['stroke-linecap'] == 'round'){ | ||
1013 | $path_style .= ' 1 J '; | ||
1014 | } | ||
1015 | else if ($critere_style['stroke-linecap'] == 'square'){ | ||
1016 | $path_style .= ' 2 J '; | ||
1017 | } | ||
1018 | |||
1019 | if (isset($critere_style['stroke-miterlimit'])){ | ||
1020 | if ($critere_style['stroke-miterlimit'] == 'none'){ | ||
1021 | } | ||
1022 | else if (preg_match('/^[\d.]+$/',$critere_style['stroke-miterlimit'])) { | ||
1023 | $path_style .= sprintf('%.2F M ',$critere_style['stroke-miterlimit']); | ||
1024 | } | ||
1025 | } | ||
1026 | // mPDF 4.4.003 | ||
1027 | if (isset($critere_style['stroke-dasharray'])){ | ||
1028 | $off = 0; | ||
1029 | $d = preg_split('/[ ,]/',$critere_style['stroke-dasharray']); | ||
1030 | if (count($d) == 1 && $d[0]==0) { | ||
1031 | $path_style .= '[] 0 d '; | ||
1032 | } | ||
1033 | else { | ||
1034 | if (count($d) % 2 == 1) { $d = array_merge($d, $d); } // 5, 3, 1 => 5,3,1,5,3,1 OR 3 => 3,3 | ||
1035 | $arr = ''; | ||
1036 | for($i=0; $i<count($d); $i+=2) { | ||
1037 | $arr .= sprintf('%.3F %.3F ', $d[$i]*$this->kp, $d[$i+1]*$this->kp); | ||
1038 | } | ||
1039 | if (isset($critere_style['stroke-dashoffset'])){ $off = $critere_style['stroke-dashoffset'] + 0; } | ||
1040 | $path_style .= sprintf('[%s] %.3F d ', $arr, $off*$this->kp); | ||
1041 | } | ||
1042 | } | ||
1043 | } | ||
1044 | |||
1045 | // mPDF 4.4.003 | ||
1046 | if ($critere_style['fill-rule']=='evenodd') { $fr = '*'; } | ||
1047 | else { $fr = ''; } | ||
1048 | |||
1049 | // mPDF 4.4.003 | ||
1050 | if (isset($critere_style['fill-opacity'])) { | ||
1051 | $opacity = 1; | ||
1052 | if ($critere_style['fill-opacity'] == 0) { $opacity = 0; } | ||
1053 | else if ($critere_style['fill-opacity'] > 1) { $opacity = 1; } | ||
1054 | else if ($critere_style['fill-opacity'] > 0) { $opacity = $critere_style['fill-opacity']; } | ||
1055 | else if ($critere_style['fill-opacity'] < 0) { $opacity = 0; } | ||
1056 | $gs = $this->mpdf_ref->AddExtGState(array('ca'=>$opacity, 'BM'=>'/Normal')); | ||
1057 | $this->mpdf_ref->extgstates[$gs]['fo'] = true; // mPDF 5.0.039 | ||
1058 | $path_style .= sprintf(' /GS%d gs ', $gs); | ||
1059 | } | ||
1060 | |||
1061 | // mPDF 4.4.003 | ||
1062 | if (isset($critere_style['stroke-opacity'])) { | ||
1063 | $opacity = 1; | ||
1064 | if ($critere_style['stroke-opacity'] == 0) { $opacity = 0; } | ||
1065 | else if ($critere_style['stroke-opacity'] > 1) { $opacity = 1; } | ||
1066 | else if ($critere_style['stroke-opacity'] > 0) { $opacity = $critere_style['stroke-opacity']; } | ||
1067 | else if ($critere_style['stroke-opacity'] < 0) { $opacity = 0; } | ||
1068 | $gs = $this->mpdf_ref->AddExtGState(array('CA'=>$opacity, 'BM'=>'/Normal')); | ||
1069 | $this->mpdf_ref->extgstates[$gs]['fo'] = true; // mPDF 5.0.039 | ||
1070 | $path_style .= sprintf(' /GS%d gs ', $gs); | ||
1071 | } | ||
1072 | |||
1073 | switch ($style){ | ||
1074 | case 'F': | ||
1075 | $op = 'f'; | ||
1076 | break; | ||
1077 | case 'FD': | ||
1078 | $op = 'B'; | ||
1079 | break; | ||
1080 | case 'ND': | ||
1081 | $op = 'S'; | ||
1082 | break; | ||
1083 | case 'D': | ||
1084 | $op = 'S'; | ||
1085 | break; | ||
1086 | default: | ||
1087 | $op = 'n'; | ||
1088 | } | ||
1089 | |||
1090 | // mPDF 5.0 | ||
1091 | $prestyle = $path_style.' '; | ||
1092 | $poststyle = $w.' '. $op.$fr.' '.$fill_gradient."\n"; | ||
1093 | return array($prestyle,$poststyle); | ||
1094 | |||
1095 | } | ||
1096 | |||
1097 | // | ||
1098 | // fonction retracant les <path /> | ||
1099 | function svgPath($command, $arguments){ | ||
1100 | $path_cmd = ''; | ||
1101 | $newsubpath = false; // mPDF 4.4.003 | ||
1102 | // mPDF 5.0.039 | ||
1103 | $minl = $this->pathBBox[0]; | ||
1104 | $mint = $this->pathBBox[1]; | ||
1105 | $maxr = $this->pathBBox[2]+$this->pathBBox[0]; | ||
1106 | $maxb = $this->pathBBox[3]+$this->pathBBox[1]; | ||
1107 | // mPDF 5.0.040 | ||
1108 | $start = array($this->xbase, -$this->ybase); | ||
1109 | |||
1110 | // mPDF 4.4.003 | ||
1111 | preg_match_all('/[\-^]?[\d.]+(e[\-]?[\d]+){0,1}/i', $arguments, $a, PREG_SET_ORDER); | ||
1112 | |||
1113 | // if the command is a capital letter, the coords go absolute, otherwise relative | ||
1114 | if(strtolower($command) == $command) $relative = true; | ||
1115 | else $relative = false; | ||
1116 | |||
1117 | |||
1118 | $ile_argumentow = count($a); | ||
1119 | |||
1120 | // each command may have different needs for arguments [1 to 8] | ||
1121 | |||
1122 | switch(strtolower($command)){ | ||
1123 | case 'm': // move | ||
1124 | for($i = 0; $i<$ile_argumentow; $i+=2){ | ||
1125 | $x = $a[$i][0]; | ||
1126 | $y = $a[$i+1][0]; | ||
1127 | if($relative){ | ||
1128 | $pdfx = ($this->xbase + $x); | ||
1129 | $pdfy = ($this->ybase - $y); | ||
1130 | $this->xbase += $x; | ||
1131 | $this->ybase += -$y; | ||
1132 | } | ||
1133 | else{ | ||
1134 | $pdfx = $x; | ||
1135 | $pdfy = -$y ; | ||
1136 | $this->xbase = $x; | ||
1137 | $this->ybase = -$y; | ||
1138 | } | ||
1139 | $pdf_pt = $this->svg_overflow($pdfx,$pdfy); | ||
1140 | // mPDF 5.0.039 | ||
1141 | $minl = min($minl,$pdf_pt['x']); | ||
1142 | $maxr = max($maxr,$pdf_pt['x']); | ||
1143 | $mint = min($mint,-$pdf_pt['y']); | ||
1144 | $maxb = max($maxb,-$pdf_pt['y']); | ||
1145 | if($i == 0) $path_cmd .= sprintf('%.3F %.3F m ', $pdf_pt['x']*$this->kp, $pdf_pt['y']*$this->kp); | ||
1146 | else $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x']*$this->kp, $pdf_pt['y']*$this->kp); | ||
1147 | // mPDF 4.4.003 Save start points of subpath | ||
1148 | if ($this->subPathInit) { | ||
1149 | $this->spxstart = $this->xbase; | ||
1150 | $this->spystart = $this->ybase; | ||
1151 | $this->subPathInit = false; | ||
1152 | } | ||
1153 | } | ||
1154 | break; | ||
1155 | case 'l': // a simple line | ||
1156 | for($i = 0; $i<$ile_argumentow; $i+=2){ | ||
1157 | $x = ($a[$i][0]); | ||
1158 | $y = ($a[$i+1][0]); | ||
1159 | if($relative){ | ||
1160 | $pdfx = ($this->xbase + $x); | ||
1161 | $pdfy = ($this->ybase - $y); | ||
1162 | $this->xbase += $x; | ||
1163 | $this->ybase += -$y; | ||
1164 | } | ||
1165 | else{ | ||
1166 | $pdfx = $x ; | ||
1167 | $pdfy = -$y ; | ||
1168 | $this->xbase = $x; | ||
1169 | $this->ybase = -$y; | ||
1170 | } | ||
1171 | $pdf_pt = $this->svg_overflow($pdfx,$pdfy); | ||
1172 | // mPDF 5.0.039 | ||
1173 | $minl = min($minl,$pdf_pt['x']); | ||
1174 | $maxr = max($maxr,$pdf_pt['x']); | ||
1175 | $mint = min($mint,-$pdf_pt['y']); | ||
1176 | $maxb = max($maxb,-$pdf_pt['y']); | ||
1177 | $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x']*$this->kp, $pdf_pt['y']*$this->kp); | ||
1178 | } | ||
1179 | break; | ||
1180 | case 'h': // a very simple horizontal line | ||
1181 | for($i = 0; $i<$ile_argumentow; $i++){ | ||
1182 | $x = ($a[$i][0]); | ||
1183 | if($relative){ | ||
1184 | $y = 0; | ||
1185 | $pdfx = ($this->xbase + $x) ; | ||
1186 | $pdfy = ($this->ybase - $y) ; | ||
1187 | $this->xbase += $x; | ||
1188 | $this->ybase += -$y; | ||
1189 | } | ||
1190 | else{ | ||
1191 | $y = -$this->ybase; | ||
1192 | $pdfx = $x; | ||
1193 | $pdfy = -$y; | ||
1194 | $this->xbase = $x; | ||
1195 | $this->ybase = -$y; | ||
1196 | } | ||
1197 | $pdf_pt = $this->svg_overflow($pdfx,$pdfy); | ||
1198 | // mPDF 5.0.039 | ||
1199 | $minl = min($minl,$pdf_pt['x']); | ||
1200 | $maxr = max($maxr,$pdf_pt['x']); | ||
1201 | $mint = min($mint,-$pdf_pt['y']); | ||
1202 | $maxb = max($maxb,-$pdf_pt['y']); | ||
1203 | $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x']*$this->kp, $pdf_pt['y']*$this->kp); | ||
1204 | } | ||
1205 | break; | ||
1206 | case 'v': // the simplest line, vertical | ||
1207 | for($i = 0; $i<$ile_argumentow; $i++){ | ||
1208 | $y = ($a[$i][0]); | ||
1209 | if($relative){ | ||
1210 | $x = 0; | ||
1211 | $pdfx = ($this->xbase + $x); | ||
1212 | $pdfy = ($this->ybase - $y); | ||
1213 | $this->xbase += $x; | ||
1214 | $this->ybase += -$y; | ||
1215 | } | ||
1216 | else{ | ||
1217 | $x = $this->xbase; | ||
1218 | $pdfx = $x; | ||
1219 | $pdfy = -$y; | ||
1220 | $this->xbase = $x; | ||
1221 | $this->ybase = -$y; | ||
1222 | } | ||
1223 | $pdf_pt = $this->svg_overflow($pdfx,$pdfy); | ||
1224 | // mPDF 5.0.039 | ||
1225 | $minl = min($minl,$pdf_pt['x']); | ||
1226 | $maxr = max($maxr,$pdf_pt['x']); | ||
1227 | $mint = min($mint,-$pdf_pt['y']); | ||
1228 | $maxb = max($maxb,-$pdf_pt['y']); | ||
1229 | $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x']*$this->kp, $pdf_pt['y']*$this->kp); | ||
1230 | } | ||
1231 | break; | ||
1232 | case 's': // bezier with first vertex equal first control | ||
1233 | // mPDF 4.4.003 | ||
1234 | if (!($this->lastcommand == 'C' || $this->lastcommand == 'c' || $this->lastcommand == 'S' || $this->lastcommand == 's')) { | ||
1235 | $this->lastcontrolpoints = array(0,0); | ||
1236 | } | ||
1237 | for($i = 0; $i<$ile_argumentow; $i += 4){ | ||
1238 | $x1 = $this->lastcontrolpoints[0]; | ||
1239 | $y1 = $this->lastcontrolpoints[1]; | ||
1240 | $x2 = ($a[$i][0]); | ||
1241 | $y2 = ($a[$i+1][0]); | ||
1242 | $x = ($a[$i+2][0]); | ||
1243 | $y = ($a[$i+3][0]); | ||
1244 | if($relative){ | ||
1245 | $pdfx1 = ($this->xbase + $x1); | ||
1246 | $pdfy1 = ($this->ybase - $y1); | ||
1247 | $pdfx2 = ($this->xbase + $x2); | ||
1248 | $pdfy2 = ($this->ybase - $y2); | ||
1249 | $pdfx = ($this->xbase + $x); | ||
1250 | $pdfy = ($this->ybase - $y); | ||
1251 | $this->xbase += $x; | ||
1252 | $this->ybase += -$y; | ||
1253 | } | ||
1254 | else{ | ||
1255 | $pdfx1 = $this->xbase + $x1; | ||
1256 | $pdfy1 = $this->ybase -$y1; | ||
1257 | $pdfx2 = $x2; | ||
1258 | $pdfy2 = -$y2; | ||
1259 | $pdfx = $x; | ||
1260 | $pdfy = -$y; | ||
1261 | $this->xbase = $x; | ||
1262 | $this->ybase = -$y; | ||
1263 | } | ||
1264 | $this->lastcontrolpoints = array(($pdfx-$pdfx2),-($pdfy-$pdfy2)); // mPDF 4.4.003 always relative | ||
1265 | |||
1266 | $pdf_pt = $this->svg_overflow($pdfx,$pdfy); | ||
1267 | |||
1268 | // mPDF 5.0.040 | ||
1269 | $curves = array($pdfx1,-$pdfy1,$pdfx2,-$pdfy2,$pdfx,-$pdfy); | ||
1270 | $bx = calc_bezier_bbox($start, $curves); | ||
1271 | $minl = min($minl,$bx[0]); | ||
1272 | $maxr = max($maxr,$bx[2]); | ||
1273 | $mint = min($mint,$bx[1]); | ||
1274 | $maxb = max($maxb,$bx[3]); | ||
1275 | |||
1276 | if( ($pdf_pt['x'] != $pdfx) || ($pdf_pt['y'] != $pdfy) ) | ||
1277 | { | ||
1278 | $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x']*$this->kp, $pdf_pt['y']*$this->kp); | ||
1279 | } | ||
1280 | else | ||
1281 | { | ||
1282 | $path_cmd .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', $pdfx1*$this->kp, $pdfy1*$this->kp, $pdfx2*$this->kp, $pdfy2*$this->kp, $pdfx*$this->kp, $pdfy*$this->kp); | ||
1283 | } | ||
1284 | |||
1285 | } | ||
1286 | break; | ||
1287 | case 'c': // bezier with second vertex equal second control | ||
1288 | for($i = 0; $i<$ile_argumentow; $i += 6){ | ||
1289 | $x1 = ($a[$i][0]); | ||
1290 | $y1 = ($a[$i+1][0]); | ||
1291 | $x2 = ($a[$i+2][0]); | ||
1292 | $y2 = ($a[$i+3][0]); | ||
1293 | $x = ($a[$i+4][0]); | ||
1294 | $y = ($a[$i+5][0]); | ||
1295 | |||
1296 | |||
1297 | if($relative){ | ||
1298 | $pdfx1 = ($this->xbase + $x1); | ||
1299 | $pdfy1 = ($this->ybase - $y1); | ||
1300 | $pdfx2 = ($this->xbase + $x2); | ||
1301 | $pdfy2 = ($this->ybase - $y2); | ||
1302 | $pdfx = ($this->xbase + $x); | ||
1303 | $pdfy = ($this->ybase - $y); | ||
1304 | $this->xbase += $x; | ||
1305 | $this->ybase += -$y; | ||
1306 | } | ||
1307 | else{ | ||
1308 | $pdfx1 = $x1; | ||
1309 | $pdfy1 = -$y1; | ||
1310 | $pdfx2 = $x2; | ||
1311 | $pdfy2 = -$y2; | ||
1312 | $pdfx = $x; | ||
1313 | $pdfy = -$y; | ||
1314 | $this->xbase = $x; | ||
1315 | $this->ybase = -$y; | ||
1316 | } | ||
1317 | $this->lastcontrolpoints = array(($pdfx-$pdfx2),-($pdfy-$pdfy2)); // mPDF 4.4.003 always relative | ||
1318 | // $pdf_pt2 = $this->svg_overflow($pdfx2,$pdfy2); | ||
1319 | // $pdf_pt1 = $this->svg_overflow($pdfx1,$pdfy1); | ||
1320 | $pdf_pt = $this->svg_overflow($pdfx,$pdfy); | ||
1321 | |||
1322 | // mPDF 5.0.040 | ||
1323 | $curves = array($pdfx1,-$pdfy1,$pdfx2,-$pdfy2,$pdfx,-$pdfy); | ||
1324 | $bx = calc_bezier_bbox($start, $curves); | ||
1325 | $minl = min($minl,$bx[0]); | ||
1326 | $maxr = max($maxr,$bx[2]); | ||
1327 | $mint = min($mint,$bx[1]); | ||
1328 | $maxb = max($maxb,$bx[3]); | ||
1329 | |||
1330 | if( ($pdf_pt['x'] != $pdfx) || ($pdf_pt['y'] != $pdfy) ) | ||
1331 | { | ||
1332 | $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x']*$this->kp, $pdf_pt['y']*$this->kp); | ||
1333 | } | ||
1334 | else | ||
1335 | { | ||
1336 | $path_cmd .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', $pdfx1*$this->kp, $pdfy1*$this->kp, $pdfx2*$this->kp, $pdfy2*$this->kp, $pdfx*$this->kp, $pdfy*$this->kp); | ||
1337 | } | ||
1338 | |||
1339 | } | ||
1340 | break; | ||
1341 | |||
1342 | case 'q': // bezier quadratic avec point de control | ||
1343 | for($i = 0; $i<$ile_argumentow; $i += 4){ | ||
1344 | $x1 = ($a[$i][0]); | ||
1345 | $y1 = ($a[$i+1][0]); | ||
1346 | $x = ($a[$i+2][0]); | ||
1347 | $y = ($a[$i+3][0]); | ||
1348 | if($relative){ | ||
1349 | $pdfx = ($this->xbase + $x); | ||
1350 | $pdfy = ($this->ybase - $y); | ||
1351 | |||
1352 | $pdfx1 = ($this->xbase + ($x1*2/3)); | ||
1353 | $pdfy1 = ($this->ybase - ($y1*2/3)); | ||
1354 | // mPDF 4.4.003 | ||
1355 | $pdfx2 = $pdfx1 + 1/3 *($x); | ||
1356 | $pdfy2 = $pdfy1 + 1/3 *(-$y) ; | ||
1357 | |||
1358 | $this->xbase += $x; | ||
1359 | $this->ybase += -$y; | ||
1360 | } | ||
1361 | else{ | ||
1362 | $pdfx = $x; | ||
1363 | $pdfy = -$y; | ||
1364 | |||
1365 | $pdfx1 = ($this->xbase+(($x1-$this->xbase)*2/3)); | ||
1366 | $pdfy1 = ($this->ybase-(($y1+$this->ybase)*2/3)); | ||
1367 | |||
1368 | $pdfx2 = ($x+(($x1-$x)*2/3)); | ||
1369 | $pdfy2 = (-$y-(($y1-$y)*2/3)); | ||
1370 | |||
1371 | // mPDF 4.4.003 | ||
1372 | $pdfx2 = $pdfx1 + 1/3 *($x - $this->xbase); | ||
1373 | $pdfy2 = $pdfy1 + 1/3 *(-$y - $this->ybase) ; | ||
1374 | |||
1375 | $this->xbase = $x; | ||
1376 | $this->ybase = -$y; | ||
1377 | } | ||
1378 | $this->lastcontrolpoints = array(($pdfx-$pdfx2),-($pdfy-$pdfy2)); // mPDF 4.4.003 always relative | ||
1379 | |||
1380 | $pdf_pt = $this->svg_overflow($pdfx,$pdfy); | ||
1381 | |||
1382 | // mPDF 5.0.040 | ||
1383 | $curves = array($pdfx1,-$pdfy1,$pdfx2,-$pdfy2,$pdfx,-$pdfy); | ||
1384 | $bx = calc_bezier_bbox($start, $curves); | ||
1385 | $minl = min($minl,$bx[0]); | ||
1386 | $maxr = max($maxr,$bx[2]); | ||
1387 | $mint = min($mint,$bx[1]); | ||
1388 | $maxb = max($maxb,$bx[3]); | ||
1389 | |||
1390 | if( ($pdf_pt['x'] != $pdfx) || ($pdf_pt['y'] != $pdfy) ) | ||
1391 | { | ||
1392 | $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x']*$this->kp, $pdf_pt['y']*$this->kp); | ||
1393 | } | ||
1394 | else | ||
1395 | { | ||
1396 | $path_cmd .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', $pdfx1*$this->kp, $pdfy1*$this->kp, $pdfx2*$this->kp, $pdfy2*$this->kp, $pdfx*$this->kp, $pdfy*$this->kp); | ||
1397 | } | ||
1398 | } | ||
1399 | break; | ||
1400 | case 't': // bezier quadratic avec point de control simetrique a lancien point de control | ||
1401 | // mPDF 4.4.003 | ||
1402 | if (!($this->lastcommand == 'Q' || $this->lastcommand == 'q' || $this->lastcommand == 'T' || $this->lastcommand == 't')) { | ||
1403 | $this->lastcontrolpoints = array(0,0); | ||
1404 | } | ||
1405 | for($i = 0; $i<$ile_argumentow; $i += 2){ | ||
1406 | $x = ($a[$i][0]); | ||
1407 | $y = ($a[$i+1][0]); | ||
1408 | |||
1409 | $x1 = $this->lastcontrolpoints[0]; | ||
1410 | $y1 = $this->lastcontrolpoints[1]; | ||
1411 | |||
1412 | if($relative){ | ||
1413 | $pdfx = ($this->xbase + $x); | ||
1414 | $pdfy = ($this->ybase - $y); | ||
1415 | |||
1416 | $pdfx1 = ($this->xbase + ($x1)); // mPDF 4.4.003 | ||
1417 | $pdfy1 = ($this->ybase - ($y1)); // mPDF 4.4.003 | ||
1418 | // mPDF 4.4.003 | ||
1419 | $pdfx2 = $pdfx1 + 1/3 *($x); | ||
1420 | $pdfy2 = $pdfy1 + 1/3 *(-$y) ; | ||
1421 | |||
1422 | $this->xbase += $x; | ||
1423 | $this->ybase += -$y; | ||
1424 | } | ||
1425 | else{ | ||
1426 | $pdfx = $x; | ||
1427 | $pdfy = -$y; | ||
1428 | |||
1429 | $pdfx1 = ($this->xbase + ($x1)); // mPDF 4.4.003 | ||
1430 | $pdfy1 = ($this->ybase - ($y1)); // mPDF 4.4.003 | ||
1431 | // mPDF 4.4.003 | ||
1432 | $pdfx2 = $pdfx1 + 1/3 *($x - $this->xbase); | ||
1433 | $pdfy2 = $pdfy1 + 1/3 *(-$y - $this->ybase) ; | ||
1434 | |||
1435 | $this->xbase = $x; | ||
1436 | $this->ybase = -$y; | ||
1437 | } | ||
1438 | |||
1439 | $this->lastcontrolpoints = array(($pdfx-$pdfx2),-($pdfy-$pdfy2)); // mPDF 4.4.003 always relative | ||
1440 | |||
1441 | // mPDF 5.0.040 | ||
1442 | $curves = array($pdfx1,-$pdfy1,$pdfx2,-$pdfy2,$pdfx,-$pdfy); | ||
1443 | $bx = calc_bezier_bbox($start, $curves); | ||
1444 | $minl = min($minl,$bx[0]); | ||
1445 | $maxr = max($maxr,$bx[2]); | ||
1446 | $mint = min($mint,$bx[1]); | ||
1447 | $maxb = max($maxb,$bx[3]); | ||
1448 | |||
1449 | $path_cmd .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', $pdfx1*$this->kp, $pdfy1*$this->kp, $pdfx2*$this->kp, $pdfy2*$this->kp, $pdfx*$this->kp, $pdfy*$this->kp); | ||
1450 | } | ||
1451 | |||
1452 | break; | ||
1453 | case 'a': // Elliptical arc | ||
1454 | for($i = 0; $i<$ile_argumentow; $i += 7){ | ||
1455 | $rx = ($a[$i][0]); | ||
1456 | $ry = ($a[$i+1][0]); | ||
1457 | $angle = ($a[$i+2][0]); //x-axis-rotation | ||
1458 | $largeArcFlag = ($a[$i+3][0]); | ||
1459 | $sweepFlag = ($a[$i+4][0]); | ||
1460 | $x2 = ($a[$i+5][0]); | ||
1461 | $y2 = ($a[$i+6][0]); | ||
1462 | $x1 = $this->xbase; | ||
1463 | $y1 = -$this->ybase; | ||
1464 | if($relative){ | ||
1465 | $x2 = $this->xbase + $x2; | ||
1466 | $y2 = -$this->ybase + $y2; | ||
1467 | $this->xbase += ($a[$i+5][0]); | ||
1468 | $this->ybase += -($a[$i+6][0]); | ||
1469 | } | ||
1470 | else{ | ||
1471 | $this->xbase = $x2; | ||
1472 | $this->ybase = -$y2; | ||
1473 | } | ||
1474 | // mPDF 5.0.039 // mPDF 5.0.040 | ||
1475 | list($pcmd, $bounds) = $this->Arcto($x1, $y1, $x2, $y2, $rx, $ry, $angle, $largeArcFlag, $sweepFlag); | ||
1476 | $minl = min($minl,$x2,min($bounds[0])); | ||
1477 | $maxr = max($maxr,$x2,max($bounds[0])); | ||
1478 | $mint = min($mint,$y2,min($bounds[1])); | ||
1479 | $maxb = max($maxb,$y2,max($bounds[1])); | ||
1480 | $path_cmd .= $pcmd; | ||
1481 | |||
1482 | } | ||
1483 | break; | ||
1484 | case'z': | ||
1485 | $path_cmd .= 'h '; | ||
1486 | // mPDF 4.4.003 | ||
1487 | $this->subPathInit = true; | ||
1488 | $newsubpath = true; | ||
1489 | $this->xbase = $this->spxstart; | ||
1490 | $this->ybase = $this->spystart; | ||
1491 | break; | ||
1492 | default: | ||
1493 | break; | ||
1494 | } | ||
1495 | |||
1496 | if (!$newsubpath) { $this->subPathInit = false; } // mPDF 4.4.003 | ||
1497 | $this->lastcommand = $command; | ||
1498 | // mPDF 5.0.039 | ||
1499 | $this->pathBBox[0] = $minl; | ||
1500 | $this->pathBBox[1] = $mint; | ||
1501 | $this->pathBBox[2] = $maxr - $this->pathBBox[0]; | ||
1502 | $this->pathBBox[3] = $maxb - $this->pathBBox[1]; | ||
1503 | return $path_cmd; | ||
1504 | |||
1505 | } | ||
1506 | |||
1507 | function Arcto($x1, $y1, $x2, $y2, $rx, $ry, $angle, $largeArcFlag, $sweepFlag) { | ||
1508 | |||
1509 | // mPDF 5.0.040 | ||
1510 | $bounds = array(0=>array($x1,$x2),1=>array($y1,$y2)); | ||
1511 | // 1. Treat out-of-range parameters as described in | ||
1512 | // http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes | ||
1513 | // If the endpoints (x1, y1) and (x2, y2) are identical, then this | ||
1514 | // is equivalent to omitting the elliptical arc segment entirely | ||
1515 | if ($x1 == $x2 && $y1 == $y2) return array('', $bounds); // mPD 5.0.040 | ||
1516 | |||
1517 | // If rX = 0 or rY = 0 then this arc is treated as a straight line | ||
1518 | // segment (a "lineto") joining the endpoints. | ||
1519 | if ($rx == 0.0 || $ry == 0.0) { | ||
1520 | // return array(Lineto(x2, y2), $bounds); // mPD 5.0.040 | ||
1521 | } | ||
1522 | |||
1523 | // If rX or rY have negative signs, these are dropped; the absolute | ||
1524 | // value is used instead. | ||
1525 | if ($rx<0.0) $rx = -$rx; | ||
1526 | if ($ry<0.0) $ry = -$ry; | ||
1527 | |||
1528 | // 2. convert to center parameterization as shown in | ||
1529 | // http://www.w3.org/TR/SVG/implnote.html | ||
1530 | $sinPhi = sin(deg2rad($angle)); | ||
1531 | $cosPhi = cos(deg2rad($angle)); | ||
1532 | |||
1533 | $x1dash = $cosPhi * ($x1-$x2)/2.0 + $sinPhi * ($y1-$y2)/2.0; | ||
1534 | $y1dash = -$sinPhi * ($x1-$x2)/2.0 + $cosPhi * ($y1-$y2)/2.0; | ||
1535 | |||
1536 | |||
1537 | $numerator = $rx*$rx*$ry*$ry - $rx*$rx*$y1dash*$y1dash - $ry*$ry*$x1dash*$x1dash; | ||
1538 | |||
1539 | if ($numerator < 0.0) { | ||
1540 | // If rX , rY and are such that there is no solution (basically, | ||
1541 | // the ellipse is not big enough to reach from (x1, y1) to (x2, | ||
1542 | // y2)) then the ellipse is scaled up uniformly until there is | ||
1543 | // exactly one solution (until the ellipse is just big enough). | ||
1544 | |||
1545 | // -> find factor s, such that numerator' with rx'=s*rx and | ||
1546 | // ry'=s*ry becomes 0 : | ||
1547 | $s = sqrt(1.0 - $numerator/($rx*$rx*$ry*$ry)); | ||
1548 | |||
1549 | $rx *= $s; | ||
1550 | $ry *= $s; | ||
1551 | $root = 0.0; | ||
1552 | |||
1553 | } | ||
1554 | else { | ||
1555 | $root = ($largeArcFlag == $sweepFlag ? -1.0 : 1.0) * sqrt( $numerator/($rx*$rx*$y1dash*$y1dash+$ry*$ry*$x1dash*$x1dash) ); | ||
1556 | } | ||
1557 | |||
1558 | $cxdash = $root*$rx*$y1dash/$ry; | ||
1559 | $cydash = -$root*$ry*$x1dash/$rx; | ||
1560 | |||
1561 | $cx = $cosPhi * $cxdash - $sinPhi * $cydash + ($x1+$x2)/2.0; | ||
1562 | $cy = $sinPhi * $cxdash + $cosPhi * $cydash + ($y1+$y2)/2.0; | ||
1563 | |||
1564 | |||
1565 | $theta1 = $this->CalcVectorAngle(1.0, 0.0, ($x1dash-$cxdash)/$rx, ($y1dash-$cydash)/$ry); | ||
1566 | $dtheta = $this->CalcVectorAngle(($x1dash-$cxdash)/$rx, ($y1dash-$cydash)/$ry, (-$x1dash-$cxdash)/$rx, (-$y1dash-$cydash)/$ry); | ||
1567 | if (!$sweepFlag && $dtheta>0) | ||
1568 | $dtheta -= 2.0*M_PI; | ||
1569 | else if ($sweepFlag && $dtheta<0) | ||
1570 | $dtheta += 2.0*M_PI; | ||
1571 | |||
1572 | // 3. convert into cubic bezier segments <= 90deg | ||
1573 | $segments = ceil(abs($dtheta/(M_PI/2.0))); | ||
1574 | $delta = $dtheta/$segments; | ||
1575 | $t = 8.0/3.0 * sin($delta/4.0) * sin($delta/4.0) / sin($delta/2.0); | ||
1576 | $coords = array(); | ||
1577 | for ($i = 0; $i < $segments; $i++) { | ||
1578 | $cosTheta1 = cos($theta1); | ||
1579 | $sinTheta1 = sin($theta1); | ||
1580 | $theta2 = $theta1 + $delta; | ||
1581 | $cosTheta2 = cos($theta2); | ||
1582 | $sinTheta2 = sin($theta2); | ||
1583 | |||
1584 | // a) calculate endpoint of the segment: | ||
1585 | $xe = $cosPhi * $rx*$cosTheta2 - $sinPhi * $ry*$sinTheta2 + $cx; | ||
1586 | $ye = $sinPhi * $rx*$cosTheta2 + $cosPhi * $ry*$sinTheta2 + $cy; | ||
1587 | |||
1588 | // b) calculate gradients at start/end points of segment: | ||
1589 | $dx1 = $t * ( - $cosPhi * $rx*$sinTheta1 - $sinPhi * $ry*$cosTheta1); | ||
1590 | $dy1 = $t * ( - $sinPhi * $rx*$sinTheta1 + $cosPhi * $ry*$cosTheta1); | ||
1591 | |||
1592 | $dxe = $t * ( $cosPhi * $rx*$sinTheta2 + $sinPhi * $ry*$cosTheta2); | ||
1593 | $dye = $t * ( $sinPhi * $rx*$sinTheta2 - $cosPhi * $ry*$cosTheta2); | ||
1594 | |||
1595 | // c) draw the cubic bezier: | ||
1596 | $coords[$i] = array(($x1+$dx1), ($y1+$dy1), ($xe+$dxe), ($ye+$dye), $xe, $ye); | ||
1597 | |||
1598 | // do next segment | ||
1599 | $theta1 = $theta2; | ||
1600 | $x1 = $xe; | ||
1601 | $y1 = $ye; | ||
1602 | } | ||
1603 | $path = ' '; | ||
1604 | foreach($coords AS $c) { | ||
1605 | $cpx1 = $c[0]; | ||
1606 | $cpy1 = $c[1]; | ||
1607 | $cpx2 = $c[2]; | ||
1608 | $cpy2 = $c[3]; | ||
1609 | $x2 = $c[4]; | ||
1610 | $y2 = $c[5]; | ||
1611 | $path .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', $cpx1*$this->kp, -$cpy1*$this->kp, $cpx2*$this->kp, -$cpy2*$this->kp, $x2*$this->kp, -$y2*$this->kp) ."\n"; | ||
1612 | |||
1613 | // mPDF 5.0.040 | ||
1614 | $bounds[0][] = $c[4]; | ||
1615 | $bounds[1][] = $c[5]; | ||
1616 | } | ||
1617 | return array($path, $bounds); // mPD 5.0.040 | ||
1618 | } | ||
1619 | |||
1620 | |||
1621 | function CalcVectorAngle($ux, $uy, $vx, $vy) { | ||
1622 | $ta = atan2($uy, $ux); | ||
1623 | $tb = atan2($vy, $vx); | ||
1624 | if ($tb >= $ta) | ||
1625 | return ($tb-$ta); | ||
1626 | return (6.28318530718 - ($ta-$tb)); | ||
1627 | } | ||
1628 | |||
1629 | |||
1630 | // mPDF 4.4.003 | ||
1631 | function ConvertSVGSizePixels($size=5,$maxsize='x'){ | ||
1632 | // maxsize in pixels (user units) or 'y' or 'x' | ||
1633 | // e.g. $w = $this->ConvertSVGSizePixels($arguments['w'],$this->svg_info['w']*(25.4/$this->mpdf_ref->dpi)); | ||
1634 | // usefontsize - setfalse for e.g. margins - will ignore fontsize for % values | ||
1635 | // Depends of maxsize value to make % work properly. Usually maxsize == pagewidth | ||
1636 | // For text $maxsize = Fontsize | ||
1637 | // Setting e.g. margin % will use maxsize (pagewidth) and em will use fontsize | ||
1638 | |||
1639 | if ($maxsize == 'y') { $maxsize = $this->svg_info['h']; } | ||
1640 | else if ($maxsize == 'x') { $maxsize = $this->svg_info['w']; } | ||
1641 | $maxsize *= (25.4/$this->mpdf_ref->dpi); // convert pixels to mm | ||
1642 | $fontsize=$this->mpdf_ref->FontSize; | ||
1643 | //Return as pixels | ||
1644 | $size = $this->mpdf_ref->ConvertSize($size,$maxsize,$fontsize,false) * 1/(25.4/$this->mpdf_ref->dpi); | ||
1645 | return $size; | ||
1646 | } | ||
1647 | |||
1648 | // mPDF 4.4.003 | ||
1649 | function ConvertSVGSizePts($size=5){ | ||
1650 | // usefontsize - setfalse for e.g. margins - will ignore fontsize for % values | ||
1651 | // Depends of maxsize value to make % work properly. Usually maxsize == pagewidth | ||
1652 | // For text $maxsize = Fontsize | ||
1653 | // Setting e.g. margin % will use maxsize (pagewidth) and em will use fontsize | ||
1654 | $maxsize=$this->mpdf_ref->FontSize; | ||
1655 | //Return as pts | ||
1656 | $size = $this->mpdf_ref->ConvertSize($size,$maxsize,false,true) * 72/25.4; | ||
1657 | return $size; | ||
1658 | } | ||
1659 | |||
1660 | |||
1661 | // | ||
1662 | // fonction retracant les <rect /> | ||
1663 | function svgRect($arguments){ | ||
1664 | |||
1665 | if ($arguments['h']==0 || $arguments['w']==0) { return ''; } // mPDF 4.4.003 | ||
1666 | |||
1667 | $x = $this->ConvertSVGSizePixels($arguments['x'],'x'); // mPDF 4.4.003 | ||
1668 | $y = $this->ConvertSVGSizePixels($arguments['y'],'y'); // mPDF 4.4.003 | ||
1669 | $h = $this->ConvertSVGSizePixels($arguments['h'],'y'); // mPDF 4.4.003 | ||
1670 | $w = $this->ConvertSVGSizePixels($arguments['w'],'x'); // mPDF 4.4.003 | ||
1671 | $rx = $this->ConvertSVGSizePixels($arguments['rx'],'x'); // mPDF 4.4.003 | ||
1672 | $ry = $this->ConvertSVGSizePixels($arguments['ry'],'y'); // mPDF 4.4.003 | ||
1673 | |||
1674 | if ($rx > $w/2) { $rx = $w/2; } // mPDF 4.4.003 | ||
1675 | if ($ry > $h/2) { $ry = $h/2; } // mPDF 4.4.003 | ||
1676 | |||
1677 | if ($rx>0 and $ry == 0){$ry = $rx;} | ||
1678 | if ($ry>0 and $rx == 0){$rx = $ry;} | ||
1679 | |||
1680 | if ($rx == 0 and $ry == 0){ | ||
1681 | // trace un rectangle sans angle arrondit | ||
1682 | $path_cmd = sprintf('%.3F %.3F m ', ($x*$this->kp), -($y*$this->kp)); | ||
1683 | $path_cmd .= sprintf('%.3F %.3F l ', (($x+$w)*$this->kp), -($y*$this->kp)); | ||
1684 | $path_cmd .= sprintf('%.3F %.3F l ', (($x+$w)*$this->kp), -(($y+$h)*$this->kp)); | ||
1685 | $path_cmd .= sprintf('%.3F %.3F l ', ($x)*$this->kp, -(($y+$h)*$this->kp)); | ||
1686 | $path_cmd .= sprintf('%.3F %.3F l h ', ($x*$this->kp), -($y*$this->kp)); | ||
1687 | |||
1688 | |||
1689 | } | ||
1690 | else { | ||
1691 | // trace un rectangle avec les arrondit | ||
1692 | // les points de controle du bezier sont deduis grace a la constante kappa | ||
1693 | $kappa = 4*(sqrt(2)-1)/3; | ||
1694 | |||
1695 | $kx = $kappa*$rx; | ||
1696 | $ky = $kappa*$ry; | ||
1697 | |||
1698 | $path_cmd = sprintf('%.3F %.3F m ', ($x+$rx)*$this->kp, -$y*$this->kp); | ||
1699 | $path_cmd .= sprintf('%.3F %.3F l ', ($x+($w-$rx))*$this->kp, -$y*$this->kp); | ||
1700 | $path_cmd .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', ($x+($w-$rx+$kx))*$this->kp, -$y*$this->kp, ($x+$w)*$this->kp, (-$y+(-$ry+$ky))*$this->kp, ($x+$w)*$this->kp, (-$y+(-$ry))*$this->kp ); | ||
1701 | $path_cmd .= sprintf('%.3F %.3F l ', ($x+$w)*$this->kp, (-$y+(-$h+$ry))*$this->kp); | ||
1702 | $path_cmd .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', ($x+$w)*$this->kp, (-$y+(-$h-$ky+$ry))*$this->kp, ($x+($w-$rx+$kx))*$this->kp, (-$y+(-$h))*$this->kp, ($x+($w-$rx))*$this->kp, (-$y+(-$h))*$this->kp ); | ||
1703 | |||
1704 | $path_cmd .= sprintf('%.3F %.3F l ', ($x+$rx)*$this->kp, (-$y+(-$h))*$this->kp); | ||
1705 | $path_cmd .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', ($x+($rx-$kx))*$this->kp, (-$y+(-$h))*$this->kp, $x*$this->kp, (-$y+(-$h-$ky+$ry))*$this->kp, $x*$this->kp, (-$y+(-$h+$ry))*$this->kp ); | ||
1706 | $path_cmd .= sprintf('%.3F %.3F l ', $x*$this->kp, (-$y+(-$ry))*$this->kp); | ||
1707 | $path_cmd .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c h ', $x*$this->kp, (-$y+(-$ry+$ky))*$this->kp, ($x+($rx-$kx))*$this->kp, -$y*$this->kp, ($x+$rx)*$this->kp, -$y*$this->kp ); | ||
1708 | |||
1709 | |||
1710 | } | ||
1711 | return $path_cmd; | ||
1712 | } | ||
1713 | |||
1714 | // | ||
1715 | // fonction retracant les <ellipse /> et <circle /> | ||
1716 | // le cercle est tracé grave a 4 bezier cubic, les poitn de controles | ||
1717 | // sont deduis grace a la constante kappa * rayon | ||
1718 | function svgEllipse($arguments){ | ||
1719 | if ($arguments['rx']==0 || $arguments['ry']==0) { return ''; } // mPDF 4.4.003 | ||
1720 | |||
1721 | $kappa = 4*(sqrt(2)-1)/3; | ||
1722 | |||
1723 | $cx = $this->ConvertSVGSizePixels($arguments['cx'],'x'); // mPDF 4.4.003 | ||
1724 | $cy = $this->ConvertSVGSizePixels($arguments['cy'],'y'); // mPDF 4.4.003 | ||
1725 | $rx = $this->ConvertSVGSizePixels($arguments['rx'],'x'); // mPDF 4.4.003 | ||
1726 | $ry = $this->ConvertSVGSizePixels($arguments['ry'],'y'); // mPDF 4.4.003 | ||
1727 | |||
1728 | $x1 = $cx; | ||
1729 | $y1 = -$cy+$ry; | ||
1730 | |||
1731 | $x2 = $cx+$rx; | ||
1732 | $y2 = -$cy; | ||
1733 | |||
1734 | $x3 = $cx; | ||
1735 | $y3 = -$cy-$ry; | ||
1736 | |||
1737 | $x4 = $cx-$rx; | ||
1738 | $y4 = -$cy; | ||
1739 | |||
1740 | $path_cmd = sprintf('%.3F %.3F m ', $x1*$this->kp, $y1*$this->kp); | ||
1741 | $path_cmd .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', ($x1+($rx*$kappa))*$this->kp, $y1*$this->kp, $x2*$this->kp, ($y2+($ry*$kappa))*$this->kp, $x2*$this->kp, $y2*$this->kp); | ||
1742 | $path_cmd .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', $x2*$this->kp, ($y2-($ry*$kappa))*$this->kp, ($x3+($rx*$kappa))*$this->kp, $y3*$this->kp, $x3*$this->kp, $y3*$this->kp); | ||
1743 | $path_cmd .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', ($x3-($rx*$kappa))*$this->kp, $y3*$this->kp, $x4*$this->kp, ($y4-($ry*$kappa))*$this->kp, $x4*$this->kp, $y4*$this->kp); | ||
1744 | $path_cmd .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', $x4*$this->kp, ($y4+($ry*$kappa))*$this->kp, ($x1-($rx*$kappa))*$this->kp, $y1*$this->kp, $x1*$this->kp, $y1*$this->kp); | ||
1745 | $path_cmd .= 'h '; | ||
1746 | |||
1747 | return $path_cmd; | ||
1748 | |||
1749 | } | ||
1750 | |||
1751 | // | ||
1752 | // fonction retracant les <polyline /> et les <line /> | ||
1753 | function svgPolyline($arguments,$ispolyline=true){ | ||
1754 | if ($ispolyline) { | ||
1755 | $xbase = $arguments[0] ; | ||
1756 | $ybase = - $arguments[1] ; | ||
1757 | } | ||
1758 | else { | ||
1759 | if ($arguments[0]==$arguments[2] && $arguments[1]==$arguments[3]) { return ''; } // mPDF 4.4.003 Zero length line | ||
1760 | $xbase = $this->ConvertSVGSizePixels($arguments[0],'x'); // mPDF 4.4.003 | ||
1761 | $ybase = - $this->ConvertSVGSizePixels($arguments[1],'y'); // mPDF 4.4.003 | ||
1762 | } | ||
1763 | $path_cmd = sprintf('%.3F %.3F m ', $xbase*$this->kp, $ybase*$this->kp); | ||
1764 | for ($i = 2; $i<count($arguments);$i += 2) { | ||
1765 | if ($ispolyline) { | ||
1766 | $tmp_x = $arguments[$i] ; | ||
1767 | $tmp_y = - $arguments[($i+1)] ; | ||
1768 | } | ||
1769 | else { | ||
1770 | $tmp_x = $this->ConvertSVGSizePixels($arguments[$i],'x') ; // mPDF 4.4.003 | ||
1771 | $tmp_y = - $this->ConvertSVGSizePixels($arguments[($i+1)],'y') ; // mPDF 4.4.003 | ||
1772 | } | ||
1773 | $path_cmd .= sprintf('%.3F %.3F l ', $tmp_x*$this->kp, $tmp_y*$this->kp); | ||
1774 | } | ||
1775 | |||
1776 | // $path_cmd .= 'h '; // ?? In error - don't close subpath here | ||
1777 | return $path_cmd; | ||
1778 | |||
1779 | } | ||
1780 | |||
1781 | // | ||
1782 | // fonction retracant les <polygone /> | ||
1783 | function svgPolygon($arguments){ | ||
1784 | $xbase = $arguments[0] ; | ||
1785 | $ybase = - $arguments[1] ; | ||
1786 | $path_cmd = sprintf('%.3F %.3F m ', $xbase*$this->kp, $ybase*$this->kp); | ||
1787 | for ($i = 2; $i<count($arguments);$i += 2) { | ||
1788 | $tmp_x = $arguments[$i] ; | ||
1789 | $tmp_y = - $arguments[($i+1)] ; | ||
1790 | |||
1791 | $path_cmd .= sprintf('%.3F %.3F l ', $tmp_x*$this->kp, $tmp_y*$this->kp); | ||
1792 | |||
1793 | } | ||
1794 | $path_cmd .= sprintf('%.3F %.3F l ', $xbase*$this->kp, $ybase*$this->kp); | ||
1795 | $path_cmd .= 'h '; | ||
1796 | return $path_cmd; | ||
1797 | |||
1798 | } | ||
1799 | |||
1800 | // | ||
1801 | // write string to image | ||
1802 | function svgText() { | ||
1803 | // $tmp = count($this->txt_style)-1; | ||
1804 | $current_style = array_pop($this->txt_style); | ||
1805 | $style = ''; | ||
1806 | $render = -1; | ||
1807 | if(isset($this->txt_data[2])) | ||
1808 | { | ||
1809 | // select font | ||
1810 | $style .= ($current_style['font-weight'] == 'bold')?'B':''; | ||
1811 | $style .= ($current_style['font-style'] == 'italic')?'I':''; | ||
1812 | $size = $current_style['font-size']*$this->kf; // mPDF 5.0.039 | ||
1813 | |||
1814 | // mPDF 5.0 | ||
1815 | $current_style['font-family'] = $this->mpdf_ref->SetFont($current_style['font-family'],$style,$size,false); | ||
1816 | $this->mpdf_ref->CurrentFont['fo'] = true; // mPDF 5.0.039 | ||
1817 | |||
1818 | |||
1819 | // mPDF 5.0.041 | ||
1820 | $opacitystr = ''; | ||
1821 | $opacity = 1; | ||
1822 | if (isset($current_style['fill-opacity'])) { | ||
1823 | if ($current_style['fill-opacity'] == 0) { $opacity = 0; } | ||
1824 | else if ($current_style['fill-opacity'] > 1) { $opacity = 1; } | ||
1825 | else if ($current_style['fill-opacity'] > 0) { $opacity = $current_style['fill-opacity']; } | ||
1826 | else if ($current_style['fill-opacity'] < 0) { $opacity = 0; } | ||
1827 | } | ||
1828 | $gs = $this->mpdf_ref->AddExtGState(array('ca'=>$opacity, 'BM'=>'/Normal')); | ||
1829 | $this->mpdf_ref->extgstates[$gs]['fo'] = true; // mPDF 5.0.039 | ||
1830 | $opacitystr = sprintf(' /GS%d gs ', $gs); | ||
1831 | |||
1832 | // mPDF 5.0.051 | ||
1833 | $fillstr = ''; | ||
1834 | if (isset($current_style['fill']) && $current_style['fill']!='none') { | ||
1835 | $col = $this->mpdf_ref->ConvertColor($current_style['fill']); | ||
1836 | // mPDF 5.0.051 | ||
1837 | $fillstr = $this->mpdf_ref->SetFColor($col, true); | ||
1838 | $render = "0"; // Fill (only) | ||
1839 | } | ||
1840 | $strokestr = ''; | ||
1841 | if (isset($current_style['stroke-width']) && $current_style['stroke-width']>0 && $current_style['stroke']!='none') { | ||
1842 | $scol = $this->mpdf_ref->ConvertColor($current_style['stroke']); | ||
1843 | if ($scol) { | ||
1844 | $strokestr .= $this->mpdf_ref->SetDColor($scol, true).' '; // mPDF 5.0.051 | ||
1845 | } | ||
1846 | $linewidth = $this->ConvertSVGSizePixels($current_style['stroke-width']); | ||
1847 | if ($linewidth > 0) { | ||
1848 | $strokestr .= sprintf('%.3F w 1 J 1 j ',$linewidth*$this->kp); | ||
1849 | if ($render == -1) { $render = "1"; } // stroke only | ||
1850 | else { $render = "2"; } // fill and stroke | ||
1851 | } | ||
1852 | } | ||
1853 | if ($render == -1) { return ''; } | ||
1854 | |||
1855 | $x = $this->ConvertSVGSizePixels($this->txt_data[0],'x'); // mPDF 4.4.003 | ||
1856 | $y = $this->ConvertSVGSizePixels($this->txt_data[1],'y'); // mPDF 4.4.003 | ||
1857 | $txt = $this->txt_data[2]; | ||
1858 | |||
1859 | // mPDF 4.4.003 | ||
1860 | $txt = preg_replace('/\f/','',$txt); | ||
1861 | $txt = preg_replace('/\r/','',$txt); | ||
1862 | $txt = preg_replace('/\n/',' ',$txt); | ||
1863 | $txt = preg_replace('/\t/',' ',$txt); | ||
1864 | $txt = preg_replace("/[ ]+/u",' ',$txt); | ||
1865 | |||
1866 | $txt = trim($txt); | ||
1867 | |||
1868 | $txt = $this->mpdf_ref->purify_utf8_text($txt); | ||
1869 | if ($this->mpdf_ref->text_input_as_HTML) { | ||
1870 | $txt = $this->mpdf_ref->all_entities_to_utf8($txt); | ||
1871 | } | ||
1872 | |||
1873 | // mPDF 5.0 | ||
1874 | if ($this->mpdf_ref->usingCoreFont) { $txt = mb_convert_encoding($txt,$this->mpdf_ref->mb_enc,'UTF-8'); } | ||
1875 | if (preg_match("/([".$this->mpdf_ref->pregRTLchars."])/u", $txt)) { $this->mpdf_ref->biDirectional = true; } // mPDF 4.4.003 | ||
1876 | |||
1877 | $this->mpdf_ref->magic_reverse_dir($txt, true, 'ltr'); // mPDF 5.0.054 | ||
1878 | $this->mpdf_ref->ConvertIndic($txt); | ||
1879 | |||
1880 | |||
1881 | if ($current_style['text-anchor']=='middle') { | ||
1882 | $tw = $this->mpdf_ref->GetStringWidth($txt)*_MPDFK/2; // mPDF 4.4.003 // mPDF 5.4.09 | ||
1883 | } | ||
1884 | else if ($current_style['text-anchor']=='end') { | ||
1885 | $tw = $this->mpdf_ref->GetStringWidth($txt)*_MPDFK; // mPDF 4.4.003 // mPDF 5.4.09 | ||
1886 | } | ||
1887 | else $tw = 0; | ||
1888 | |||
1889 | if (!$this->mpdf_ref->usingCoreFont) { | ||
1890 | $this->mpdf_ref->UTF8StringToArray($txt); // mPDF 5.0 adds chars to subset list | ||
1891 | $txt= $this->mpdf_ref->UTF8ToUTF16BE($txt, false); | ||
1892 | } | ||
1893 | $txt='('.$this->mpdf_ref->_escape($txt).')'; | ||
1894 | $this->mpdf_ref->CurrentFont['used']= true; | ||
1895 | |||
1896 | $pdfx = $x - $tw/$this->kp; // mPDF 4.4.009 | ||
1897 | $pdfy = -$y ; | ||
1898 | $xbase = $x; | ||
1899 | $ybase = -$y; | ||
1900 | |||
1901 | // mPDF 5.0.041 | ||
1902 | // mPDF 5.0.051 | ||
1903 | $path_cmd = sprintf('q BT /F%d %s %.3F Tf %.3F %.3F Td %s Tr %s %s %s Tj ET Q ',$this->mpdf_ref->CurrentFont['i'],$opacitystr, $this->mpdf_ref->FontSizePt,$pdfx*$this->kp,$pdfy*$this->kp,$render,$fillstr,$strokestr,$txt)."\n"; | ||
1904 | unset($this->txt_data[0], $this->txt_data[1],$this->txt_data[2]); | ||
1905 | |||
1906 | // mPDF 5.4.12 | ||
1907 | if (isset($current_style['font-size-parent'])) { | ||
1908 | $this->mpdf_ref->SetFontSize($current_style['font-size-parent']); | ||
1909 | } | ||
1910 | } | ||
1911 | else | ||
1912 | { | ||
1913 | return ' '; | ||
1914 | } | ||
1915 | // $path_cmd .= 'h '; // mPDF 5.0 | ||
1916 | return $path_cmd; | ||
1917 | } | ||
1918 | |||
1919 | |||
1920 | function svgDefineTxtStyle($critere_style) | ||
1921 | { | ||
1922 | // get copy of current/default txt style, and modify it with supplied attributes | ||
1923 | $tmp = count($this->txt_style)-1; | ||
1924 | $current_style = $this->txt_style[$tmp]; | ||
1925 | if (isset($critere_style['style'])){ | ||
1926 | if (preg_match('/fill:\s*rgb\((\d+),\s*(\d+),\s*(\d+)\)/',$critere_style['style'], $m)) { | ||
1927 | $current_style['fill'] = '#'.str_pad(dechex($m[1]), 2, "0", STR_PAD_LEFT).str_pad(dechex($m[2]), 2, "0", STR_PAD_LEFT).str_pad(dechex($m[3]), 2, "0", STR_PAD_LEFT); | ||
1928 | } | ||
1929 | else { $tmp = preg_replace("/(.*)fill:\s*([a-z0-9#_()]*|none)(.*)/i","$2",$critere_style['style']); | ||
1930 | if ($tmp != $critere_style['style']){ $current_style['fill'] = $tmp; } | ||
1931 | } | ||
1932 | |||
1933 | $tmp = preg_replace("/(.*)fill-opacity:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']); | ||
1934 | if ($tmp != $critere_style['style']){ $current_style['fill-opacity'] = $tmp;} | ||
1935 | |||
1936 | $tmp = preg_replace("/(.*)fill-rule:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']); | ||
1937 | if ($tmp != $critere_style['style']){ $current_style['fill-rule'] = $tmp;} | ||
1938 | |||
1939 | if (preg_match('/stroke:\s*rgb\((\d+),\s*(\d+),\s*(\d+)\)/',$critere_style['style'], $m)) { | ||
1940 | $current_style['stroke'] = '#'.str_pad(dechex($m[1]), 2, "0", STR_PAD_LEFT).str_pad(dechex($m[2]), 2, "0", STR_PAD_LEFT).str_pad(dechex($m[3]), 2, "0", STR_PAD_LEFT); | ||
1941 | } | ||
1942 | else { $tmp = preg_replace("/(.*)stroke:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']); | ||
1943 | if ($tmp != $critere_style['style']){ $current_style['stroke'] = $tmp; } | ||
1944 | } | ||
1945 | |||
1946 | $tmp = preg_replace("/(.*)stroke-linecap:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']); | ||
1947 | if ($tmp != $critere_style['style']){ $current_style['stroke-linecap'] = $tmp;} | ||
1948 | |||
1949 | $tmp = preg_replace("/(.*)stroke-linejoin:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']); | ||
1950 | if ($tmp != $critere_style['style']){ $current_style['stroke-linejoin'] = $tmp;} | ||
1951 | |||
1952 | $tmp = preg_replace("/(.*)stroke-miterlimit:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']); | ||
1953 | if ($tmp != $critere_style['style']){ $current_style['stroke-miterlimit'] = $tmp;} | ||
1954 | |||
1955 | $tmp = preg_replace("/(.*)stroke-opacity:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']); | ||
1956 | if ($tmp != $critere_style['style']){ $current_style['stroke-opacity'] = $tmp; } | ||
1957 | |||
1958 | $tmp = preg_replace("/(.*)stroke-width:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']); | ||
1959 | if ($tmp != $critere_style['style']){ $current_style['stroke-width'] = $tmp;} | ||
1960 | |||
1961 | $tmp = preg_replace("/(.*)stroke-dasharray:\s*([a-z0-9., ]*|none)(.*)/i","$2",$critere_style['style']); | ||
1962 | if ($tmp != $critere_style['style']){ $current_style['stroke-dasharray'] = $tmp;} | ||
1963 | |||
1964 | $tmp = preg_replace("/(.*)stroke-dashoffset:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']); | ||
1965 | if ($tmp != $critere_style['style']){ $current_style['stroke-dashoffset'] = $tmp;} | ||
1966 | |||
1967 | // mPDF 5.0.039 | ||
1968 | $tmp = preg_replace("/(.*)font-family:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']); | ||
1969 | if ($tmp != $critere_style['style']){ $critere_style['font-family'] = $tmp;} | ||
1970 | |||
1971 | $tmp = preg_replace("/(.*)font-size:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']); | ||
1972 | if ($tmp != $critere_style['style']){ $critere_style['font-size'] = $tmp;} | ||
1973 | |||
1974 | $tmp = preg_replace("/(.*)font-weight:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']); | ||
1975 | if ($tmp != $critere_style['style']){ $critere_style['font-weight'] = $tmp;} | ||
1976 | |||
1977 | $tmp = preg_replace("/(.*)font-style:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']); | ||
1978 | if ($tmp != $critere_style['style']){ $critere_style['font-style'] = $tmp;} | ||
1979 | |||
1980 | } | ||
1981 | |||
1982 | if (isset($critere_style['font'])){ | ||
1983 | |||
1984 | // [ [ <'font-style'> || <'font-variant'> || <'font-weight'> ]?<'font-size'> [ / <'line-height'> ]? <'font-family'> ] | ||
1985 | |||
1986 | $tmp = preg_replace("/(.*)(italic|oblique)(.*)/i","$2",$critere_style['font']); | ||
1987 | if ($tmp != $critere_style['font']){ | ||
1988 | if($tmp == 'oblique'){ | ||
1989 | $tmp = 'italic'; | ||
1990 | } | ||
1991 | $current_style['font-style'] = $tmp; | ||
1992 | } | ||
1993 | $tmp = preg_replace("/(.*)(bold|bolder)(.*)/i","$2",$critere_style['font']); | ||
1994 | if ($tmp != $critere_style['font']){ | ||
1995 | if($tmp == 'bolder'){ | ||
1996 | $tmp = 'bold'; | ||
1997 | } | ||
1998 | $current_style['font-weight'] = $tmp; | ||
1999 | } | ||
2000 | |||
2001 | // select digits not followed by percent sign nor preceeded by forward slash | ||
2002 | $tmp = preg_replace("/(.*)\b(\d+)[\b|\/](.*)/i","$2",$critere_style['font']); | ||
2003 | if ($tmp != $critere_style['font']){ | ||
2004 | $current_style['font-size'] = $this->ConvertSVGSizePts($tmp); | ||
2005 | $this->mpdf_ref->SetFont('','',$current_style['font-size'],false); | ||
2006 | } | ||
2007 | |||
2008 | } | ||
2009 | |||
2010 | if(isset($critere_style['fill'])){ | ||
2011 | $current_style['fill'] = $critere_style['fill']; | ||
2012 | } | ||
2013 | if(isset($critere_style['stroke'])){ | ||
2014 | $current_style['stroke'] = $critere_style['stroke']; | ||
2015 | } | ||
2016 | if(isset($critere_style['stroke-width'])){ | ||
2017 | $current_style['stroke-width'] = $critere_style['stroke-width']; | ||
2018 | } | ||
2019 | |||
2020 | if(isset($critere_style['font-style'])){ | ||
2021 | if(strtolower($critere_style['font-style']) == 'oblique') | ||
2022 | { | ||
2023 | $critere_style['font-style'] = 'italic'; | ||
2024 | } | ||
2025 | $current_style['font-style'] = $critere_style['font-style']; | ||
2026 | } | ||
2027 | |||
2028 | if(isset($critere_style['font-weight'])){ | ||
2029 | if(strtolower($critere_style['font-weight']) == 'bolder') | ||
2030 | { | ||
2031 | $critere_style['font-weight'] = 'bold'; | ||
2032 | } | ||
2033 | $current_style['font-weight'] = $critere_style['font-weight']; | ||
2034 | } | ||
2035 | |||
2036 | if(isset($critere_style['font-size'])){ | ||
2037 | // mPDF 5.4.12 | ||
2038 | if (strpos($critere_style['font-size'], '%')!==false) { | ||
2039 | $current_style['font-size-parent'] = $current_style['font-size']; | ||
2040 | } | ||
2041 | $current_style['font-size'] = $this->ConvertSVGSizePts($critere_style['font-size']); | ||
2042 | $this->mpdf_ref->SetFont('','',$current_style['font-size'],false); | ||
2043 | } | ||
2044 | |||
2045 | if(isset($critere_style['font-family'])){ | ||
2046 | $v = $critere_style['font-family']; | ||
2047 | $aux_fontlist = explode(",",$v); | ||
2048 | $found = 0; | ||
2049 | foreach($aux_fontlist AS $f) { | ||
2050 | $fonttype = trim($f); | ||
2051 | $fonttype = preg_replace('/["\']*(.*?)["\']*/','\\1',$fonttype); | ||
2052 | $fonttype = preg_replace('/ /','',$fonttype); | ||
2053 | $v = strtolower(trim($fonttype)); | ||
2054 | if (isset($this->mpdf_ref->fonttrans[$v]) && $this->mpdf_ref->fonttrans[$v]) { $v = $this->mpdf_ref->fonttrans[$v]; } | ||
2055 | if ((!$this->mpdf_ref->usingCoreFont && in_array($v,$this->mpdf_ref->available_unifonts)) || | ||
2056 | ($this->mpdf_ref->usingCoreFont && in_array($v,array('courier','times','helvetica','arial'))) || | ||
2057 | in_array($v, array('sjis','uhc','big5','gb'))) { | ||
2058 | $current_style['font-family'] = $v; | ||
2059 | $found = 1; | ||
2060 | break; | ||
2061 | } | ||
2062 | } | ||
2063 | if (!$found) { | ||
2064 | foreach($aux_fontlist AS $f) { | ||
2065 | $fonttype = trim($f); | ||
2066 | $fonttype = preg_replace('/["\']*(.*?)["\']*/','\\1',$fonttype); | ||
2067 | $fonttype = preg_replace('/ /','',$fonttype); | ||
2068 | $v = strtolower(trim($fonttype)); | ||
2069 | if (isset($this->mpdf_ref->fonttrans[$v]) && $this->mpdf_ref->fonttrans[$v]) { $v = $this->mpdf_ref->fonttrans[$v]; } | ||
2070 | if (in_array($v,$this->mpdf_ref->sans_fonts) || in_array($v,$this->mpdf_ref->serif_fonts) || in_array($v,$this->mpdf_ref->mono_fonts) ) { | ||
2071 | $current_style['font-family'] = $v; | ||
2072 | break; | ||
2073 | } | ||
2074 | } | ||
2075 | } | ||
2076 | } | ||
2077 | |||
2078 | if(isset($critere_style['text-anchor'])){ | ||
2079 | $current_style['text-anchor'] = $critere_style['text-anchor']; | ||
2080 | } | ||
2081 | |||
2082 | // add current style to text style array (will remove it later after writing text to svg_string) | ||
2083 | array_push($this->txt_style,$current_style); | ||
2084 | } | ||
2085 | |||
2086 | |||
2087 | |||
2088 | // | ||
2089 | // fonction ajoutant un gradient | ||
2090 | function svgAddGradient($id,$array_gradient){ | ||
2091 | |||
2092 | $this->svg_gradient[$id] = $array_gradient; | ||
2093 | |||
2094 | } | ||
2095 | // | ||
2096 | // Ajoute une couleur dans le gradient correspondant | ||
2097 | |||
2098 | // | ||
2099 | // function ecrivant dans le svgstring | ||
2100 | function svgWriteString($content){ | ||
2101 | |||
2102 | $this->svg_string .= $content; | ||
2103 | |||
2104 | } | ||
2105 | |||
2106 | |||
2107 | |||
2108 | // analise le svg et renvoie aux fonctions precedente our le traitement | ||
2109 | function ImageSVG($data){ | ||
2110 | $this->svg_info = array(); | ||
2111 | |||
2112 | // mPDF 4.4.006 | ||
2113 | if (preg_match('/<!ENTITY/si',$data)) { | ||
2114 | // Get User-defined entities | ||
2115 | preg_match_all('/<!ENTITY\s+([a-z]+)\s+\"(.*?)\">/si',$data, $ent); | ||
2116 | // Replace entities | ||
2117 | for ($i=0; $i<count($ent[0]); $i++) { | ||
2118 | $data = preg_replace('/&'.preg_quote($ent[1][$i],'/').';/is', $ent[2][$i], $data); | ||
2119 | } | ||
2120 | } | ||
2121 | |||
2122 | |||
2123 | // mPDF 4.4.003 | ||
2124 | if (preg_match('/xlink:href=/si',$data)) { | ||
2125 | // Get links | ||
2126 | preg_match_all('/(<(linearGradient|radialgradient)[^>]*)xlink:href=["\']#(.*?)["\'](.*?)\/>/si',$data, $links); | ||
2127 | if (count($links[0])) { $links[5] = array(); } // mPDF 4.5.010 | ||
2128 | // Delete links from data - keeping in $links | ||
2129 | for ($i=0; $i<count($links[0]); $i++) { | ||
2130 | $links[5][$i] = 'tmpLink'.RAND(100000,9999999); // mPDF 4.5.010 | ||
2131 | $data = preg_replace('/'.preg_quote($links[0][$i],'/').'/is', '<MYLINKS'.$links[5][$i].'>' , $data); // mPDF 4.5.010 | ||
2132 | } | ||
2133 | // Get targets | ||
2134 | preg_match_all('/<(linearGradient|radialgradient)([^>]*)id=["\'](.*?)["\'](.*?)>(.*?)<\/(linearGradient|radialgradient)>/si',$data, $m); | ||
2135 | $targets = array(); | ||
2136 | $stops = array(); | ||
2137 | // keeping in $targets | ||
2138 | for ($i=0; $i<count($m[0]); $i++) { | ||
2139 | $stops[$m[3][$i]] = $m[5][$i]; | ||
2140 | } | ||
2141 | // Add back links this time as targets (gradients) | ||
2142 | for ($i=0; $i<count($links[0]); $i++) { | ||
2143 | $def = $links[1][$i] .' '.$links[4][$i].'>'. $stops[$links[3][$i]].'</'.$links[2][$i] .'>' ; // mPDF 4.5.010 | ||
2144 | $data = preg_replace('/<MYLINKS'.$links[5][$i].'>/is', $def , $data); // mPDF 4.5.010 | ||
2145 | } | ||
2146 | } | ||
2147 | // mPDF 4.4.003 - Removes <pattern> | ||
2148 | $data = preg_replace('/<pattern.*?<\/pattern>/is', '', $data); | ||
2149 | // mPDF 4.4.003 - Removes <marker> | ||
2150 | $data = preg_replace('/<marker.*?<\/marker>/is', '', $data); | ||
2151 | |||
2152 | $this->svg_info['data'] = $data; | ||
2153 | |||
2154 | $this->svg_string = ''; | ||
2155 | |||
2156 | // | ||
2157 | // chargement unique des fonctions | ||
2158 | if(!function_exists("xml_svg2pdf_start")){ // mPDF 5.3.76 | ||
2159 | |||
2160 | function xml_svg2pdf_start($parser, $name, $attribs){ | ||
2161 | // | ||
2162 | // definition | ||
2163 | global $svg_class, $last_gradid; | ||
2164 | |||
2165 | // mPDF 4.4.003 | ||
2166 | $svg_class->xbase = 0; | ||
2167 | $svg_class->ybase = 0; | ||
2168 | switch (strtolower($name)){ | ||
2169 | |||
2170 | // mPDF 5.0.039 - Don't output stuff inside <defs> | ||
2171 | case 'defs': | ||
2172 | $svg_class->inDefs = true; | ||
2173 | return; | ||
2174 | |||
2175 | case 'svg': | ||
2176 | $svg_class->svgOffset($attribs); | ||
2177 | break; | ||
2178 | |||
2179 | case 'path': | ||
2180 | $path = $attribs['d']; | ||
2181 | // mPDF 5.6.65 | ||
2182 | preg_match_all('/([MZLHVCSQTAmzlhvcsqta])([eE ,\-.\d]+)*/', $path, $commands, PREG_SET_ORDER); | ||
2183 | $path_cmd = ''; | ||
2184 | $svg_class->subPathInit = true; | ||
2185 | // mPDF 5.0.039 | ||
2186 | $svg_class->pathBBox = array(999999,999999,-999999,-999999); | ||
2187 | foreach($commands as $c){ | ||
2188 | if(count($c)==3 || $c[2]==''){ | ||
2189 | list($tmp, $command, $arguments) = $c; | ||
2190 | } | ||
2191 | else{ | ||
2192 | list($tmp, $command) = $c; | ||
2193 | $arguments = ''; | ||
2194 | } | ||
2195 | |||
2196 | $path_cmd .= $svg_class->svgPath($command, $arguments); | ||
2197 | } | ||
2198 | // mPDF 5.0.039 | ||
2199 | if ($svg_class->pathBBox[2]==-1999998) { $svg_class->pathBBox[2] = 100; } | ||
2200 | if ($svg_class->pathBBox[3]==-1999998) { $svg_class->pathBBox[3] = 100; } | ||
2201 | if ($svg_class->pathBBox[0]==999999) { $svg_class->pathBBox[0] = 0; } | ||
2202 | if ($svg_class->pathBBox[1]==999999) { $svg_class->pathBBox[1] = 0; } | ||
2203 | $critere_style = $attribs; | ||
2204 | unset($critere_style['d']); | ||
2205 | $path_style = $svg_class->svgDefineStyle($critere_style); | ||
2206 | break; | ||
2207 | |||
2208 | case 'rect': | ||
2209 | if (!isset($attribs['x'])) {$attribs['x'] = 0;} | ||
2210 | if (!isset($attribs['y'])) {$attribs['y'] = 0;} | ||
2211 | if (!isset($attribs['rx'])) {$attribs['rx'] = 0;} | ||
2212 | if (!isset($attribs['ry'])) {$attribs['ry'] = 0;} | ||
2213 | $arguments = array( | ||
2214 | 'x' => $attribs['x'], | ||
2215 | 'y' => $attribs['y'], | ||
2216 | 'w' => $attribs['width'], | ||
2217 | 'h' => $attribs['height'], | ||
2218 | 'rx' => $attribs['rx'], | ||
2219 | 'ry' => $attribs['ry'] | ||
2220 | ); | ||
2221 | $path_cmd = $svg_class->svgRect($arguments); | ||
2222 | $critere_style = $attribs; | ||
2223 | unset($critere_style['x'],$critere_style['y'],$critere_style['rx'],$critere_style['ry'],$critere_style['height'],$critere_style['width']); | ||
2224 | $path_style = $svg_class->svgDefineStyle($critere_style); | ||
2225 | break; | ||
2226 | |||
2227 | case 'circle': | ||
2228 | if (!isset($attribs['cx'])) {$attribs['cx'] = 0;} | ||
2229 | if (!isset($attribs['cy'])) {$attribs['cy'] = 0;} | ||
2230 | $arguments = array( | ||
2231 | 'cx' => $attribs['cx'], | ||
2232 | 'cy' => $attribs['cy'], | ||
2233 | 'rx' => $attribs['r'], | ||
2234 | 'ry' => $attribs['r'] | ||
2235 | ); | ||
2236 | $path_cmd = $svg_class->svgEllipse($arguments); | ||
2237 | $critere_style = $attribs; | ||
2238 | unset($critere_style['cx'],$critere_style['cy'],$critere_style['r']); | ||
2239 | $path_style = $svg_class->svgDefineStyle($critere_style); | ||
2240 | break; | ||
2241 | |||
2242 | case 'ellipse': | ||
2243 | if (!isset($attribs['cx'])) {$attribs['cx'] = 0;} | ||
2244 | if (!isset($attribs['cy'])) {$attribs['cy'] = 0;} | ||
2245 | $arguments = array( | ||
2246 | 'cx' => $attribs['cx'], | ||
2247 | 'cy' => $attribs['cy'], | ||
2248 | 'rx' => $attribs['rx'], | ||
2249 | 'ry' => $attribs['ry'] | ||
2250 | ); | ||
2251 | $path_cmd = $svg_class->svgEllipse($arguments); | ||
2252 | $critere_style = $attribs; | ||
2253 | unset($critere_style['cx'],$critere_style['cy'],$critere_style['rx'],$critere_style['ry']); | ||
2254 | $path_style = $svg_class->svgDefineStyle($critere_style); | ||
2255 | break; | ||
2256 | |||
2257 | case 'line': | ||
2258 | $arguments = array($attribs['x1'],$attribs['y1'],$attribs['x2'],$attribs['y2']); | ||
2259 | $path_cmd = $svg_class->svgPolyline($arguments,false); // mPDF 4.4.003 | ||
2260 | $critere_style = $attribs; | ||
2261 | unset($critere_style['x1'],$critere_style['y1'],$critere_style['x2'],$critere_style['y2']); | ||
2262 | $path_style = $svg_class->svgDefineStyle($critere_style); | ||
2263 | break; | ||
2264 | |||
2265 | case 'polyline': | ||
2266 | $path = $attribs['points']; | ||
2267 | preg_match_all('/[0-9\-\.]*/',$path, $tmp, PREG_SET_ORDER); | ||
2268 | $arguments = array(); | ||
2269 | for ($i=0;$i<count($tmp);$i++){ | ||
2270 | if ($tmp[$i][0] !=''){ | ||
2271 | array_push($arguments, $tmp[$i][0]); | ||
2272 | } | ||
2273 | } | ||
2274 | $path_cmd = $svg_class->svgPolyline($arguments); | ||
2275 | $critere_style = $attribs; | ||
2276 | unset($critere_style['points']); | ||
2277 | $path_style = $svg_class->svgDefineStyle($critere_style); | ||
2278 | break; | ||
2279 | |||
2280 | case 'polygon': | ||
2281 | $path = $attribs['points']; | ||
2282 | preg_match_all('/([\-]*[0-9\.]+)/',$path, $tmp); | ||
2283 | $arguments = array(); | ||
2284 | for ($i=0;$i<count($tmp[0]);$i++){ | ||
2285 | if ($tmp[0][$i] !=''){ | ||
2286 | array_push($arguments, $tmp[0][$i]); | ||
2287 | } | ||
2288 | } | ||
2289 | $path_cmd = $svg_class->svgPolygon($arguments); | ||
2290 | // definition du style de la forme: | ||
2291 | $critere_style = $attribs; | ||
2292 | unset($critere_style['points']); | ||
2293 | $path_style = $svg_class->svgDefineStyle($critere_style); | ||
2294 | break; | ||
2295 | |||
2296 | case 'lineargradient': | ||
2297 | $tmp_gradient = array( | ||
2298 | 'type' => 'linear', | ||
2299 | 'info' => array( | ||
2300 | 'x1' => $attribs['x1'], | ||
2301 | 'y1' => $attribs['y1'], | ||
2302 | 'x2' => $attribs['x2'], | ||
2303 | 'y2' => $attribs['y2'] | ||
2304 | ), | ||
2305 | 'transform' => $attribs['gradientTransform'], | ||
2306 | 'units' => $attribs['gradientUnits'], /* mPDF 4.4.003 */ | ||
2307 | 'spread' => $attribs['spreadMethod'], /* mPDF 5.0.040 */ | ||
2308 | 'color' => array() | ||
2309 | ); | ||
2310 | |||
2311 | $last_gradid = $attribs['id']; | ||
2312 | $svg_class->svgAddGradient($attribs['id'],$tmp_gradient); | ||
2313 | break; | ||
2314 | |||
2315 | case 'radialgradient': | ||
2316 | $tmp_gradient = array( | ||
2317 | 'type' => 'radial', | ||
2318 | 'info' => array( | ||
2319 | 'x0' => $attribs['cx'], | ||
2320 | 'y0' => $attribs['cy'], | ||
2321 | 'x1' => $attribs['fx'], | ||
2322 | 'y1' => $attribs['fy'], | ||
2323 | 'r' => $attribs['r'] | ||
2324 | ), | ||
2325 | 'transform' => $attribs['gradientTransform'], | ||
2326 | 'units' => $attribs['gradientUnits'], /* mPDF 4.4.003 */ | ||
2327 | 'spread' => $attribs['spreadMethod'], /* mPDF 5.0.040 */ | ||
2328 | 'color' => array() | ||
2329 | ); | ||
2330 | |||
2331 | $last_gradid = $attribs['id']; | ||
2332 | |||
2333 | $svg_class->svgAddGradient($attribs['id'],$tmp_gradient); | ||
2334 | |||
2335 | break; | ||
2336 | |||
2337 | case 'stop': | ||
2338 | if (!$last_gradid) break; | ||
2339 | // mPDF 4.4.003 // mPDF 5.0.040 | ||
2340 | if (isset($attribs['style']) AND preg_match('/stop-color:\s*([^;]*)/i',$attribs['style'],$m)) { | ||
2341 | $color = trim($m[1]); | ||
2342 | } else if (isset($attribs['stop-color'])) { | ||
2343 | $color = $attribs['stop-color']; | ||
2344 | } | ||
2345 | $col = $svg_class->mpdf_ref->ConvertColor($color); | ||
2346 | |||
2347 | // mPDF 5.0.051 | ||
2348 | // mPDF 5.3.74 | ||
2349 | if ($col{0}==3 || $col{0}==5) { // RGB | ||
2350 | $color_final = sprintf('%.3F %.3F %.3F',ord($col{1})/255,ord($col{2})/255,ord($col{3})/255); | ||
2351 | $svg_class->svg_gradient[$last_gradid]['colorspace']='RGB'; | ||
2352 | } | ||
2353 | else if ($col{0}==4 || $col{0}==6) { // CMYK | ||
2354 | $color_final = sprintf('%.3F %.3F %.3F %.3F',ord($col{1})/100,ord($col{2})/100,ord($col{3})/100,ord($col{4})/100); | ||
2355 | $svg_class->svg_gradient[$last_gradid]['colorspace']='CMYK'; | ||
2356 | } | ||
2357 | else if ($col{0}==1) { // Grayscale | ||
2358 | $color_final = sprintf('%.3F',ord($col{1})/255); | ||
2359 | $svg_class->svg_gradient[$last_gradid]['colorspace']='Gray'; | ||
2360 | } | ||
2361 | |||
2362 | |||
2363 | // mPDF 5.0.020 | ||
2364 | $stop_opacity = 1; | ||
2365 | // mPDF 4.4.003 | ||
2366 | if (isset($attribs['style']) AND preg_match('/stop-opacity:\s*([0-9.]*)/i',$attribs['style'],$m)) { | ||
2367 | $stop_opacity = $m[1]; | ||
2368 | } else if (isset($attribs['stop-opacity'])) { | ||
2369 | $stop_opacity = $attribs['stop-opacity']; | ||
2370 | } | ||
2371 | // mPDF 5.0.051 | ||
2372 | // mPDF 5.3.74 | ||
2373 | else if ($col{0}==5) { // RGBa | ||
2374 | $stop_opacity = ord($col{4}/100); | ||
2375 | } | ||
2376 | else if ($col{0}==6) { // CMYKa | ||
2377 | $stop_opacity = ord($col{5}/100); | ||
2378 | } | ||
2379 | |||
2380 | $tmp_color = array( | ||
2381 | 'color' => $color_final, | ||
2382 | 'offset' => $attribs['offset'], | ||
2383 | 'opacity' => $stop_opacity | ||
2384 | ); | ||
2385 | array_push($svg_class->svg_gradient[$last_gradid]['color'],$tmp_color); | ||
2386 | break; | ||
2387 | |||
2388 | |||
2389 | case 'a': | ||
2390 | if (isset($attribs['xlink:href'])) { | ||
2391 | unset($attribs['xlink:href']); // this should be a hyperlink | ||
2392 | // not handled like a xlink:href in other elements | ||
2393 | } // then continue like a <g> | ||
2394 | case 'g': | ||
2395 | $array_style = $svg_class->svgDefineStyle($attribs); | ||
2396 | if ($array_style['transformations']) { | ||
2397 | $svg_class->svgWriteString(' q '.$array_style['transformations']); | ||
2398 | } | ||
2399 | array_push($svg_class->svg_style,$array_style); | ||
2400 | |||
2401 | $svg_class->svgDefineTxtStyle($attribs); // mPDF 4.4.003 | ||
2402 | |||
2403 | break; | ||
2404 | |||
2405 | case 'text': | ||
2406 | // mPDF 4.4.003 | ||
2407 | $array_style = $svg_class->svgDefineStyle($attribs); | ||
2408 | if ($array_style['transformations']) { | ||
2409 | $svg_class->svgWriteString(' q '.$array_style['transformations']); | ||
2410 | } | ||
2411 | array_push($svg_class->svg_style,$array_style); | ||
2412 | |||
2413 | $svg_class->txt_data = array(); | ||
2414 | $svg_class->txt_data[0] = $attribs['x']; | ||
2415 | $svg_class->txt_data[1] = $attribs['y']; | ||
2416 | $critere_style = $attribs; | ||
2417 | unset($critere_style['x'], $critere_style['y']); | ||
2418 | $svg_class->svgDefineTxtStyle($critere_style); | ||
2419 | break; | ||
2420 | } | ||
2421 | |||
2422 | // | ||
2423 | //insertion des path et du style dans le flux de donné general. | ||
2424 | if (isset($path_cmd) && $path_cmd) { // mPDF 4.4.003 | ||
2425 | // mPDF 5.0 | ||
2426 | list($prestyle,$poststyle) = $svg_class->svgStyle($path_style, $attribs, strtolower($name)); | ||
2427 | if ($path_style['transformations']) { // transformation on an element | ||
2428 | $svg_class->svgWriteString(" q ".$path_style['transformations']. " $prestyle $path_cmd $poststyle" . " Q\n"); | ||
2429 | } | ||
2430 | else { | ||
2431 | $svg_class->svgWriteString("$prestyle $path_cmd $poststyle\n"); | ||
2432 | } | ||
2433 | } | ||
2434 | } | ||
2435 | |||
2436 | function characterData($parser, $data) | ||
2437 | { | ||
2438 | global $svg_class; | ||
2439 | if(isset($svg_class->txt_data[2])) { | ||
2440 | $svg_class->txt_data[2] .= $data; | ||
2441 | } | ||
2442 | else { | ||
2443 | $svg_class->txt_data[2] = $data; | ||
2444 | } | ||
2445 | } | ||
2446 | |||
2447 | |||
2448 | function xml_svg2pdf_end($parser, $name){ | ||
2449 | global $svg_class; | ||
2450 | switch($name){ | ||
2451 | |||
2452 | case "g": | ||
2453 | case "a": | ||
2454 | $tmp = count($svg_class->svg_style)-1; | ||
2455 | $current_style = $svg_class->svg_style[$tmp]; | ||
2456 | if ($current_style['transformations']) { | ||
2457 | $svg_class->svgWriteString(" Q\n"); | ||
2458 | } | ||
2459 | array_pop($svg_class->svg_style); | ||
2460 | |||
2461 | array_pop($svg_class->txt_style); // mPDF 4.4.003 | ||
2462 | |||
2463 | break; | ||
2464 | case 'radialgradient': | ||
2465 | case 'lineargradient': | ||
2466 | $last_gradid = ''; | ||
2467 | break; | ||
2468 | case "text": | ||
2469 | $path_cmd = $svg_class->svgText(); | ||
2470 | // echo 'path >> '.$path_cmd."<br><br>"; | ||
2471 | // echo "style >> ".$get_style[1]."<br><br>"; | ||
2472 | $svg_class->svgWriteString($path_cmd); | ||
2473 | // mPDF 4.4.003 | ||
2474 | $tmp = count($svg_class->svg_style)-1; | ||
2475 | $current_style = $svg_class->svg_style[$tmp]; | ||
2476 | if ($current_style['transformations']) { | ||
2477 | $svg_class->svgWriteString(" Q\n"); | ||
2478 | } | ||
2479 | array_pop($svg_class->svg_style); | ||
2480 | |||
2481 | break; | ||
2482 | } | ||
2483 | // mPDF 5.0.039 - Don't output stuff inside <defs> | ||
2484 | if ($name == 'defs') { | ||
2485 | $svg_class->inDefs = false; | ||
2486 | } | ||
2487 | |||
2488 | } | ||
2489 | |||
2490 | } | ||
2491 | |||
2492 | $svg2pdf_xml=''; | ||
2493 | global $svg_class; | ||
2494 | $svg_class = $this; | ||
2495 | // mPDF 5.0.039 - Don't output stuff inside <defs> | ||
2496 | $svg_class->inDefs = false; | ||
2497 | $svg2pdf_xml_parser = xml_parser_create("utf-8"); | ||
2498 | xml_parser_set_option($svg2pdf_xml_parser, XML_OPTION_CASE_FOLDING, false); | ||
2499 | xml_set_element_handler($svg2pdf_xml_parser, "xml_svg2pdf_start", "xml_svg2pdf_end"); | ||
2500 | xml_set_character_data_handler($svg2pdf_xml_parser, "characterData"); | ||
2501 | xml_parse($svg2pdf_xml_parser, $data); | ||
2502 | // mPDF 4.4.003 | ||
2503 | if ($this->svg_error) { return false; } | ||
2504 | else { | ||
2505 | return array('x'=>$this->svg_info['x']*$this->kp,'y'=>-$this->svg_info['y']*$this->kp,'w'=>$this->svg_info['w']*$this->kp,'h'=>-$this->svg_info['h']*$this->kp,'data'=>$svg_class->svg_string); | ||
2506 | } | ||
2507 | |||
2508 | } | ||
2509 | |||
2510 | } | ||
2511 | |||
2512 | // END OF CLASS | ||
2513 | |||
2514 | |||
2515 | // mPDF 5.0.040 | ||
2516 | function calc_bezier_bbox($start, $c) { | ||
2517 | $P0 = array($start[0],$start[1]); | ||
2518 | $P1 = array($c[0],$c[1]); | ||
2519 | $P2 = array($c[2],$c[3]); | ||
2520 | $P3 = array($c[4],$c[5]); | ||
2521 | $bounds = array(); | ||
2522 | $bounds[0][] = $P0[0]; | ||
2523 | $bounds[1][] = $P0[1]; | ||
2524 | $bounds[0][] = $P3[0]; | ||
2525 | $bounds[1][] = $P3[1]; | ||
2526 | for ($i=0;$i<=1;$i++) { | ||
2527 | $b = 6 * $P0[$i] - 12 * $P1[$i] + 6 * $P2[$i]; | ||
2528 | $a = -3 * $P0[$i] + 9 * $P1[$i] - 9 * $P2[$i] + 3 * $P3[$i]; | ||
2529 | $c = 3 * $P1[$i] - 3 * $P0[$i]; | ||
2530 | if ($a == 0) { | ||
2531 | if ($b == 0) { continue; } | ||
2532 | $t = -$c / $b; | ||
2533 | if ($t>0 && $t<1) { | ||
2534 | $bounds[$i][] = (pow((1-$t),3) * $P0[$i] + 3 * pow((1-$t),2) * $t * $P1[$i] + 3 * (1-$t) * pow($t,2) * $P2[$i] + pow($t,3) * $P3[$i]); | ||
2535 | } | ||
2536 | continue; | ||
2537 | } | ||
2538 | $b2ac = pow($b, 2) - 4 * $c * $a; | ||
2539 | if ($b2ac < 0) { continue; } | ||
2540 | $t1 = (-$b + sqrt($b2ac))/(2 * $a); | ||
2541 | if ($t1>0 && $t1<1) { | ||
2542 | $bounds[$i][] = (pow((1-$t1),3) * $P0[$i] + 3 * pow((1-$t1),2) * $t1 * $P1[$i] + 3 * (1-$t1) * pow($t1,2) * $P2[$i] + pow($t1,3) * $P3[$i]); | ||
2543 | } | ||
2544 | $t2 = (-$b - sqrt($b2ac))/(2 * $a); | ||
2545 | if ($t2>0 && $t2<1) { | ||
2546 | $bounds[$i][] = (pow((1-$t2),3) * $P0[$i] + 3 * pow((1-$t2),2) * $t2 * $P1[$i] + 3 * (1-$t2) * pow($t2,2) * $P2[$i] + pow($t2,3) * $P3[$i]); | ||
2547 | } | ||
2548 | } | ||
2549 | $x = min($bounds[0]); | ||
2550 | $x2 = max($bounds[0]); | ||
2551 | $y = min($bounds[1]); | ||
2552 | $y2 = max($bounds[1]); | ||
2553 | return array($x, $y, $x2, $y2); | ||
2554 | } | ||
2555 | |||
2556 | // mPDF 5.0.040 | ||
2557 | function _testIntersectCircle($cx, $cy, $cr) { | ||
2558 | // Tests whether a circle fully encloses a rectangle 0,0,1,1 | ||
2559 | // to see if any further radial gradients need adding (SVG) | ||
2560 | // If centre of circle is inside 0,0,1,1 square | ||
2561 | if ($cx >= 0 && $cx <= 1 && $cy >= 0 && $cy <= 1) { | ||
2562 | $maxd = 1.5; | ||
2563 | } | ||
2564 | // distance to four corners | ||
2565 | else { | ||
2566 | $d1 = sqrt(pow(($cy-0),2) + pow(($cx-0),2)); | ||
2567 | $d2 = sqrt(pow(($cy-1),2) + pow(($cx-0),2)); | ||
2568 | $d3 = sqrt(pow(($cy-0),2) + pow(($cx-1),2)); | ||
2569 | $d4 = sqrt(pow(($cy-1),2) + pow(($cx-1),2)); | ||
2570 | $maxd = max($d1,$d2,$d3,$d4); | ||
2571 | } | ||
2572 | if ($cr < $maxd) { return true; } | ||
2573 | else { return false; } | ||
2574 | } | ||
2575 | |||
2576 | // mPDF 5.0.040 | ||
2577 | function _testIntersect($x1, $y1, $x2, $y2, $x3, $y3, $x4, $y4) { | ||
2578 | // Tests whether line (x1, y1) and (x2, y2) [a gradient axis (perpendicular)] | ||
2579 | // intersects with a specific line segment (x3, y3) and (x4, y4) | ||
2580 | $a1 = $y2-$y1; | ||
2581 | $b1 = $x1-$x2; | ||
2582 | $c1 = $a1*$x1+$b1*$y1; | ||
2583 | $a2 = $y4-$y3; | ||
2584 | $b2 = $x3-$x4; | ||
2585 | $c2 = $a2*$x3+$b2*$y3; | ||
2586 | $det = $a1*$b2 - $a2*$b1; | ||
2587 | if($det == 0){ //Lines are parallel | ||
2588 | return false; | ||
2589 | } | ||
2590 | else{ | ||
2591 | $x = ($b2*$c1 - $b1*$c2)/$det; | ||
2592 | $y = ($a1*$c2 - $a2*$c1)/$det; | ||
2593 | if ($x >= $x3 && $x <= $x4 && $y >= $y3 && $y <= $y4) { return true; } | ||
2594 | } | ||
2595 | return false; | ||
2596 | } | ||
2597 | |||
2598 | |||
2599 | |||
2600 | ?> \ No newline at end of file | ||
diff --git a/inc/3rdparty/libraries/mpdf/classes/tocontents.php b/inc/3rdparty/libraries/mpdf/classes/tocontents.php new file mode 100644 index 00000000..4e0065d2 --- /dev/null +++ b/inc/3rdparty/libraries/mpdf/classes/tocontents.php | |||
@@ -0,0 +1,468 @@ | |||
1 | <?php | ||
2 | |||
3 | class tocontents { | ||
4 | |||
5 | var $mpdf = null; | ||
6 | var $_toc; | ||
7 | var $TOCmark; | ||
8 | var $TOCoutdent; // mPDF 5.6.31 | ||
9 | var $TOCpreHTML; | ||
10 | var $TOCpostHTML; | ||
11 | var $TOCbookmarkText; | ||
12 | var $TOCusePaging; | ||
13 | var $TOCuseLinking; | ||
14 | var $TOCorientation; | ||
15 | var $TOC_margin_left; | ||
16 | var $TOC_margin_right; | ||
17 | var $TOC_margin_top; | ||
18 | var $TOC_margin_bottom; | ||
19 | var $TOC_margin_header; | ||
20 | var $TOC_margin_footer; | ||
21 | var $TOC_odd_header_name; | ||
22 | var $TOC_even_header_name; | ||
23 | var $TOC_odd_footer_name; | ||
24 | var $TOC_even_footer_name; | ||
25 | var $TOC_odd_header_value; | ||
26 | var $TOC_even_header_value; | ||
27 | var $TOC_odd_footer_value; | ||
28 | var $TOC_even_footer_value; | ||
29 | var $TOC_page_selector; | ||
30 | var $m_TOC; | ||
31 | |||
32 | function tocontents(&$mpdf) { | ||
33 | $this->mpdf = $mpdf; | ||
34 | $this->_toc=array(); | ||
35 | $this->TOCmark = 0; | ||
36 | $this->m_TOC=array(); | ||
37 | } | ||
38 | |||
39 | function TOCpagebreak($tocfont='', $tocfontsize='', $tocindent='', $TOCusePaging=true, $TOCuseLinking='', $toc_orientation='', $toc_mgl='',$toc_mgr='',$toc_mgt='',$toc_mgb='',$toc_mgh='',$toc_mgf='',$toc_ohname='',$toc_ehname='',$toc_ofname='',$toc_efname='',$toc_ohvalue=0,$toc_ehvalue=0,$toc_ofvalue=0, $toc_efvalue=0, $toc_preHTML='', $toc_postHTML='', $toc_bookmarkText='', $resetpagenum='', $pagenumstyle='', $suppress='', $orientation='', $mgl='',$mgr='',$mgt='',$mgb='',$mgh='',$mgf='',$ohname='',$ehname='',$ofname='',$efname='',$ohvalue=0,$ehvalue=0,$ofvalue=0,$efvalue=0, $toc_id=0, $pagesel='', $toc_pagesel='', $sheetsize='', $toc_sheetsize='', $tocoutdent='') { // mPDF 5.6.19 | ||
40 | if (strtoupper($toc_id)=='ALL') { $toc_id = '_mpdf_all'; } | ||
41 | else if (!$toc_id) { $toc_id = 0; } | ||
42 | else { $toc_id = strtolower($toc_id); } | ||
43 | |||
44 | if ($TOCusePaging === false || strtolower($TOCusePaging) == "off" || $TOCusePaging === 0 || $TOCusePaging === "0" || $TOCusePaging === "") { $TOCusePaging = false; } | ||
45 | else { $TOCusePaging = true; } | ||
46 | if (!$TOCuseLinking) { $TOCuseLinking = false; } | ||
47 | if ($toc_id) { | ||
48 | $this->m_TOC[$toc_id]['TOCmark'] = $this->mpdf->page; | ||
49 | $this->m_TOC[$toc_id]['TOCoutdent'] = $tocoutdent; | ||
50 | $this->m_TOC[$toc_id]['TOCorientation'] = $toc_orientation; | ||
51 | $this->m_TOC[$toc_id]['TOCuseLinking'] = $TOCuseLinking; | ||
52 | $this->m_TOC[$toc_id]['TOCusePaging'] = $TOCusePaging; | ||
53 | |||
54 | if ($toc_preHTML) { $this->m_TOC[$toc_id]['TOCpreHTML'] = $toc_preHTML; } | ||
55 | if ($toc_postHTML) { $this->m_TOC[$toc_id]['TOCpostHTML'] = $toc_postHTML; } | ||
56 | if ($toc_bookmarkText) { $this->m_TOC[$toc_id]['TOCbookmarkText'] = $toc_bookmarkText; } | ||
57 | |||
58 | $this->m_TOC[$toc_id]['TOC_margin_left'] = $toc_mgl; | ||
59 | $this->m_TOC[$toc_id]['TOC_margin_right'] = $toc_mgr; | ||
60 | $this->m_TOC[$toc_id]['TOC_margin_top'] = $toc_mgt; | ||
61 | $this->m_TOC[$toc_id]['TOC_margin_bottom'] = $toc_mgb; | ||
62 | $this->m_TOC[$toc_id]['TOC_margin_header'] = $toc_mgh; | ||
63 | $this->m_TOC[$toc_id]['TOC_margin_footer'] = $toc_mgf; | ||
64 | $this->m_TOC[$toc_id]['TOC_odd_header_name'] = $toc_ohname; | ||
65 | $this->m_TOC[$toc_id]['TOC_even_header_name'] = $toc_ehname; | ||
66 | $this->m_TOC[$toc_id]['TOC_odd_footer_name'] = $toc_ofname; | ||
67 | $this->m_TOC[$toc_id]['TOC_even_footer_name'] = $toc_efname; | ||
68 | $this->m_TOC[$toc_id]['TOC_odd_header_value'] = $toc_ohvalue; | ||
69 | $this->m_TOC[$toc_id]['TOC_even_header_value'] = $toc_ehvalue; | ||
70 | $this->m_TOC[$toc_id]['TOC_odd_footer_value'] = $toc_ofvalue; | ||
71 | $this->m_TOC[$toc_id]['TOC_even_footer_value'] = $toc_efvalue; | ||
72 | $this->m_TOC[$toc_id]['TOC_page_selector'] = $toc_pagesel; | ||
73 | $this->m_TOC[$toc_id]['TOCsheetsize'] = $toc_sheetsize; | ||
74 | } | ||
75 | else { | ||
76 | $this->TOCmark = $this->mpdf->page; | ||
77 | $this->TOCoutdent = $tocoutdent; | ||
78 | $this->TOCorientation = $toc_orientation; | ||
79 | $this->TOCuseLinking = $TOCuseLinking; | ||
80 | $this->TOCusePaging = $TOCusePaging; | ||
81 | |||
82 | if ($toc_preHTML) { $this->TOCpreHTML = $toc_preHTML; } | ||
83 | if ($toc_postHTML) { $this->TOCpostHTML = $toc_postHTML; } | ||
84 | if ($toc_bookmarkText) { $this->TOCbookmarkText = $toc_bookmarkText; } | ||
85 | |||
86 | $this->TOC_margin_left = $toc_mgl; | ||
87 | $this->TOC_margin_right = $toc_mgr; | ||
88 | $this->TOC_margin_top = $toc_mgt; | ||
89 | $this->TOC_margin_bottom = $toc_mgb; | ||
90 | $this->TOC_margin_header = $toc_mgh; | ||
91 | $this->TOC_margin_footer = $toc_mgf; | ||
92 | $this->TOC_odd_header_name = $toc_ohname; | ||
93 | $this->TOC_even_header_name = $toc_ehname; | ||
94 | $this->TOC_odd_footer_name = $toc_ofname; | ||
95 | $this->TOC_even_footer_name = $toc_efname; | ||
96 | $this->TOC_odd_header_value = $toc_ohvalue; | ||
97 | $this->TOC_even_header_value = $toc_ehvalue; | ||
98 | $this->TOC_odd_footer_value = $toc_ofvalue; | ||
99 | $this->TOC_even_footer_value = $toc_efvalue; | ||
100 | $this->TOC_page_selector = $toc_pagesel; | ||
101 | $this->TOCsheetsize = $toc_sheetsize; | ||
102 | } | ||
103 | } | ||
104 | |||
105 | // Initiate, and Mark a place for the Table of Contents to be inserted | ||
106 | function TOC($tocfont='', $tocfontsize=0, $tocindent=0, $resetpagenum='', $pagenumstyle='', $suppress='', $toc_orientation='', $TOCusePaging=true, $TOCuseLinking=false, $toc_id=0, $tocoutdent='') { // mPDF 5.6.19) { | ||
107 | if (strtoupper($toc_id)=='ALL') { $toc_id = '_mpdf_all'; } | ||
108 | else if (!$toc_id) { $toc_id = 0; } | ||
109 | else { $toc_id = strtolower($toc_id); } | ||
110 | // To use odd and even pages | ||
111 | // Cannot start table of contents on an even page | ||
112 | if (($this->mpdf->mirrorMargins) && (($this->mpdf->page)%2==0)) { // EVEN | ||
113 | if ($this->mpdf->ColActive) { | ||
114 | if (count($this->mpdf->columnbuffer)) { $this->mpdf->printcolumnbuffer(); } | ||
115 | } | ||
116 | $this->mpdf->AddPage($this->mpdf->CurOrientation,'',$resetpagenum, $pagenumstyle, $suppress); | ||
117 | } | ||
118 | else { | ||
119 | $this->mpdf->PageNumSubstitutions[] = array('from'=>$this->mpdf->page, 'reset'=> $resetpagenum, 'type'=>$pagenumstyle, 'suppress'=>$suppress); | ||
120 | } | ||
121 | if ($toc_id) { | ||
122 | $this->m_TOC[$toc_id]['TOCmark'] = $this->mpdf->page; | ||
123 | $this->m_TOC[$toc_id]['TOCoutdent'] = $tocoutdent; | ||
124 | $this->m_TOC[$toc_id]['TOCorientation'] = $toc_orientation; | ||
125 | $this->m_TOC[$toc_id]['TOCuseLinking'] = $TOCuseLinking; | ||
126 | $this->m_TOC[$toc_id]['TOCusePaging'] = $TOCusePaging; | ||
127 | } | ||
128 | else { | ||
129 | $this->TOCmark = $this->mpdf->page; | ||
130 | $this->TOCoutdent = $tocoutdent; | ||
131 | $this->TOCorientation = $toc_orientation; | ||
132 | $this->TOCuseLinking = $TOCuseLinking; | ||
133 | $this->TOCusePaging = $TOCusePaging; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | |||
138 | function insertTOC() { | ||
139 | $notocs = 0; | ||
140 | if ($this->TOCmark) { $notocs = 1; } | ||
141 | $notocs += count($this->m_TOC); | ||
142 | |||
143 | if ($notocs==0) { return; } | ||
144 | |||
145 | if (count($this->m_TOC)) { reset($this->m_TOC); } | ||
146 | $added_toc_pages = 0; | ||
147 | |||
148 | if ($this->mpdf->ColActive) { $this->mpdf->SetColumns(0); } | ||
149 | if (($this->mpdf->mirrorMargins) && (($this->mpdf->page)%2==1)) { // ODD | ||
150 | $this->mpdf->AddPage($this->mpdf->CurOrientation); | ||
151 | $extrapage = true; | ||
152 | } | ||
153 | else { $extrapage = false; } | ||
154 | |||
155 | for ($toci = 0; $toci<$notocs; $toci++) { | ||
156 | if ($toci==0 && $this->TOCmark) { | ||
157 | $toc_id = 0; | ||
158 | $toc_page = $this->TOCmark; | ||
159 | $tocoutdent = $this->TOCoutdent; | ||
160 | $toc_orientation = $this->TOCorientation; | ||
161 | $TOCuseLinking = $this->TOCuseLinking; | ||
162 | $TOCusePaging = $this->TOCusePaging; | ||
163 | $toc_preHTML = $this->TOCpreHTML; | ||
164 | $toc_postHTML = $this->TOCpostHTML; | ||
165 | $toc_bookmarkText = $this->TOCbookmarkText; | ||
166 | $toc_mgl = $this->TOC_margin_left; | ||
167 | $toc_mgr = $this->TOC_margin_right; | ||
168 | $toc_mgt = $this->TOC_margin_top; | ||
169 | $toc_mgb = $this->TOC_margin_bottom; | ||
170 | $toc_mgh = $this->TOC_margin_header; | ||
171 | $toc_mgf = $this->TOC_margin_footer; | ||
172 | $toc_ohname = $this->TOC_odd_header_name; | ||
173 | $toc_ehname = $this->TOC_even_header_name; | ||
174 | $toc_ofname = $this->TOC_odd_footer_name; | ||
175 | $toc_efname = $this->TOC_even_footer_name; | ||
176 | $toc_ohvalue = $this->TOC_odd_header_value; | ||
177 | $toc_ehvalue = $this->TOC_even_header_value; | ||
178 | $toc_ofvalue = $this->TOC_odd_footer_value; | ||
179 | $toc_efvalue = $this->TOC_even_footer_value; | ||
180 | $toc_page_selector = $this->TOC_page_selector; | ||
181 | $toc_sheet_size = $this->TOCsheetsize; | ||
182 | } | ||
183 | else { | ||
184 | $arr = current($this->m_TOC); | ||
185 | |||
186 | $toc_id = key($this->m_TOC); | ||
187 | $toc_page = $this->m_TOC[$toc_id]['TOCmark']; | ||
188 | $tocoutdent = $this->m_TOC[$toc_id]['TOCoutdent']; | ||
189 | $toc_orientation = $this->m_TOC[$toc_id]['TOCorientation']; | ||
190 | $TOCuseLinking = $this->m_TOC[$toc_id]['TOCuseLinking']; | ||
191 | $TOCusePaging = $this->m_TOC[$toc_id]['TOCusePaging']; | ||
192 | if (isset($this->m_TOC[$toc_id]['TOCpreHTML'])) { $toc_preHTML = $this->m_TOC[$toc_id]['TOCpreHTML']; } | ||
193 | else { $toc_preHTML = ''; } | ||
194 | if (isset($this->m_TOC[$toc_id]['TOCpostHTML'])) { $toc_postHTML = $this->m_TOC[$toc_id]['TOCpostHTML']; } | ||
195 | else { $toc_postHTML = ''; } | ||
196 | if (isset($this->m_TOC[$toc_id]['TOCbookmarkText'])) { $toc_bookmarkText = $this->m_TOC[$toc_id]['TOCbookmarkText']; } | ||
197 | else { $toc_bookmarkText = ''; } // *BOOKMARKS* | ||
198 | $toc_mgl = $this->m_TOC[$toc_id]['TOC_margin_left']; | ||
199 | $toc_mgr = $this->m_TOC[$toc_id]['TOC_margin_right']; | ||
200 | $toc_mgt = $this->m_TOC[$toc_id]['TOC_margin_top']; | ||
201 | $toc_mgb = $this->m_TOC[$toc_id]['TOC_margin_bottom']; | ||
202 | $toc_mgh = $this->m_TOC[$toc_id]['TOC_margin_header']; | ||
203 | $toc_mgf = $this->m_TOC[$toc_id]['TOC_margin_footer']; | ||
204 | $toc_ohname = $this->m_TOC[$toc_id]['TOC_odd_header_name']; | ||
205 | $toc_ehname = $this->m_TOC[$toc_id]['TOC_even_header_name']; | ||
206 | $toc_ofname = $this->m_TOC[$toc_id]['TOC_odd_footer_name']; | ||
207 | $toc_efname = $this->m_TOC[$toc_id]['TOC_even_footer_name']; | ||
208 | $toc_ohvalue = $this->m_TOC[$toc_id]['TOC_odd_header_value']; | ||
209 | $toc_ehvalue = $this->m_TOC[$toc_id]['TOC_even_header_value']; | ||
210 | $toc_ofvalue = $this->m_TOC[$toc_id]['TOC_odd_footer_value']; | ||
211 | $toc_efvalue = $this->m_TOC[$toc_id]['TOC_even_footer_value']; | ||
212 | $toc_page_selector = $this->m_TOC[$toc_id]['TOC_page_selector']; | ||
213 | $toc_sheet_size = $this->m_TOC[$toc_id]['TOCsheetsize']; | ||
214 | next($this->m_TOC); | ||
215 | } | ||
216 | |||
217 | // mPDF 5.6.31 | ||
218 | |||
219 | if (!$toc_orientation) { $toc_orientation= $this->mpdf->DefOrientation; } | ||
220 | $this->mpdf->AddPage($toc_orientation, '', '', '', "on", $toc_mgl, $toc_mgr, $toc_mgt, $toc_mgb, $toc_mgh, $toc_mgf, $toc_ohname, $toc_ehname, $toc_ofname, $toc_efname, $toc_ohvalue, $toc_ehvalue, $toc_ofvalue, $toc_efvalue, $toc_page_selector, $toc_sheet_size ); | ||
221 | |||
222 | $this->mpdf->writingToC = true; // mPDF 5.6.38 | ||
223 | // mPDF 5.6.31 | ||
224 | $tocstart=count($this->mpdf->pages); | ||
225 | if ($toc_preHTML) { $this->mpdf->WriteHTML($toc_preHTML); } | ||
226 | |||
227 | |||
228 | // mPDF 5.6.19 | ||
229 | $html ='<div class="mpdf_toc" id="mpdf_toc_'.$toc_id.'">'; | ||
230 | foreach($this->_toc as $t) { | ||
231 | if ($t['toc_id']==='_mpdf_all' || $t['toc_id']===$toc_id ) { | ||
232 | $html .= '<div class="mpdf_toc_level_'.$t['l'].'">'; | ||
233 | if ($TOCuseLinking) { $html .= '<a class="mpdf_toc_a" href="#__mpdfinternallink_'.$t['link'].'">'; } | ||
234 | $html .= '<span class="mpdf_toc_t_level_'.$t['l'].'">'.$t['t'].'</span>'; | ||
235 | if ($TOCuseLinking) { $html .= '</a>'; } | ||
236 | if (!$tocoutdent) { $tocoutdent = '0'; } | ||
237 | if ($TOCusePaging) { $html .= ' <dottab outdent="'.$tocoutdent.'" /> '; | ||
238 | if ($TOCuseLinking) { $html .= '<a class="mpdf_toc_a" href="#__mpdfinternallink_'.$t['link'].'">'; } | ||
239 | $html .= '<span class="mpdf_toc_p_level_'.$t['l'].'">'.$this->mpdf->docPageNum($t['p']).'</span>'; | ||
240 | if ($TOCuseLinking) { $html .= '</a>'; } | ||
241 | } | ||
242 | $html .= '</div>'; | ||
243 | } | ||
244 | } | ||
245 | $html .= '</div>'; | ||
246 | $this->mpdf->WriteHTML($html); | ||
247 | |||
248 | if ($toc_postHTML) { $this->mpdf->WriteHTML($toc_postHTML); } | ||
249 | $this->mpdf->writingToC = false; // mPDF 5.6.38 | ||
250 | $this->mpdf->AddPage($toc_orientation,'E'); | ||
251 | |||
252 | $n_toc = $this->mpdf->page - $tocstart + 1; | ||
253 | |||
254 | if ($toci==0 && $this->TOCmark) { | ||
255 | $TOC_start = $tocstart ; | ||
256 | $TOC_end = $this->mpdf->page; | ||
257 | $TOC_npages = $n_toc; | ||
258 | } | ||
259 | else { | ||
260 | $this->m_TOC[$toc_id]['start'] = $tocstart ; | ||
261 | $this->m_TOC[$toc_id]['end'] = $this->mpdf->page; | ||
262 | $this->m_TOC[$toc_id]['npages'] = $n_toc; | ||
263 | } | ||
264 | } | ||
265 | |||
266 | $s = ''; | ||
267 | |||
268 | $s .= $this->mpdf->PrintBodyBackgrounds(); | ||
269 | |||
270 | $s .= $this->mpdf->PrintPageBackgrounds(); | ||
271 | $this->mpdf->pages[$this->mpdf->page] = preg_replace('/(___BACKGROUND___PATTERNS'.date('jY').')/', "\n".$s."\n".'\\1', $this->mpdf->pages[$this->mpdf->page]); | ||
272 | $this->mpdf->pageBackgrounds = array(); | ||
273 | |||
274 | //Page footer | ||
275 | $this->mpdf->InFooter=true; | ||
276 | $this->mpdf->Footer(); | ||
277 | $this->mpdf->InFooter=false; | ||
278 | |||
279 | // 2nd time through to move pages etc. | ||
280 | $added_toc_pages = 0; | ||
281 | if (count($this->m_TOC)) { reset($this->m_TOC); } | ||
282 | |||
283 | for ($toci = 0; $toci<$notocs; $toci++) { | ||
284 | if ($toci==0 && $this->TOCmark) { | ||
285 | $toc_id = 0; | ||
286 | $toc_page = $this->TOCmark + $added_toc_pages; | ||
287 | $toc_orientation = $this->TOCorientation; | ||
288 | $TOCuseLinking = $this->TOCuseLinking; | ||
289 | $TOCusePaging = $this->TOCusePaging; | ||
290 | $toc_bookmarkText = $this->TOCbookmarkText; // *BOOKMARKS* | ||
291 | |||
292 | $tocstart = $TOC_start ; | ||
293 | $tocend = $n = $TOC_end; | ||
294 | $n_toc = $TOC_npages; | ||
295 | } | ||
296 | else { | ||
297 | $arr = current($this->m_TOC); | ||
298 | |||
299 | $toc_id = key($this->m_TOC); | ||
300 | $toc_page = $this->m_TOC[$toc_id]['TOCmark'] + $added_toc_pages; | ||
301 | $toc_orientation = $this->m_TOC[$toc_id]['TOCorientation']; | ||
302 | $TOCuseLinking = $this->m_TOC[$toc_id]['TOCuseLinking']; | ||
303 | $TOCusePaging = $this->m_TOC[$toc_id]['TOCusePaging']; | ||
304 | $toc_bookmarkText = $this->m_TOC[$toc_id]['TOCbookmarkText']; // *BOOKMARKS* | ||
305 | |||
306 | $tocstart = $this->m_TOC[$toc_id]['start'] ; | ||
307 | $tocend = $n = $this->m_TOC[$toc_id]['end'] ; | ||
308 | $n_toc = $this->m_TOC[$toc_id]['npages'] ; | ||
309 | |||
310 | next($this->m_TOC); | ||
311 | } | ||
312 | |||
313 | // Now pages moved | ||
314 | $added_toc_pages += $n_toc; | ||
315 | |||
316 | $this->mpdf->MovePages($toc_page, $tocstart, $tocend) ; | ||
317 | $this->mpdf->pgsIns[$toc_page] = $tocend - $tocstart + 1; | ||
318 | |||
319 | /*-- BOOKMARKS --*/ | ||
320 | // Insert new Bookmark for Bookmark | ||
321 | if ($toc_bookmarkText) { | ||
322 | $insert = -1; | ||
323 | foreach($this->mpdf->BMoutlines as $i=>$o) { | ||
324 | if($o['p']<$toc_page) { // i.e. before point of insertion | ||
325 | $insert = $i; | ||
326 | } | ||
327 | } | ||
328 | $txt = $this->mpdf->purify_utf8_text($toc_bookmarkText); | ||
329 | if ($this->mpdf->text_input_as_HTML) { | ||
330 | $txt = $this->mpdf->all_entities_to_utf8($txt); | ||
331 | } | ||
332 | $newBookmark[0] = array('t'=>$txt,'l'=>0,'y'=>0,'p'=>$toc_page ); | ||
333 | array_splice($this->mpdf->BMoutlines,($insert+1),0,$newBookmark); | ||
334 | } | ||
335 | /*-- END BOOKMARKS --*/ | ||
336 | |||
337 | } | ||
338 | |||
339 | // Delete empty page that was inserted earlier | ||
340 | if ($extrapage) { | ||
341 | unset($this->mpdf->pages[count($this->mpdf->pages)]); | ||
342 | $this->mpdf->page--; // Reset page pointer | ||
343 | } | ||
344 | |||
345 | |||
346 | } | ||
347 | |||
348 | |||
349 | function openTagTOC($attr) { | ||
350 | if (isset($attr['OUTDENT']) && $attr['OUTDENT']) { $tocoutdent = $attr['OUTDENT']; } else { $tocoutdent = ''; } // mPDF 5.6.19 | ||
351 | if (isset($attr['RESETPAGENUM']) && $attr['RESETPAGENUM']) { $resetpagenum = $attr['RESETPAGENUM']; } else { $resetpagenum = ''; } | ||
352 | if (isset($attr['PAGENUMSTYLE']) && $attr['PAGENUMSTYLE']) { $pagenumstyle = $attr['PAGENUMSTYLE']; } else { $pagenumstyle= ''; } | ||
353 | if (isset($attr['SUPPRESS']) && $attr['SUPPRESS']) { $suppress = $attr['SUPPRESS']; } else { $suppress = ''; } | ||
354 | if (isset($attr['TOC-ORIENTATION']) && $attr['TOC-ORIENTATION']) { $toc_orientation = $attr['TOC-ORIENTATION']; } else { $toc_orientation = ''; } | ||
355 | if (isset($attr['PAGING']) && (strtoupper($attr['PAGING'])=='OFF' || $attr['PAGING']==='0')) { $paging = false; } | ||
356 | else { $paging = true; } | ||
357 | if (isset($attr['LINKS']) && (strtoupper($attr['LINKS'])=='ON' || $attr['LINKS']==1)) { $links = true; } | ||
358 | else { $links = false; } | ||
359 | if (isset($attr['NAME']) && $attr['NAME']) { $toc_id = strtolower($attr['NAME']); } else { $toc_id = 0; } | ||
360 | $this->TOC('',0,0,$resetpagenum, $pagenumstyle, $suppress, $toc_orientation, $paging, $links, $toc_id, $tocoutdent); // mPDF 5.6.19 5.6.31 | ||
361 | } | ||
362 | |||
363 | |||
364 | function openTagTOCPAGEBREAK($attr) { | ||
365 | if (isset($attr['NAME']) && $attr['NAME']) { $toc_id = strtolower($attr['NAME']); } else { $toc_id = 0; } | ||
366 | if ($toc_id) { | ||
367 | if (isset($attr['OUTDENT']) && $attr['OUTDENT']) { $this->m_TOC[$toc_id]['TOCoutdent'] = $attr['OUTDENT']; } else { $this->m_TOC[$toc_id]['TOCoutdent'] = ''; } // mPDF 5.6.19 | ||
368 | if (isset($attr['TOC-ORIENTATION']) && $attr['TOC-ORIENTATION']) { $this->m_TOC[$toc_id]['TOCorientation'] = $attr['TOC-ORIENTATION']; } else { $this->m_TOC[$toc_id]['TOCorientation'] = ''; } | ||
369 | if (isset($attr['PAGING']) && (strtoupper($attr['PAGING'])=='OFF' || $attr['PAGING']==='0')) { $this->m_TOC[$toc_id]['TOCusePaging'] = false; } | ||
370 | else { $this->m_TOC[$toc_id]['TOCusePaging'] = true; } | ||
371 | if (isset($attr['LINKS']) && (strtoupper($attr['LINKS'])=='ON' || $attr['LINKS']==1)) { $this->m_TOC[$toc_id]['TOCuseLinking'] = true; } | ||
372 | else { $this->m_TOC[$toc_id]['TOCuseLinking'] = false; } | ||
373 | |||
374 | $this->m_TOC[$toc_id]['TOC_margin_left'] = $this->m_TOC[$toc_id]['TOC_margin_right'] = $this->m_TOC[$toc_id]['TOC_margin_top'] = $this->m_TOC[$toc_id]['TOC_margin_bottom'] = $this->m_TOC[$toc_id]['TOC_margin_header'] = $this->m_TOC[$toc_id]['TOC_margin_footer'] = ''; | ||
375 | if (isset($attr['TOC-MARGIN-RIGHT'])) { $this->m_TOC[$toc_id]['TOC_margin_right'] = $this->mpdf->ConvertSize($attr['TOC-MARGIN-RIGHT'],$this->mpdf->w,$this->mpdf->FontSize,false); } | ||
376 | if (isset($attr['TOC-MARGIN-LEFT'])) { $this->m_TOC[$toc_id]['TOC_margin_left'] = $this->mpdf->ConvertSize($attr['TOC-MARGIN-LEFT'],$this->mpdf->w,$this->mpdf->FontSize,false); } | ||
377 | if (isset($attr['TOC-MARGIN-TOP'])) { $this->m_TOC[$toc_id]['TOC_margin_top'] = $this->mpdf->ConvertSize($attr['TOC-MARGIN-TOP'],$this->mpdf->w,$this->mpdf->FontSize,false); } | ||
378 | if (isset($attr['TOC-MARGIN-BOTTOM'])) { $this->m_TOC[$toc_id]['TOC_margin_bottom'] = $this->mpdf->ConvertSize($attr['TOC-MARGIN-BOTTOM'],$this->mpdf->w,$this->mpdf->FontSize,false); } | ||
379 | if (isset($attr['TOC-MARGIN-HEADER'])) { $this->m_TOC[$toc_id]['TOC_margin_header'] = $this->mpdf->ConvertSize($attr['TOC-MARGIN-HEADER'],$this->mpdf->w,$this->mpdf->FontSize,false); } | ||
380 | if (isset($attr['TOC-MARGIN-FOOTER'])) { $this->m_TOC[$toc_id]['TOC_margin_footer'] = $this->mpdf->ConvertSize($attr['TOC-MARGIN-FOOTER'],$this->mpdf->w,$this->mpdf->FontSize,false); } | ||
381 | $this->m_TOC[$toc_id]['TOC_odd_header_name'] = $this->m_TOC[$toc_id]['TOC_even_header_name'] = $this->m_TOC[$toc_id]['TOC_odd_footer_name'] = $this->m_TOC[$toc_id]['TOC_even_footer_name'] = ''; | ||
382 | if (isset($attr['TOC-ODD-HEADER-NAME']) && $attr['TOC-ODD-HEADER-NAME']) { $this->m_TOC[$toc_id]['TOC_odd_header_name'] = $attr['TOC-ODD-HEADER-NAME']; } | ||
383 | if (isset($attr['TOC-EVEN-HEADER-NAME']) && $attr['TOC-EVEN-HEADER-NAME']) { $this->m_TOC[$toc_id]['TOC_even_header_name'] = $attr['TOC-EVEN-HEADER-NAME']; } | ||
384 | if (isset($attr['TOC-ODD-FOOTER-NAME']) && $attr['TOC-ODD-FOOTER-NAME']) { $this->m_TOC[$toc_id]['TOC_odd_footer_name'] = $attr['TOC-ODD-FOOTER-NAME']; } | ||
385 | if (isset($attr['TOC-EVEN-FOOTER-NAME']) && $attr['TOC-EVEN-FOOTER-NAME']) { $this->m_TOC[$toc_id]['TOC_even_footer_name'] = $attr['TOC-EVEN-FOOTER-NAME']; } | ||
386 | $this->m_TOC[$toc_id]['TOC_odd_header_value'] = $this->m_TOC[$toc_id]['TOC_even_header_value'] = $this->m_TOC[$toc_id]['TOC_odd_footer_value'] = $this->m_TOC[$toc_id]['TOC_even_footer_value'] = 0; | ||
387 | if (isset($attr['TOC-ODD-HEADER-VALUE']) && ($attr['TOC-ODD-HEADER-VALUE']=='1' || strtoupper($attr['TOC-ODD-HEADER-VALUE'])=='ON')) { $this->m_TOC[$toc_id]['TOC_odd_header_value'] = 1; } | ||
388 | else if (isset($attr['TOC-ODD-HEADER-VALUE']) && ($attr['TOC-ODD-HEADER-VALUE']=='-1' || strtoupper($attr['TOC-ODD-HEADER-VALUE'])=='OFF')) { $this->m_TOC[$toc_id]['TOC_odd_header_value'] = -1; } | ||
389 | if (isset($attr['TOC-EVEN-HEADER-VALUE']) && ($attr['TOC-EVEN-HEADER-VALUE']=='1' || strtoupper($attr['TOC-EVEN-HEADER-VALUE'])=='ON')) { $this->m_TOC[$toc_id]['TOC_even_header_value'] = 1; } | ||
390 | else if (isset($attr['TOC-EVEN-HEADER-VALUE']) && ($attr['TOC-EVEN-HEADER-VALUE']=='-1' || strtoupper($attr['TOC-EVEN-HEADER-VALUE'])=='OFF')) { $this->m_TOC[$toc_id]['TOC_even_header_value'] = -1; } | ||
391 | if (isset($attr['TOC-ODD-FOOTER-VALUE']) && ($attr['TOC-ODD-FOOTER-VALUE']=='1' || strtoupper($attr['TOC-ODD-FOOTER-VALUE'])=='ON')) { $this->m_TOC[$toc_id]['TOC_odd_footer_value'] = 1; } | ||
392 | else if (isset($attr['TOC-ODD-FOOTER-VALUE']) && ($attr['TOC-ODD-FOOTER-VALUE']=='-1' || strtoupper($attr['TOC-ODD-FOOTER-VALUE'])=='OFF')) { $this->m_TOC[$toc_id]['TOC_odd_footer_value'] = -1; } | ||
393 | if (isset($attr['TOC-EVEN-FOOTER-VALUE']) && ($attr['TOC-EVEN-FOOTER-VALUE']=='1' || strtoupper($attr['TOC-EVEN-FOOTER-VALUE'])=='ON')) { $this->m_TOC[$toc_id]['TOC_even_footer_value'] = 1; } | ||
394 | else if (isset($attr['TOC-EVEN-FOOTER-VALUE']) && ($attr['TOC-EVEN-FOOTER-VALUE']=='-1' || strtoupper($attr['TOC-EVEN-FOOTER-VALUE'])=='OFF')) { $this->m_TOC[$toc_id]['TOC_even_footer_value'] = -1; } | ||
395 | if (isset($attr['TOC-PAGE-SELECTOR']) && $attr['TOC-PAGE-SELECTOR']) { $this->m_TOC[$toc_id]['TOC_page_selector'] = $attr['TOC-PAGE-SELECTOR']; } | ||
396 | else { $this->m_TOC[$toc_id]['TOC_page_selector'] = ''; } | ||
397 | if (isset($attr['TOC-SHEET-SIZE']) && $attr['TOC-SHEET-SIZE']) { $this->m_TOC[$toc_id]['TOCsheetsize'] = $attr['TOC-SHEET-SIZE']; } else { $this->m_TOC[$toc_id]['TOCsheetsize'] = ''; } | ||
398 | |||
399 | |||
400 | if (isset($attr['TOC-PREHTML']) && $attr['TOC-PREHTML']) { $this->m_TOC[$toc_id]['TOCpreHTML'] = htmlspecialchars_decode($attr['TOC-PREHTML'],ENT_QUOTES); } | ||
401 | if (isset($attr['TOC-POSTHTML']) && $attr['TOC-POSTHTML']) { $this->m_TOC[$toc_id]['TOCpostHTML'] = htmlspecialchars_decode($attr['TOC-POSTHTML'],ENT_QUOTES); } | ||
402 | |||
403 | if (isset($attr['TOC-BOOKMARKTEXT']) && $attr['TOC-BOOKMARKTEXT']) { $this->m_TOC[$toc_id]['TOCbookmarkText'] = htmlspecialchars_decode($attr['TOC-BOOKMARKTEXT'],ENT_QUOTES); } // *BOOKMARKS* | ||
404 | } | ||
405 | else { | ||
406 | if (isset($attr['OUTDENT']) && $attr['OUTDENT']) { $this->TOCoutdent = $attr['OUTDENT']; } else { $this->TOCoutdent = ''; } // mPDF 5.6.19 | ||
407 | if (isset($attr['TOC-ORIENTATION']) && $attr['TOC-ORIENTATION']) { $this->TOCorientation = $attr['TOC-ORIENTATION']; } else { $this->TOCorientation = ''; } | ||
408 | if (isset($attr['PAGING']) && (strtoupper($attr['PAGING'])=='OFF' || $attr['PAGING']==='0')) { $this->TOCusePaging = false; } | ||
409 | else { $this->TOCusePaging = true; } | ||
410 | if (isset($attr['LINKS']) && (strtoupper($attr['LINKS'])=='ON' || $attr['LINKS']==1)) { $this->TOCuseLinking = true; } | ||
411 | else { $this->TOCuseLinking = false; } | ||
412 | |||
413 | $this->TOC_margin_left = $this->TOC_margin_right = $this->TOC_margin_top = $this->TOC_margin_bottom = $this->TOC_margin_header = $this->TOC_margin_footer = ''; | ||
414 | if (isset($attr['TOC-MARGIN-RIGHT'])) { $this->TOC_margin_right = $this->mpdf->ConvertSize($attr['TOC-MARGIN-RIGHT'],$this->mpdf->w,$this->mpdf->FontSize,false); } | ||
415 | if (isset($attr['TOC-MARGIN-LEFT'])) { $this->TOC_margin_left = $this->mpdf->ConvertSize($attr['TOC-MARGIN-LEFT'],$this->mpdf->w,$this->mpdf->FontSize,false); } | ||
416 | if (isset($attr['TOC-MARGIN-TOP'])) { $this->TOC_margin_top = $this->mpdf->ConvertSize($attr['TOC-MARGIN-TOP'],$this->mpdf->w,$this->mpdf->FontSize,false); } | ||
417 | if (isset($attr['TOC-MARGIN-BOTTOM'])) { $this->TOC_margin_bottom = $this->mpdf->ConvertSize($attr['TOC-MARGIN-BOTTOM'],$this->mpdf->w,$this->mpdf->FontSize,false); } | ||
418 | if (isset($attr['TOC-MARGIN-HEADER'])) { $this->TOC_margin_header = $this->mpdf->ConvertSize($attr['TOC-MARGIN-HEADER'],$this->mpdf->w,$this->mpdf->FontSize,false); } | ||
419 | if (isset($attr['TOC-MARGIN-FOOTER'])) { $this->TOC_margin_footer = $this->mpdf->ConvertSize($attr['TOC-MARGIN-FOOTER'],$this->mpdf->w,$this->mpdf->FontSize,false); } | ||
420 | $this->TOC_odd_header_name = $this->TOC_even_header_name = $this->TOC_odd_footer_name = $this->TOC_even_footer_name = ''; | ||
421 | if (isset($attr['TOC-ODD-HEADER-NAME']) && $attr['TOC-ODD-HEADER-NAME']) { $this->TOC_odd_header_name = $attr['TOC-ODD-HEADER-NAME']; } | ||
422 | if (isset($attr['TOC-EVEN-HEADER-NAME']) && $attr['TOC-EVEN-HEADER-NAME']) { $this->TOC_even_header_name = $attr['TOC-EVEN-HEADER-NAME']; } | ||
423 | if (isset($attr['TOC-ODD-FOOTER-NAME']) && $attr['TOC-ODD-FOOTER-NAME']) { $this->TOC_odd_footer_name = $attr['TOC-ODD-FOOTER-NAME']; } | ||
424 | if (isset($attr['TOC-EVEN-FOOTER-NAME']) && $attr['TOC-EVEN-FOOTER-NAME']) { $this->TOC_even_footer_name = $attr['TOC-EVEN-FOOTER-NAME']; } | ||
425 | $this->TOC_odd_header_value = $this->TOC_even_header_value = $this->TOC_odd_footer_value = $this->TOC_even_footer_value = 0; | ||
426 | if (isset($attr['TOC-ODD-HEADER-VALUE']) && ($attr['TOC-ODD-HEADER-VALUE']=='1' || strtoupper($attr['TOC-ODD-HEADER-VALUE'])=='ON')) { $this->TOC_odd_header_value = 1; } | ||
427 | else if (isset($attr['TOC-ODD-HEADER-VALUE']) && ($attr['TOC-ODD-HEADER-VALUE']=='-1' || strtoupper($attr['TOC-ODD-HEADER-VALUE'])=='OFF')) { $this->TOC_odd_header_value = -1; } | ||
428 | if (isset($attr['TOC-EVEN-HEADER-VALUE']) && ($attr['TOC-EVEN-HEADER-VALUE']=='1' || strtoupper($attr['TOC-EVEN-HEADER-VALUE'])=='ON')) { $this->TOC_even_header_value = 1; } | ||
429 | else if (isset($attr['TOC-EVEN-HEADER-VALUE']) && ($attr['TOC-EVEN-HEADER-VALUE']=='-1' || strtoupper($attr['TOC-EVEN-HEADER-VALUE'])=='OFF')) { $this->TOC_even_header_value = -1; } | ||
430 | |||
431 | if (isset($attr['TOC-ODD-FOOTER-VALUE']) && ($attr['TOC-ODD-FOOTER-VALUE']=='1' || strtoupper($attr['TOC-ODD-FOOTER-VALUE'])=='ON')) { $this->TOC_odd_footer_value = 1; } | ||
432 | else if (isset($attr['TOC-ODD-FOOTER-VALUE']) && ($attr['TOC-ODD-FOOTER-VALUE']=='-1' || strtoupper($attr['TOC-ODD-FOOTER-VALUE'])=='OFF')) { $this->TOC_odd_footer_value = -1; } | ||
433 | if (isset($attr['TOC-EVEN-FOOTER-VALUE']) && ($attr['TOC-EVEN-FOOTER-VALUE']=='1' || strtoupper($attr['TOC-EVEN-FOOTER-VALUE'])=='ON')) { $this->TOC_even_footer_value = 1; } | ||
434 | else if (isset($attr['TOC-EVEN-FOOTER-VALUE']) && ($attr['TOC-EVEN-FOOTER-VALUE']=='-1' || strtoupper($attr['TOC-EVEN-FOOTER-VALUE'])=='OFF')) { $this->TOC_even_footer_value = -1; } | ||
435 | if (isset($attr['TOC-PAGE-SELECTOR']) && $attr['TOC-PAGE-SELECTOR']) { $this->TOC_page_selector = $attr['TOC-PAGE-SELECTOR']; } | ||
436 | else { $this->TOC_page_selector = ''; } | ||
437 | if (isset($attr['TOC-SHEET-SIZE']) && $attr['TOC-SHEET-SIZE']) { $this->TOCsheetsize = $attr['TOC-SHEET-SIZE']; } else { $this->TOCsheetsize = ''; } | ||
438 | |||
439 | if (isset($attr['TOC-PREHTML']) && $attr['TOC-PREHTML']) { $this->TOCpreHTML = htmlspecialchars_decode($attr['TOC-PREHTML'],ENT_QUOTES); } | ||
440 | if (isset($attr['TOC-POSTHTML']) && $attr['TOC-POSTHTML']) { $this->TOCpostHTML = htmlspecialchars_decode($attr['TOC-POSTHTML'],ENT_QUOTES); } | ||
441 | if (isset($attr['TOC-BOOKMARKTEXT']) && $attr['TOC-BOOKMARKTEXT']) { $this->TOCbookmarkText = htmlspecialchars_decode($attr['TOC-BOOKMARKTEXT'],ENT_QUOTES); } | ||
442 | } | ||
443 | |||
444 | if ($this->mpdf->y == $this->mpdf->tMargin && (!$this->mpdf->mirrorMargins ||($this->mpdf->mirrorMargins && $this->mpdf->page % 2==1))) { | ||
445 | if ($toc_id) { $this->m_TOC[$toc_id]['TOCmark'] = $this->mpdf->page; } | ||
446 | else { $this->TOCmark = $this->mpdf->page; } | ||
447 | // Don't add a page | ||
448 | if ($this->mpdf->page==1 && count($this->mpdf->PageNumSubstitutions)==0) { | ||
449 | $resetpagenum = ''; | ||
450 | $pagenumstyle = ''; | ||
451 | $suppress = ''; | ||
452 | if (isset($attr['RESETPAGENUM'])) { $resetpagenum = $attr['RESETPAGENUM']; } | ||
453 | if (isset($attr['PAGENUMSTYLE'])) { $pagenumstyle = $attr['PAGENUMSTYLE']; } | ||
454 | if (isset($attr['SUPPRESS'])) { $suppress = $attr['SUPPRESS']; } | ||
455 | if (!$suppress) { $suppress = 'off'; } | ||
456 | if (!$resetpagenum) { $resetpagenum= 1; } | ||
457 | $this->mpdf->PageNumSubstitutions[] = array('from'=>1, 'reset'=> $resetpagenum, 'type'=>$pagenumstyle, 'suppress'=> $suppress); | ||
458 | } | ||
459 | return array(true, $toc_id); | ||
460 | } | ||
461 | // No break - continues as PAGEBREAK... | ||
462 | return array(false, $toc_id); | ||
463 | } | ||
464 | |||
465 | |||
466 | } | ||
467 | |||
468 | ?> \ No newline at end of file | ||
diff --git a/inc/3rdparty/libraries/mpdf/classes/ttfontsuni.php b/inc/3rdparty/libraries/mpdf/classes/ttfontsuni.php new file mode 100644 index 00000000..1c93b600 --- /dev/null +++ b/inc/3rdparty/libraries/mpdf/classes/ttfontsuni.php | |||
@@ -0,0 +1,2065 @@ | |||
1 | <?php | ||
2 | |||
3 | /******************************************************************************* | ||
4 | * TTFontFile class * | ||
5 | * * | ||
6 | * Version: 2.01 * | ||
7 | * Date: 2012-02-25 * | ||
8 | * Author: Ian Back <ianb@bpm1.com> * | ||
9 | * License: LGPL * | ||
10 | * Copyright (c) Ian Back, 2010 * | ||
11 | * This class is based on The ReportLab Open Source PDF library * | ||
12 | * written in Python - http://www.reportlab.com/software/opensource/ * | ||
13 | * together with ideas from the OpenOffice source code and others. * | ||
14 | * This header must be retained in any redistribution or * | ||
15 | * modification of the file. * | ||
16 | * * | ||
17 | *******************************************************************************/ | ||
18 | |||
19 | // Define the value used in the "head" table of a created TTF file | ||
20 | // 0x74727565 "true" for Mac | ||
21 | // 0x00010000 for Windows | ||
22 | // Either seems to work for a font embedded in a PDF file | ||
23 | // when read by Adobe Reader on a Windows PC(!) | ||
24 | if (!defined('_TTF_MAC_HEADER')) define("_TTF_MAC_HEADER", false); | ||
25 | |||
26 | // Recalculate correct metadata/profiles when making subset fonts (not SIP/SMP) | ||
27 | // e.g. xMin, xMax, maxNContours | ||
28 | if (!defined('_RECALC_PROFILE')) define("_RECALC_PROFILE", false); | ||
29 | |||
30 | // TrueType Font Glyph operators | ||
31 | define("GF_WORDS",(1 << 0)); | ||
32 | define("GF_SCALE",(1 << 3)); | ||
33 | define("GF_MORE",(1 << 5)); | ||
34 | define("GF_XYSCALE",(1 << 6)); | ||
35 | define("GF_TWOBYTWO",(1 << 7)); | ||
36 | |||
37 | |||
38 | |||
39 | class TTFontFile { | ||
40 | |||
41 | var $unAGlyphs; // mPDF 5.4.05 | ||
42 | var $panose; | ||
43 | var $maxUni; | ||
44 | var $sFamilyClass; | ||
45 | var $sFamilySubClass; | ||
46 | var $sipset; | ||
47 | var $smpset; | ||
48 | var $_pos; | ||
49 | var $numTables; | ||
50 | var $searchRange; | ||
51 | var $entrySelector; | ||
52 | var $rangeShift; | ||
53 | var $tables; | ||
54 | var $otables; | ||
55 | var $filename; | ||
56 | var $fh; | ||
57 | var $glyphPos; | ||
58 | var $charToGlyph; | ||
59 | var $ascent; | ||
60 | var $descent; | ||
61 | var $name; | ||
62 | var $familyName; | ||
63 | var $styleName; | ||
64 | var $fullName; | ||
65 | var $uniqueFontID; | ||
66 | var $unitsPerEm; | ||
67 | var $bbox; | ||
68 | var $capHeight; | ||
69 | var $stemV; | ||
70 | var $italicAngle; | ||
71 | var $flags; | ||
72 | var $underlinePosition; | ||
73 | var $underlineThickness; | ||
74 | var $charWidths; | ||
75 | var $defaultWidth; | ||
76 | var $maxStrLenRead; | ||
77 | var $numTTCFonts; | ||
78 | var $TTCFonts; | ||
79 | var $maxUniChar; | ||
80 | var $kerninfo; | ||
81 | |||
82 | function TTFontFile() { | ||
83 | $this->maxStrLenRead = 200000; // Maximum size of glyf table to read in as string (otherwise reads each glyph from file) | ||
84 | } | ||
85 | |||
86 | |||
87 | function getMetrics($file, $TTCfontID=0, $debug=false, $BMPonly=false, $kerninfo=false, $unAGlyphs=false) { // mPDF 5.4.05 | ||
88 | $this->unAGlyphs = $unAGlyphs; // mPDF 5.4.05 | ||
89 | $this->filename = $file; | ||
90 | $this->fh = fopen($file,'rb') or die('Can\'t open file ' . $file); | ||
91 | $this->_pos = 0; | ||
92 | $this->charWidths = ''; | ||
93 | $this->glyphPos = array(); | ||
94 | $this->charToGlyph = array(); | ||
95 | $this->tables = array(); | ||
96 | $this->otables = array(); | ||
97 | $this->kerninfo = array(); | ||
98 | $this->ascent = 0; | ||
99 | $this->descent = 0; | ||
100 | $this->numTTCFonts = 0; | ||
101 | $this->TTCFonts = array(); | ||
102 | $this->version = $version = $this->read_ulong(); | ||
103 | $this->panose = array(); | ||
104 | if ($version==0x4F54544F) | ||
105 | die("Postscript outlines are not supported"); | ||
106 | if ($version==0x74746366 && !$TTCfontID) | ||
107 | die("ERROR - You must define the TTCfontID for a TrueType Collection in config_fonts.php (". $file.")"); | ||
108 | if (!in_array($version, array(0x00010000,0x74727565)) && !$TTCfontID) | ||
109 | die("Not a TrueType font: version=".$version); | ||
110 | if ($TTCfontID > 0) { | ||
111 | $this->version = $version = $this->read_ulong(); // TTC Header version now | ||
112 | if (!in_array($version, array(0x00010000,0x00020000))) | ||
113 | die("ERROR - Error parsing TrueType Collection: version=".$version." - " . $file); | ||
114 | $this->numTTCFonts = $this->read_ulong(); | ||
115 | for ($i=1; $i<=$this->numTTCFonts; $i++) { | ||
116 | $this->TTCFonts[$i]['offset'] = $this->read_ulong(); | ||
117 | } | ||
118 | $this->seek($this->TTCFonts[$TTCfontID]['offset']); | ||
119 | $this->version = $version = $this->read_ulong(); // TTFont version again now | ||
120 | } | ||
121 | $this->readTableDirectory($debug); | ||
122 | $this->extractInfo($debug, $BMPonly, $kerninfo); | ||
123 | fclose($this->fh); | ||
124 | } | ||
125 | |||
126 | |||
127 | function readTableDirectory($debug=false) { | ||
128 | $this->numTables = $this->read_ushort(); | ||
129 | $this->searchRange = $this->read_ushort(); | ||
130 | $this->entrySelector = $this->read_ushort(); | ||
131 | $this->rangeShift = $this->read_ushort(); | ||
132 | $this->tables = array(); | ||
133 | for ($i=0;$i<$this->numTables;$i++) { | ||
134 | $record = array(); | ||
135 | $record['tag'] = $this->read_tag(); | ||
136 | $record['checksum'] = array($this->read_ushort(),$this->read_ushort()); | ||
137 | $record['offset'] = $this->read_ulong(); | ||
138 | $record['length'] = $this->read_ulong(); | ||
139 | $this->tables[$record['tag']] = $record; | ||
140 | } | ||
141 | if ($debug) $this->checksumTables(); | ||
142 | } | ||
143 | |||
144 | function checksumTables() { | ||
145 | // Check the checksums for all tables | ||
146 | foreach($this->tables AS $t) { | ||
147 | if ($t['length'] > 0 && $t['length'] < $this->maxStrLenRead) { // 1.02 | ||
148 | $table = $this->get_chunk($t['offset'], $t['length']); | ||
149 | $checksum = $this->calcChecksum($table); | ||
150 | if ($t['tag'] == 'head') { | ||
151 | $up = unpack('n*', substr($table,8,4)); | ||
152 | $adjustment[0] = $up[1]; | ||
153 | $adjustment[1] = $up[2]; | ||
154 | $checksum = $this->sub32($checksum, $adjustment); | ||
155 | } | ||
156 | $xchecksum = $t['checksum']; | ||
157 | if ($xchecksum != $checksum) | ||
158 | die(sprintf('TTF file "%s": invalid checksum %s table: %s (expected %s)', $this->filename,dechex($checksum[0]).dechex($checksum[1]),$t['tag'],dechex($xchecksum[0]).dechex($xchecksum[1]))); | ||
159 | } | ||
160 | } | ||
161 | } | ||
162 | |||
163 | function sub32($x, $y) { | ||
164 | $xlo = $x[1]; | ||
165 | $xhi = $x[0]; | ||
166 | $ylo = $y[1]; | ||
167 | $yhi = $y[0]; | ||
168 | if ($ylo > $xlo) { $xlo += 1 << 16; $yhi += 1; } | ||
169 | $reslo = $xlo-$ylo; | ||
170 | if ($yhi > $xhi) { $xhi += 1 << 16; } | ||
171 | $reshi = $xhi-$yhi; | ||
172 | $reshi = $reshi & 0xFFFF; | ||
173 | return array($reshi, $reslo); | ||
174 | } | ||
175 | |||
176 | function calcChecksum($data) { | ||
177 | if (strlen($data) % 4) { $data .= str_repeat("\0",(4-(strlen($data) % 4))); } | ||
178 | $len = strlen($data); | ||
179 | $hi=0x0000; | ||
180 | $lo=0x0000; | ||
181 | for($i=0;$i<$len;$i+=4) { | ||
182 | $hi += (ord($data[$i])<<8) + ord($data[$i+1]); | ||
183 | $lo += (ord($data[$i+2])<<8) + ord($data[$i+3]); | ||
184 | $hi += ($lo >> 16) & 0xFFFF; | ||
185 | $lo = $lo & 0xFFFF; | ||
186 | } | ||
187 | return array($hi, $lo); | ||
188 | } | ||
189 | |||
190 | function get_table_pos($tag) { | ||
191 | $offset = $this->tables[$tag]['offset']; | ||
192 | $length = $this->tables[$tag]['length']; | ||
193 | return array($offset, $length); | ||
194 | } | ||
195 | |||
196 | function seek($pos) { | ||
197 | $this->_pos = $pos; | ||
198 | fseek($this->fh,$this->_pos); | ||
199 | } | ||
200 | |||
201 | function skip($delta) { | ||
202 | $this->_pos = $this->_pos + $delta; | ||
203 | fseek($this->fh,$delta,SEEK_CUR); | ||
204 | } | ||
205 | |||
206 | function seek_table($tag, $offset_in_table = 0) { | ||
207 | $tpos = $this->get_table_pos($tag); | ||
208 | $this->_pos = $tpos[0] + $offset_in_table; | ||
209 | fseek($this->fh, $this->_pos); | ||
210 | return $this->_pos; | ||
211 | } | ||
212 | |||
213 | function read_tag() { | ||
214 | $this->_pos += 4; | ||
215 | return fread($this->fh,4); | ||
216 | } | ||
217 | |||
218 | function read_short() { | ||
219 | $this->_pos += 2; | ||
220 | $s = fread($this->fh,2); | ||
221 | $a = (ord($s[0])<<8) + ord($s[1]); | ||
222 | if ($a & (1 << 15) ) { | ||
223 | $a = ($a - (1 << 16)); | ||
224 | } | ||
225 | return $a; | ||
226 | } | ||
227 | |||
228 | function unpack_short($s) { | ||
229 | $a = (ord($s[0])<<8) + ord($s[1]); | ||
230 | if ($a & (1 << 15) ) { | ||
231 | $a = ($a - (1 << 16)); | ||
232 | } | ||
233 | return $a; | ||
234 | } | ||
235 | |||
236 | function read_ushort() { | ||
237 | $this->_pos += 2; | ||
238 | $s = fread($this->fh,2); | ||
239 | return (ord($s[0])<<8) + ord($s[1]); | ||
240 | } | ||
241 | |||
242 | function read_ulong() { | ||
243 | $this->_pos += 4; | ||
244 | $s = fread($this->fh,4); | ||
245 | // if large uInt32 as an integer, PHP converts it to -ve | ||
246 | return (ord($s[0])*16777216) + (ord($s[1])<<16) + (ord($s[2])<<8) + ord($s[3]); // 16777216 = 1<<24 | ||
247 | } | ||
248 | |||
249 | function get_ushort($pos) { | ||
250 | fseek($this->fh,$pos); | ||
251 | $s = fread($this->fh,2); | ||
252 | return (ord($s[0])<<8) + ord($s[1]); | ||
253 | } | ||
254 | |||
255 | function get_ulong($pos) { | ||
256 | fseek($this->fh,$pos); | ||
257 | $s = fread($this->fh,4); | ||
258 | // iF large uInt32 as an integer, PHP converts it to -ve | ||
259 | return (ord($s[0])*16777216) + (ord($s[1])<<16) + (ord($s[2])<<8) + ord($s[3]); // 16777216 = 1<<24 | ||
260 | } | ||
261 | |||
262 | function pack_short($val) { | ||
263 | if ($val<0) { | ||
264 | $val = abs($val); | ||
265 | $val = ~$val; | ||
266 | $val += 1; | ||
267 | } | ||
268 | return pack("n",$val); | ||
269 | } | ||
270 | |||
271 | function splice($stream, $offset, $value) { | ||
272 | return substr($stream,0,$offset) . $value . substr($stream,$offset+strlen($value)); | ||
273 | } | ||
274 | |||
275 | function _set_ushort($stream, $offset, $value) { | ||
276 | $up = pack("n", $value); | ||
277 | return $this->splice($stream, $offset, $up); | ||
278 | } | ||
279 | |||
280 | function _set_short($stream, $offset, $val) { | ||
281 | if ($val<0) { | ||
282 | $val = abs($val); | ||
283 | $val = ~$val; | ||
284 | $val += 1; | ||
285 | } | ||
286 | $up = pack("n",$val); | ||
287 | return $this->splice($stream, $offset, $up); | ||
288 | } | ||
289 | |||
290 | function get_chunk($pos, $length) { | ||
291 | fseek($this->fh,$pos); | ||
292 | if ($length <1) { return ''; } | ||
293 | return (fread($this->fh,$length)); | ||
294 | } | ||
295 | |||
296 | function get_table($tag) { | ||
297 | list($pos, $length) = $this->get_table_pos($tag); | ||
298 | if ($length == 0) { return ''; } | ||
299 | fseek($this->fh,$pos); | ||
300 | return (fread($this->fh,$length)); | ||
301 | } | ||
302 | |||
303 | function add($tag, $data) { | ||
304 | if ($tag == 'head') { | ||
305 | $data = $this->splice($data, 8, "\0\0\0\0"); | ||
306 | } | ||
307 | $this->otables[$tag] = $data; | ||
308 | } | ||
309 | |||
310 | |||
311 | |||
312 | ///////////////////////////////////////////////////////////////////////////////////////// | ||
313 | function getCTG($file, $TTCfontID=0, $debug=false, $unAGlyphs=false) { // mPDF 5.4.05 | ||
314 | $this->unAGlyphs = $unAGlyphs; // mPDF 5.4.05 | ||
315 | $this->filename = $file; | ||
316 | $this->fh = fopen($file,'rb') or die('Can\'t open file ' . $file); | ||
317 | $this->_pos = 0; | ||
318 | $this->charWidths = ''; | ||
319 | $this->glyphPos = array(); | ||
320 | $this->charToGlyph = array(); | ||
321 | $this->tables = array(); | ||
322 | $this->numTTCFonts = 0; | ||
323 | $this->TTCFonts = array(); | ||
324 | $this->skip(4); | ||
325 | if ($TTCfontID > 0) { | ||
326 | $this->version = $version = $this->read_ulong(); // TTC Header version now | ||
327 | if (!in_array($version, array(0x00010000,0x00020000))) | ||
328 | die("ERROR - Error parsing TrueType Collection: version=".$version." - " . $file); | ||
329 | $this->numTTCFonts = $this->read_ulong(); | ||
330 | for ($i=1; $i<=$this->numTTCFonts; $i++) { | ||
331 | $this->TTCFonts[$i]['offset'] = $this->read_ulong(); | ||
332 | } | ||
333 | $this->seek($this->TTCFonts[$TTCfontID]['offset']); | ||
334 | $this->version = $version = $this->read_ulong(); // TTFont version again now | ||
335 | } | ||
336 | $this->readTableDirectory($debug); | ||
337 | |||
338 | |||
339 | // cmap - Character to glyph index mapping table | ||
340 | $cmap_offset = $this->seek_table("cmap"); | ||
341 | $this->skip(2); | ||
342 | $cmapTableCount = $this->read_ushort(); | ||
343 | $unicode_cmap_offset = 0; | ||
344 | for ($i=0;$i<$cmapTableCount;$i++) { | ||
345 | $platformID = $this->read_ushort(); | ||
346 | $encodingID = $this->read_ushort(); | ||
347 | $offset = $this->read_ulong(); | ||
348 | $save_pos = $this->_pos; | ||
349 | if ($platformID == 3 && $encodingID == 1) { // Microsoft, Unicode | ||
350 | $format = $this->get_ushort($cmap_offset + $offset); | ||
351 | if ($format == 4) { | ||
352 | $unicode_cmap_offset = $cmap_offset + $offset; | ||
353 | break; | ||
354 | } | ||
355 | } | ||
356 | else if ($platformID == 0) { // Unicode -- assume all encodings are compatible | ||
357 | $format = $this->get_ushort($cmap_offset + $offset); | ||
358 | if ($format == 4) { | ||
359 | $unicode_cmap_offset = $cmap_offset + $offset; | ||
360 | break; | ||
361 | } | ||
362 | } | ||
363 | $this->seek($save_pos ); | ||
364 | } | ||
365 | |||
366 | $glyphToChar = array(); | ||
367 | $charToGlyph = array(); | ||
368 | $this->getCMAP4($unicode_cmap_offset, $glyphToChar, $charToGlyph ); | ||
369 | |||
370 | fclose($this->fh); | ||
371 | return ($charToGlyph); | ||
372 | } | ||
373 | |||
374 | ///////////////////////////////////////////////////////////////////////////////////////// | ||
375 | function getTTCFonts($file) { | ||
376 | $this->filename = $file; | ||
377 | $this->fh = fopen($file,'rb'); | ||
378 | if (!$this->fh) { return ('ERROR - Can\'t open file ' . $file); } | ||
379 | $this->numTTCFonts = 0; | ||
380 | $this->TTCFonts = array(); | ||
381 | $this->version = $version = $this->read_ulong(); | ||
382 | if ($version==0x74746366) { | ||
383 | $this->version = $version = $this->read_ulong(); // TTC Header version now | ||
384 | if (!in_array($version, array(0x00010000,0x00020000))) | ||
385 | return("ERROR - Error parsing TrueType Collection: version=".$version." - " . $file); | ||
386 | } | ||
387 | else { | ||
388 | return("ERROR - Not a TrueType Collection: version=".$version." - " . $file); | ||
389 | } | ||
390 | $this->numTTCFonts = $this->read_ulong(); | ||
391 | for ($i=1; $i<=$this->numTTCFonts; $i++) { | ||
392 | $this->TTCFonts[$i]['offset'] = $this->read_ulong(); | ||
393 | } | ||
394 | } | ||
395 | |||
396 | |||
397 | |||
398 | ///////////////////////////////////////////////////////////////////////////////////////// | ||
399 | |||
400 | ///////////////////////////////////////////////////////////////////////////////////////// | ||
401 | |||
402 | function extractInfo($debug=false, $BMPonly=false, $kerninfo=false) { | ||
403 | $this->panose = array(); | ||
404 | $this->sFamilyClass = 0; | ||
405 | $this->sFamilySubClass = 0; | ||
406 | /////////////////////////////////// | ||
407 | // name - Naming table | ||
408 | /////////////////////////////////// | ||
409 | $name_offset = $this->seek_table("name"); | ||
410 | $format = $this->read_ushort(); | ||
411 | if ($format != 0 && $format != 1) | ||
412 | die("Unknown name table format ".$format); | ||
413 | $numRecords = $this->read_ushort(); | ||
414 | $string_data_offset = $name_offset + $this->read_ushort(); | ||
415 | $names = array(1=>'',2=>'',3=>'',4=>'',6=>''); | ||
416 | $K = array_keys($names); | ||
417 | $nameCount = count($names); | ||
418 | for ($i=0;$i<$numRecords; $i++) { | ||
419 | $platformId = $this->read_ushort(); | ||
420 | $encodingId = $this->read_ushort(); | ||
421 | $languageId = $this->read_ushort(); | ||
422 | $nameId = $this->read_ushort(); | ||
423 | $length = $this->read_ushort(); | ||
424 | $offset = $this->read_ushort(); | ||
425 | if (!in_array($nameId,$K)) continue; | ||
426 | $N = ''; | ||
427 | if ($platformId == 3 && $encodingId == 1 && $languageId == 0x409) { // Microsoft, Unicode, US English, PS Name | ||
428 | $opos = $this->_pos; | ||
429 | $this->seek($string_data_offset + $offset); | ||
430 | if ($length % 2 != 0) | ||
431 | die("PostScript name is UTF-16BE string of odd length"); | ||
432 | $length /= 2; | ||
433 | $N = ''; | ||
434 | while ($length > 0) { | ||
435 | $char = $this->read_ushort(); | ||
436 | $N .= (chr($char)); | ||
437 | $length -= 1; | ||
438 | } | ||
439 | $this->_pos = $opos; | ||
440 | $this->seek($opos); | ||
441 | } | ||
442 | else if ($platformId == 1 && $encodingId == 0 && $languageId == 0) { // Macintosh, Roman, English, PS Name | ||
443 | $opos = $this->_pos; | ||
444 | $N = $this->get_chunk($string_data_offset + $offset, $length); | ||
445 | $this->_pos = $opos; | ||
446 | $this->seek($opos); | ||
447 | } | ||
448 | if ($N && $names[$nameId]=='') { | ||
449 | $names[$nameId] = $N; | ||
450 | $nameCount -= 1; | ||
451 | if ($nameCount==0) break; | ||
452 | } | ||
453 | } | ||
454 | if ($names[6]) | ||
455 | $psName = $names[6]; | ||
456 | else if ($names[4]) | ||
457 | $psName = preg_replace('/ /','-',$names[4]); | ||
458 | else if ($names[1]) | ||
459 | $psName = preg_replace('/ /','-',$names[1]); | ||
460 | else | ||
461 | $psName = ''; | ||
462 | if (!$psName) | ||
463 | die("Could not find PostScript font name: ".$this->filename); | ||
464 | if ($debug) { | ||
465 | for ($i=0;$i<count($psName);$i++) { | ||
466 | $c = $psName[$i]; | ||
467 | $oc = ord($c); | ||
468 | if ($oc>126 || strpos(' [](){}<>/%',$c)!==false) | ||
469 | die("psName=".$psName." contains invalid character ".$c." ie U+".ord(c)); | ||
470 | } | ||
471 | } | ||
472 | $this->name = $psName; | ||
473 | if ($names[1]) { $this->familyName = $names[1]; } else { $this->familyName = $psName; } | ||
474 | if ($names[2]) { $this->styleName = $names[2]; } else { $this->styleName = 'Regular'; } | ||
475 | if ($names[4]) { $this->fullName = $names[4]; } else { $this->fullName = $psName; } | ||
476 | if ($names[3]) { $this->uniqueFontID = $names[3]; } else { $this->uniqueFontID = $psName; } | ||
477 | |||
478 | if ($names[6]) { $this->fullName = $names[6]; } | ||
479 | |||
480 | /////////////////////////////////// | ||
481 | // head - Font header table | ||
482 | /////////////////////////////////// | ||
483 | $this->seek_table("head"); | ||
484 | if ($debug) { | ||
485 | $ver_maj = $this->read_ushort(); | ||
486 | $ver_min = $this->read_ushort(); | ||
487 | if ($ver_maj != 1) | ||
488 | die('Unknown head table version '. $ver_maj .'.'. $ver_min); | ||
489 | $this->fontRevision = $this->read_ushort() . $this->read_ushort(); | ||
490 | |||
491 | $this->skip(4); | ||
492 | $magic = $this->read_ulong(); | ||
493 | if ($magic != 0x5F0F3CF5) | ||
494 | die('Invalid head table magic ' .$magic); | ||
495 | $this->skip(2); | ||
496 | } | ||
497 | else { | ||
498 | $this->skip(18); | ||
499 | } | ||
500 | $this->unitsPerEm = $unitsPerEm = $this->read_ushort(); | ||
501 | $scale = 1000 / $unitsPerEm; | ||
502 | $this->skip(16); | ||
503 | $xMin = $this->read_short(); | ||
504 | $yMin = $this->read_short(); | ||
505 | $xMax = $this->read_short(); | ||
506 | $yMax = $this->read_short(); | ||
507 | $this->bbox = array(($xMin*$scale), ($yMin*$scale), ($xMax*$scale), ($yMax*$scale)); | ||
508 | $this->skip(3*2); | ||
509 | $indexToLocFormat = $this->read_ushort(); | ||
510 | $glyphDataFormat = $this->read_ushort(); | ||
511 | if ($glyphDataFormat != 0) | ||
512 | die('Unknown glyph data format '.$glyphDataFormat); | ||
513 | |||
514 | /////////////////////////////////// | ||
515 | // hhea metrics table | ||
516 | /////////////////////////////////// | ||
517 | // ttf2t1 seems to use this value rather than the one in OS/2 - so put in for compatibility | ||
518 | if (isset($this->tables["hhea"])) { | ||
519 | $this->seek_table("hhea"); | ||
520 | $this->skip(4); | ||
521 | $hheaAscender = $this->read_short(); | ||
522 | $hheaDescender = $this->read_short(); | ||
523 | $this->ascent = ($hheaAscender *$scale); | ||
524 | $this->descent = ($hheaDescender *$scale); | ||
525 | } | ||
526 | |||
527 | /////////////////////////////////// | ||
528 | // OS/2 - OS/2 and Windows metrics table | ||
529 | /////////////////////////////////// | ||
530 | if (isset($this->tables["OS/2"])) { | ||
531 | $this->seek_table("OS/2"); | ||
532 | $version = $this->read_ushort(); | ||
533 | $this->skip(2); | ||
534 | $usWeightClass = $this->read_ushort(); | ||
535 | $this->skip(2); | ||
536 | $fsType = $this->read_ushort(); | ||
537 | if ($fsType == 0x0002 || ($fsType & 0x0300) != 0) { | ||
538 | global $overrideTTFFontRestriction; | ||
539 | if (!$overrideTTFFontRestriction) die('ERROR - Font file '.$this->filename.' cannot be embedded due to copyright restrictions.'); | ||
540 | $this->restrictedUse = true; | ||
541 | } | ||
542 | $this->skip(20); | ||
543 | $sF = $this->read_short(); | ||
544 | $this->sFamilyClass = ($sF >> 8); | ||
545 | $this->sFamilySubClass = ($sF & 0xFF); | ||
546 | $this->_pos += 10; //PANOSE = 10 byte length | ||
547 | $panose = fread($this->fh,10); | ||
548 | $this->panose = array(); | ||
549 | for ($p=0;$p<strlen($panose);$p++) { $this->panose[] = ord($panose[$p]); } | ||
550 | $this->skip(26); | ||
551 | $sTypoAscender = $this->read_short(); | ||
552 | $sTypoDescender = $this->read_short(); | ||
553 | if (!$this->ascent) $this->ascent = ($sTypoAscender*$scale); | ||
554 | if (!$this->descent) $this->descent = ($sTypoDescender*$scale); | ||
555 | if ($version > 1) { | ||
556 | $this->skip(16); | ||
557 | $sCapHeight = $this->read_short(); | ||
558 | $this->capHeight = ($sCapHeight*$scale); | ||
559 | } | ||
560 | else { | ||
561 | $this->capHeight = $this->ascent; | ||
562 | } | ||
563 | } | ||
564 | else { | ||
565 | $usWeightClass = 500; | ||
566 | if (!$this->ascent) $this->ascent = ($yMax*$scale); | ||
567 | if (!$this->descent) $this->descent = ($yMin*$scale); | ||
568 | $this->capHeight = $this->ascent; | ||
569 | } | ||
570 | $this->stemV = 50 + intval(pow(($usWeightClass / 65.0),2)); | ||
571 | |||
572 | /////////////////////////////////// | ||
573 | // post - PostScript table | ||
574 | /////////////////////////////////// | ||
575 | $this->seek_table("post"); | ||
576 | if ($debug) { | ||
577 | $ver_maj = $this->read_ushort(); | ||
578 | $ver_min = $this->read_ushort(); | ||
579 | if ($ver_maj <1 || $ver_maj >4) | ||
580 | die('Unknown post table version '.$ver_maj); | ||
581 | } | ||
582 | else { | ||
583 | $this->skip(4); | ||
584 | } | ||
585 | $this->italicAngle = $this->read_short() + $this->read_ushort() / 65536.0; | ||
586 | $this->underlinePosition = $this->read_short() * $scale; | ||
587 | $this->underlineThickness = $this->read_short() * $scale; | ||
588 | $isFixedPitch = $this->read_ulong(); | ||
589 | |||
590 | $this->flags = 4; | ||
591 | |||
592 | if ($this->italicAngle!= 0) | ||
593 | $this->flags = $this->flags | 64; | ||
594 | if ($usWeightClass >= 600) | ||
595 | $this->flags = $this->flags | 262144; | ||
596 | if ($isFixedPitch) | ||
597 | $this->flags = $this->flags | 1; | ||
598 | |||
599 | /////////////////////////////////// | ||
600 | // hhea - Horizontal header table | ||
601 | /////////////////////////////////// | ||
602 | $this->seek_table("hhea"); | ||
603 | if ($debug) { | ||
604 | $ver_maj = $this->read_ushort(); | ||
605 | $ver_min = $this->read_ushort(); | ||
606 | if ($ver_maj != 1) | ||
607 | die('Unknown hhea table version '.$ver_maj); | ||
608 | $this->skip(28); | ||
609 | } | ||
610 | else { | ||
611 | $this->skip(32); | ||
612 | } | ||
613 | $metricDataFormat = $this->read_ushort(); | ||
614 | if ($metricDataFormat != 0) | ||
615 | die('Unknown horizontal metric data format '.$metricDataFormat); | ||
616 | $numberOfHMetrics = $this->read_ushort(); | ||
617 | if ($numberOfHMetrics == 0) | ||
618 | die('Number of horizontal metrics is 0'); | ||
619 | |||
620 | /////////////////////////////////// | ||
621 | // maxp - Maximum profile table | ||
622 | /////////////////////////////////// | ||
623 | $this->seek_table("maxp"); | ||
624 | if ($debug) { | ||
625 | $ver_maj = $this->read_ushort(); | ||
626 | $ver_min = $this->read_ushort(); | ||
627 | if ($ver_maj != 1) | ||
628 | die('Unknown maxp table version '.$ver_maj); | ||
629 | } | ||
630 | else { | ||
631 | $this->skip(4); | ||
632 | } | ||
633 | $numGlyphs = $this->read_ushort(); | ||
634 | |||
635 | |||
636 | /////////////////////////////////// | ||
637 | // cmap - Character to glyph index mapping table | ||
638 | /////////////////////////////////// | ||
639 | $cmap_offset = $this->seek_table("cmap"); | ||
640 | $this->skip(2); | ||
641 | $cmapTableCount = $this->read_ushort(); | ||
642 | $unicode_cmap_offset = 0; | ||
643 | for ($i=0;$i<$cmapTableCount;$i++) { | ||
644 | $platformID = $this->read_ushort(); | ||
645 | $encodingID = $this->read_ushort(); | ||
646 | $offset = $this->read_ulong(); | ||
647 | $save_pos = $this->_pos; | ||
648 | if (($platformID == 3 && $encodingID == 1) || $platformID == 0) { // Microsoft, Unicode | ||
649 | $format = $this->get_ushort($cmap_offset + $offset); | ||
650 | if ($format == 4) { | ||
651 | if (!$unicode_cmap_offset) $unicode_cmap_offset = $cmap_offset + $offset; | ||
652 | if ($BMPonly) break; | ||
653 | } | ||
654 | } | ||
655 | // Microsoft, Unicode Format 12 table HKCS | ||
656 | else if ((($platformID == 3 && $encodingID == 10) || $platformID == 0) && !$BMPonly) { | ||
657 | $format = $this->get_ushort($cmap_offset + $offset); | ||
658 | if ($format == 12) { | ||
659 | $unicode_cmap_offset = $cmap_offset + $offset; | ||
660 | break; | ||
661 | } | ||
662 | } | ||
663 | $this->seek($save_pos ); | ||
664 | } | ||
665 | if (!$unicode_cmap_offset) | ||
666 | die('Font ('.$this->filename .') does not have cmap for Unicode (platform 3, encoding 1, format 4, or platform 0, any encoding, format 4)'); | ||
667 | |||
668 | |||
669 | $sipset = false; | ||
670 | $smpset = false; | ||
671 | // Format 12 CMAP does characters above Unicode BMP i.e. some HKCS characters U+20000 and above | ||
672 | if ($format == 12 && !$BMPonly) { | ||
673 | $this->maxUniChar = 0; | ||
674 | $this->seek($unicode_cmap_offset + 4); | ||
675 | $length = $this->read_ulong(); | ||
676 | $limit = $unicode_cmap_offset + $length; | ||
677 | $this->skip(4); | ||
678 | |||
679 | $nGroups = $this->read_ulong(); | ||
680 | |||
681 | $glyphToChar = array(); | ||
682 | $charToGlyph = array(); | ||
683 | for($i=0; $i<$nGroups ; $i++) { | ||
684 | $startCharCode = $this->read_ulong(); | ||
685 | $endCharCode = $this->read_ulong(); | ||
686 | $startGlyphCode = $this->read_ulong(); | ||
687 | if (($endCharCode > 0x20000 && $endCharCode < 0x2A6DF) || ($endCharCode > 0x2F800 && $endCharCode < 0x2FA1F)) { | ||
688 | $sipset = true; | ||
689 | } | ||
690 | else if ($endCharCode > 0x10000 && $endCharCode < 0x1FFFF) { | ||
691 | $smpset = true; | ||
692 | } | ||
693 | $offset = 0; | ||
694 | for ($unichar=$startCharCode;$unichar<=$endCharCode;$unichar++) { | ||
695 | $glyph = $startGlyphCode + $offset ; | ||
696 | $offset++; | ||
697 | $charToGlyph[$unichar] = $glyph; | ||
698 | if ($unichar < 196608) { $this->maxUniChar = max($unichar,$this->maxUniChar); } | ||
699 | $glyphToChar[$glyph][] = $unichar; | ||
700 | } | ||
701 | } | ||
702 | } | ||
703 | else { | ||
704 | |||
705 | $glyphToChar = array(); | ||
706 | $charToGlyph = array(); | ||
707 | $this->getCMAP4($unicode_cmap_offset, $glyphToChar, $charToGlyph ); | ||
708 | |||
709 | } | ||
710 | $this->sipset = $sipset ; | ||
711 | $this->smpset = $smpset ; | ||
712 | |||
713 | /////////////////////////////////// | ||
714 | // hmtx - Horizontal metrics table | ||
715 | /////////////////////////////////// | ||
716 | $this->getHMTX($numberOfHMetrics, $numGlyphs, $glyphToChar, $scale); | ||
717 | |||
718 | /////////////////////////////////// | ||
719 | // kern - Kerning pair table | ||
720 | /////////////////////////////////// | ||
721 | if ($kerninfo) { | ||
722 | // Recognises old form of Kerning table - as required by Windows - Format 0 only | ||
723 | $kern_offset = $this->seek_table("kern"); | ||
724 | $version = $this->read_ushort(); | ||
725 | $nTables = $this->read_ushort(); | ||
726 | // subtable header | ||
727 | $sversion = $this->read_ushort(); | ||
728 | $slength = $this->read_ushort(); | ||
729 | $scoverage = $this->read_ushort(); | ||
730 | $format = $scoverage >> 8; | ||
731 | if ($kern_offset && $version==0 && $format==0) { | ||
732 | // Format 0 | ||
733 | $nPairs = $this->read_ushort(); | ||
734 | $this->skip(6); | ||
735 | for ($i=0; $i<$nPairs; $i++) { | ||
736 | $left = $this->read_ushort(); | ||
737 | $right = $this->read_ushort(); | ||
738 | $val = $this->read_short(); | ||
739 | if (count($glyphToChar[$left])==1 && count($glyphToChar[$right])==1) { | ||
740 | if ($left != 32 && $right != 32) { | ||
741 | $this->kerninfo[$glyphToChar[$left][0]][$glyphToChar[$right][0]] = intval($val*$scale); | ||
742 | } | ||
743 | } | ||
744 | } | ||
745 | } | ||
746 | } | ||
747 | } | ||
748 | |||
749 | |||
750 | ///////////////////////////////////////////////////////////////////////////////////////// | ||
751 | |||
752 | |||
753 | function makeSubset($file, &$subset, $TTCfontID=0, $debug=false, $unAGlyphs=false) { // mPDF 5.4.05 | ||
754 | $this->unAGlyphs = $unAGlyphs; // mPDF 5.4.05 | ||
755 | $this->filename = $file; | ||
756 | $this->fh = fopen($file ,'rb') or die('Can\'t open file ' . $file); | ||
757 | $this->_pos = 0; | ||
758 | $this->charWidths = ''; | ||
759 | $this->glyphPos = array(); | ||
760 | $this->charToGlyph = array(); | ||
761 | $this->tables = array(); | ||
762 | $this->otables = array(); | ||
763 | $this->ascent = 0; | ||
764 | $this->descent = 0; | ||
765 | $this->numTTCFonts = 0; | ||
766 | $this->TTCFonts = array(); | ||
767 | $this->skip(4); | ||
768 | $this->maxUni = 0; | ||
769 | if ($TTCfontID > 0) { | ||
770 | $this->version = $version = $this->read_ulong(); // TTC Header version now | ||
771 | if (!in_array($version, array(0x00010000,0x00020000))) | ||
772 | die("ERROR - Error parsing TrueType Collection: version=".$version." - " . $file); | ||
773 | $this->numTTCFonts = $this->read_ulong(); | ||
774 | for ($i=1; $i<=$this->numTTCFonts; $i++) { | ||
775 | $this->TTCFonts[$i]['offset'] = $this->read_ulong(); | ||
776 | } | ||
777 | $this->seek($this->TTCFonts[$TTCfontID]['offset']); | ||
778 | $this->version = $version = $this->read_ulong(); // TTFont version again now | ||
779 | } | ||
780 | $this->readTableDirectory($debug); | ||
781 | |||
782 | /////////////////////////////////// | ||
783 | // head - Font header table | ||
784 | /////////////////////////////////// | ||
785 | $this->seek_table("head"); | ||
786 | $this->skip(50); | ||
787 | $indexToLocFormat = $this->read_ushort(); | ||
788 | $glyphDataFormat = $this->read_ushort(); | ||
789 | |||
790 | /////////////////////////////////// | ||
791 | // hhea - Horizontal header table | ||
792 | /////////////////////////////////// | ||
793 | $this->seek_table("hhea"); | ||
794 | $this->skip(32); | ||
795 | $metricDataFormat = $this->read_ushort(); | ||
796 | $orignHmetrics = $numberOfHMetrics = $this->read_ushort(); | ||
797 | |||
798 | /////////////////////////////////// | ||
799 | // maxp - Maximum profile table | ||
800 | /////////////////////////////////// | ||
801 | $this->seek_table("maxp"); | ||
802 | $this->skip(4); | ||
803 | $numGlyphs = $this->read_ushort(); | ||
804 | |||
805 | |||
806 | /////////////////////////////////// | ||
807 | // cmap - Character to glyph index mapping table | ||
808 | /////////////////////////////////// | ||
809 | $cmap_offset = $this->seek_table("cmap"); | ||
810 | $this->skip(2); | ||
811 | $cmapTableCount = $this->read_ushort(); | ||
812 | $unicode_cmap_offset = 0; | ||
813 | for ($i=0;$i<$cmapTableCount;$i++) { | ||
814 | $platformID = $this->read_ushort(); | ||
815 | $encodingID = $this->read_ushort(); | ||
816 | $offset = $this->read_ulong(); | ||
817 | $save_pos = $this->_pos; | ||
818 | if (($platformID == 3 && $encodingID == 1) || $platformID == 0) { // Microsoft, Unicode | ||
819 | $format = $this->get_ushort($cmap_offset + $offset); | ||
820 | if ($format == 4) { | ||
821 | $unicode_cmap_offset = $cmap_offset + $offset; | ||
822 | break; | ||
823 | } | ||
824 | } | ||
825 | $this->seek($save_pos ); | ||
826 | } | ||
827 | |||
828 | if (!$unicode_cmap_offset) | ||
829 | die('Font ('.$this->filename .') does not have Unicode cmap (platform 3, encoding 1, format 4, or platform 0 [any encoding] format 4)'); | ||
830 | |||
831 | |||
832 | $glyphToChar = array(); | ||
833 | $charToGlyph = array(); | ||
834 | $this->getCMAP4($unicode_cmap_offset, $glyphToChar, $charToGlyph ); | ||
835 | |||
836 | $this->charToGlyph = $charToGlyph; | ||
837 | |||
838 | |||
839 | /////////////////////////////////// | ||
840 | // hmtx - Horizontal metrics table | ||
841 | /////////////////////////////////// | ||
842 | $scale = 1; // not used | ||
843 | $this->getHMTX($numberOfHMetrics, $numGlyphs, $glyphToChar, $scale); | ||
844 | |||
845 | /////////////////////////////////// | ||
846 | // loca - Index to location | ||
847 | /////////////////////////////////// | ||
848 | $this->getLOCA($indexToLocFormat, $numGlyphs); | ||
849 | |||
850 | $subsetglyphs = array(0=>0, 1=>1, 2=>2); | ||
851 | $subsetCharToGlyph = array(); | ||
852 | foreach($subset AS $code) { | ||
853 | if (isset($this->charToGlyph[$code])) { | ||
854 | $subsetglyphs[$this->charToGlyph[$code]] = $code; // Old Glyph ID => Unicode | ||
855 | $subsetCharToGlyph[$code] = $this->charToGlyph[$code]; // Unicode to old GlyphID | ||
856 | |||
857 | } | ||
858 | $this->maxUni = max($this->maxUni, $code); | ||
859 | } | ||
860 | |||
861 | list($start,$dummy) = $this->get_table_pos('glyf'); | ||
862 | |||
863 | $glyphSet = array(); | ||
864 | ksort($subsetglyphs); | ||
865 | $n = 0; | ||
866 | $fsLastCharIndex = 0; // maximum Unicode index (character code) in this font, according to the cmap subtable for platform ID 3 and platform- specific encoding ID 0 or 1. | ||
867 | foreach($subsetglyphs AS $originalGlyphIdx => $uni) { | ||
868 | $fsLastCharIndex = max($fsLastCharIndex , $uni); | ||
869 | $glyphSet[$originalGlyphIdx] = $n; // old glyphID to new glyphID | ||
870 | $n++; | ||
871 | } | ||
872 | |||
873 | ksort($subsetCharToGlyph); | ||
874 | foreach($subsetCharToGlyph AS $uni => $originalGlyphIdx) { | ||
875 | $codeToGlyph[$uni] = $glyphSet[$originalGlyphIdx] ; | ||
876 | } | ||
877 | $this->codeToGlyph = $codeToGlyph; | ||
878 | |||
879 | ksort($subsetglyphs); | ||
880 | foreach($subsetglyphs AS $originalGlyphIdx => $uni) { | ||
881 | $this->getGlyphs($originalGlyphIdx, $start, $glyphSet, $subsetglyphs); | ||
882 | } | ||
883 | |||
884 | $numGlyphs = $numberOfHMetrics = count($subsetglyphs ); | ||
885 | |||
886 | /////////////////////////////////// | ||
887 | // name - table copied from the original | ||
888 | /////////////////////////////////// | ||
889 | $this->add('name', $this->get_table('name')); | ||
890 | |||
891 | /////////////////////////////////// | ||
892 | //tables copied from the original | ||
893 | /////////////////////////////////// | ||
894 | $tags = array ('cvt ', 'fpgm', 'prep', 'gasp'); | ||
895 | foreach($tags AS $tag) { | ||
896 | if (isset($this->tables[$tag])) { $this->add($tag, $this->get_table($tag)); } | ||
897 | } | ||
898 | |||
899 | /////////////////////////////////// | ||
900 | // post - PostScript | ||
901 | /////////////////////////////////// | ||
902 | if (isset($this->tables['post'])) { | ||
903 | $opost = $this->get_table('post'); | ||
904 | $post = "\x00\x03\x00\x00" . substr($opost,4,12) . "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; | ||
905 | $this->add('post', $post); | ||
906 | } | ||
907 | |||
908 | /////////////////////////////////// | ||
909 | // Sort CID2GID map into segments of contiguous codes | ||
910 | /////////////////////////////////// | ||
911 | ksort($codeToGlyph); | ||
912 | unset($codeToGlyph[0]); | ||
913 | //unset($codeToGlyph[65535]); | ||
914 | $rangeid = 0; | ||
915 | $range = array(); | ||
916 | $prevcid = -2; | ||
917 | $prevglidx = -1; | ||
918 | // for each character | ||
919 | foreach ($codeToGlyph as $cid => $glidx) { | ||
920 | if ($cid == ($prevcid + 1) && $glidx == ($prevglidx + 1)) { | ||
921 | $range[$rangeid][] = $glidx; | ||
922 | } else { | ||
923 | // new range | ||
924 | $rangeid = $cid; | ||
925 | $range[$rangeid] = array(); | ||
926 | $range[$rangeid][] = $glidx; | ||
927 | } | ||
928 | $prevcid = $cid; | ||
929 | $prevglidx = $glidx; | ||
930 | } | ||
931 | |||
932 | |||
933 | |||
934 | /////////////////////////////////// | ||
935 | // CMap table | ||
936 | /////////////////////////////////// | ||
937 | // cmap - Character to glyph mapping | ||
938 | $segCount = count($range) + 1; // + 1 Last segment has missing character 0xFFFF | ||
939 | $searchRange = 1; | ||
940 | $entrySelector = 0; | ||
941 | while ($searchRange * 2 <= $segCount ) { | ||
942 | $searchRange = $searchRange * 2; | ||
943 | $entrySelector = $entrySelector + 1; | ||
944 | } | ||
945 | $searchRange = $searchRange * 2; | ||
946 | $rangeShift = $segCount * 2 - $searchRange; | ||
947 | $length = 16 + (8*$segCount ) + ($numGlyphs+1); | ||
948 | $cmap = array(0, 3, // Index : version, number of encoding subtables | ||
949 | 0, 0, // Encoding Subtable : platform (UNI=0), encoding 0 | ||
950 | 0, 28, // Encoding Subtable : offset (hi,lo) | ||
951 | 0, 3, // Encoding Subtable : platform (UNI=0), encoding 3 | ||
952 | 0, 28, // Encoding Subtable : offset (hi,lo) | ||
953 | 3, 1, // Encoding Subtable : platform (MS=3), encoding 1 | ||
954 | 0, 28, // Encoding Subtable : offset (hi,lo) | ||
955 | 4, $length, 0, // Format 4 Mapping subtable: format, length, language | ||
956 | $segCount*2, | ||
957 | $searchRange, | ||
958 | $entrySelector, | ||
959 | $rangeShift); | ||
960 | |||
961 | // endCode(s) | ||
962 | foreach($range AS $start=>$subrange) { | ||
963 | $endCode = $start + (count($subrange)-1); | ||
964 | $cmap[] = $endCode; // endCode(s) | ||
965 | } | ||
966 | $cmap[] = 0xFFFF; // endCode of last Segment | ||
967 | $cmap[] = 0; // reservedPad | ||
968 | |||
969 | // startCode(s) | ||
970 | foreach($range AS $start=>$subrange) { | ||
971 | $cmap[] = $start; // startCode(s) | ||
972 | } | ||
973 | $cmap[] = 0xFFFF; // startCode of last Segment | ||
974 | // idDelta(s) | ||
975 | foreach($range AS $start=>$subrange) { | ||
976 | $idDelta = -($start-$subrange[0]); | ||
977 | $n += count($subrange); | ||
978 | $cmap[] = $idDelta; // idDelta(s) | ||
979 | } | ||
980 | $cmap[] = 1; // idDelta of last Segment | ||
981 | // idRangeOffset(s) | ||
982 | foreach($range AS $subrange) { | ||
983 | $cmap[] = 0; // idRangeOffset[segCount] Offset in bytes to glyph indexArray, or 0 | ||
984 | |||
985 | } | ||
986 | $cmap[] = 0; // idRangeOffset of last Segment | ||
987 | foreach($range AS $subrange) { | ||
988 | foreach($subrange AS $glidx) { | ||
989 | $cmap[] = $glidx; | ||
990 | } | ||
991 | } | ||
992 | $cmap[] = 0; // Mapping for last character | ||
993 | $cmapstr = ''; | ||
994 | foreach($cmap AS $cm) { $cmapstr .= pack("n",$cm); } | ||
995 | $this->add('cmap', $cmapstr); | ||
996 | |||
997 | |||
998 | /////////////////////////////////// | ||
999 | // glyf - Glyph data | ||
1000 | /////////////////////////////////// | ||
1001 | list($glyfOffset,$glyfLength) = $this->get_table_pos('glyf'); | ||
1002 | if ($glyfLength < $this->maxStrLenRead) { | ||
1003 | $glyphData = $this->get_table('glyf'); | ||
1004 | } | ||
1005 | |||
1006 | $offsets = array(); | ||
1007 | $glyf = ''; | ||
1008 | $pos = 0; | ||
1009 | $hmtxstr = ''; | ||
1010 | $xMinT = 0; | ||
1011 | $yMinT = 0; | ||
1012 | $xMaxT = 0; | ||
1013 | $yMaxT = 0; | ||
1014 | $advanceWidthMax = 0; | ||
1015 | $minLeftSideBearing = 0; | ||
1016 | $minRightSideBearing = 0; | ||
1017 | $xMaxExtent = 0; | ||
1018 | $maxPoints = 0; // points in non-compound glyph | ||
1019 | $maxContours = 0; // contours in non-compound glyph | ||
1020 | $maxComponentPoints = 0; // points in compound glyph | ||
1021 | $maxComponentContours = 0; // contours in compound glyph | ||
1022 | $maxComponentElements = 0; // number of glyphs referenced at top level | ||
1023 | $maxComponentDepth = 0; // levels of recursion, set to 0 if font has only simple glyphs | ||
1024 | $this->glyphdata = array(); | ||
1025 | |||
1026 | foreach($subsetglyphs AS $originalGlyphIdx => $uni) { | ||
1027 | // hmtx - Horizontal Metrics | ||
1028 | $hm = $this->getHMetric($orignHmetrics, $originalGlyphIdx); | ||
1029 | $hmtxstr .= $hm; | ||
1030 | |||
1031 | $offsets[] = $pos; | ||
1032 | $glyphPos = $this->glyphPos[$originalGlyphIdx]; | ||
1033 | $glyphLen = $this->glyphPos[$originalGlyphIdx + 1] - $glyphPos; | ||
1034 | if ($glyfLength < $this->maxStrLenRead) { | ||
1035 | $data = substr($glyphData,$glyphPos,$glyphLen); | ||
1036 | } | ||
1037 | else { | ||
1038 | if ($glyphLen > 0) $data = $this->get_chunk($glyfOffset+$glyphPos,$glyphLen); | ||
1039 | else $data = ''; | ||
1040 | } | ||
1041 | |||
1042 | if ($glyphLen > 0) { | ||
1043 | if (_RECALC_PROFILE) { | ||
1044 | $xMin = $this->unpack_short(substr($data,2,2)); | ||
1045 | $yMin = $this->unpack_short(substr($data,4,2)); | ||
1046 | $xMax = $this->unpack_short(substr($data,6,2)); | ||
1047 | $yMax = $this->unpack_short(substr($data,8,2)); | ||
1048 | $xMinT = min($xMinT,$xMin); | ||
1049 | $yMinT = min($yMinT,$yMin); | ||
1050 | $xMaxT = max($xMaxT,$xMax); | ||
1051 | $yMaxT = max($yMaxT,$yMax); | ||
1052 | $aw = $this->unpack_short(substr($hm,0,2)); | ||
1053 | $lsb = $this->unpack_short(substr($hm,2,2)); | ||
1054 | $advanceWidthMax = max($advanceWidthMax,$aw); | ||
1055 | $minLeftSideBearing = min($minLeftSideBearing,$lsb); | ||
1056 | $minRightSideBearing = min($minRightSideBearing,($aw - $lsb - ($xMax - $xMin))); | ||
1057 | $xMaxExtent = max($xMaxExtent,($lsb + ($xMax - $xMin))); | ||
1058 | } | ||
1059 | $up = unpack("n", substr($data,0,2)); | ||
1060 | } | ||
1061 | if ($glyphLen > 2 && ($up[1] & (1 << 15)) ) { // If number of contours <= -1 i.e. composiste glyph | ||
1062 | $pos_in_glyph = 10; | ||
1063 | $flags = GF_MORE; | ||
1064 | $nComponentElements = 0; | ||
1065 | while ($flags & GF_MORE) { | ||
1066 | $nComponentElements += 1; // number of glyphs referenced at top level | ||
1067 | $up = unpack("n", substr($data,$pos_in_glyph,2)); | ||
1068 | $flags = $up[1]; | ||
1069 | $up = unpack("n", substr($data,$pos_in_glyph+2,2)); | ||
1070 | $glyphIdx = $up[1]; | ||
1071 | $this->glyphdata[$originalGlyphIdx]['compGlyphs'][] = $glyphIdx; | ||
1072 | $data = $this->_set_ushort($data, $pos_in_glyph + 2, $glyphSet[$glyphIdx]); | ||
1073 | $pos_in_glyph += 4; | ||
1074 | if ($flags & GF_WORDS) { $pos_in_glyph += 4; } | ||
1075 | else { $pos_in_glyph += 2; } | ||
1076 | if ($flags & GF_SCALE) { $pos_in_glyph += 2; } | ||
1077 | else if ($flags & GF_XYSCALE) { $pos_in_glyph += 4; } | ||
1078 | else if ($flags & GF_TWOBYTWO) { $pos_in_glyph += 8; } | ||
1079 | } | ||
1080 | $maxComponentElements = max($maxComponentElements, $nComponentElements); | ||
1081 | } | ||
1082 | // Simple Glyph | ||
1083 | else if (_RECALC_PROFILE && $glyphLen > 2 && $up[1] < (1 << 15) && $up[1] > 0) { // Number of contours > 0 simple glyph | ||
1084 | $nContours = $up[1]; | ||
1085 | $this->glyphdata[$originalGlyphIdx]['nContours'] = $nContours; | ||
1086 | $maxContours = max($maxContours, $nContours); | ||
1087 | |||
1088 | // Count number of points in simple glyph | ||
1089 | $pos_in_glyph = 10 + ($nContours * 2) - 2; // Last endContourPoint | ||
1090 | $up = unpack("n", substr($data,$pos_in_glyph,2)); | ||
1091 | $points = $up[1]+1; | ||
1092 | $this->glyphdata[$originalGlyphIdx]['nPoints'] = $points; | ||
1093 | $maxPoints = max($maxPoints, $points); | ||
1094 | } | ||
1095 | |||
1096 | $glyf .= $data; | ||
1097 | $pos += $glyphLen; | ||
1098 | if ($pos % 4 != 0) { | ||
1099 | $padding = 4 - ($pos % 4); | ||
1100 | $glyf .= str_repeat("\0",$padding); | ||
1101 | $pos += $padding; | ||
1102 | } | ||
1103 | } | ||
1104 | |||
1105 | if (_RECALC_PROFILE) { | ||
1106 | foreach($this->glyphdata AS $originalGlyphIdx => $val) { | ||
1107 | $maxdepth = $depth = -1; | ||
1108 | $points = 0; | ||
1109 | $contours = 0; | ||
1110 | $this->getGlyphData($originalGlyphIdx, $maxdepth, $depth, $points, $contours) ; | ||
1111 | $maxComponentDepth = max($maxComponentDepth , $maxdepth); | ||
1112 | $maxComponentPoints = max($maxComponentPoints , $points); | ||
1113 | $maxComponentContours = max($maxComponentContours , $contours); | ||
1114 | } | ||
1115 | } | ||
1116 | |||
1117 | |||
1118 | $offsets[] = $pos; | ||
1119 | $this->add('glyf', $glyf); | ||
1120 | |||
1121 | /////////////////////////////////// | ||
1122 | // hmtx - Horizontal Metrics | ||
1123 | /////////////////////////////////// | ||
1124 | $this->add('hmtx', $hmtxstr); | ||
1125 | |||
1126 | |||
1127 | /////////////////////////////////// | ||
1128 | // loca - Index to location | ||
1129 | /////////////////////////////////// | ||
1130 | $locastr = ''; | ||
1131 | if ((($pos + 1) >> 1) > 0xFFFF) { | ||
1132 | $indexToLocFormat = 1; // long format | ||
1133 | foreach($offsets AS $offset) { $locastr .= pack("N",$offset); } | ||
1134 | } | ||
1135 | else { | ||
1136 | $indexToLocFormat = 0; // short format | ||
1137 | foreach($offsets AS $offset) { $locastr .= pack("n",($offset/2)); } | ||
1138 | } | ||
1139 | $this->add('loca', $locastr); | ||
1140 | |||
1141 | /////////////////////////////////// | ||
1142 | // head - Font header | ||
1143 | /////////////////////////////////// | ||
1144 | $head = $this->get_table('head'); | ||
1145 | $head = $this->_set_ushort($head, 50, $indexToLocFormat); | ||
1146 | if (_RECALC_PROFILE) { | ||
1147 | $head = $this->_set_short($head, 36, $xMinT); // for all glyph bounding boxes | ||
1148 | $head = $this->_set_short($head, 38, $yMinT); // for all glyph bounding boxes | ||
1149 | $head = $this->_set_short($head, 40, $xMaxT); // for all glyph bounding boxes | ||
1150 | $head = $this->_set_short($head, 42, $yMaxT); // for all glyph bounding boxes | ||
1151 | $head[17] = chr($head[17] & ~(1 << 4)); // Unset Bit 4 (as hdmx/LTSH tables not included) | ||
1152 | } | ||
1153 | $this->add('head', $head); | ||
1154 | |||
1155 | |||
1156 | /////////////////////////////////// | ||
1157 | // hhea - Horizontal Header | ||
1158 | /////////////////////////////////// | ||
1159 | $hhea = $this->get_table('hhea'); | ||
1160 | $hhea = $this->_set_ushort($hhea, 34, $numberOfHMetrics); | ||
1161 | if (_RECALC_PROFILE) { | ||
1162 | $hhea = $this->_set_ushort($hhea, 10, $advanceWidthMax); | ||
1163 | $hhea = $this->_set_short($hhea, 12, $minLeftSideBearing); | ||
1164 | $hhea = $this->_set_short($hhea, 14, $minRightSideBearing); | ||
1165 | $hhea = $this->_set_short($hhea, 16, $xMaxExtent); | ||
1166 | } | ||
1167 | $this->add('hhea', $hhea); | ||
1168 | |||
1169 | /////////////////////////////////// | ||
1170 | // maxp - Maximum Profile | ||
1171 | /////////////////////////////////// | ||
1172 | $maxp = $this->get_table('maxp'); | ||
1173 | $maxp = $this->_set_ushort($maxp, 4, $numGlyphs); | ||
1174 | if (_RECALC_PROFILE) { | ||
1175 | $maxp = $this->_set_ushort($maxp, 6, $maxPoints); // points in non-compound glyph | ||
1176 | $maxp = $this->_set_ushort($maxp, 8, $maxContours); // contours in non-compound glyph | ||
1177 | $maxp = $this->_set_ushort($maxp, 10, $maxComponentPoints); // points in compound glyph | ||
1178 | $maxp = $this->_set_ushort($maxp, 12, $maxComponentContours); // contours in compound glyph | ||
1179 | $maxp = $this->_set_ushort($maxp, 28, $maxComponentElements); // number of glyphs referenced at top level | ||
1180 | $maxp = $this->_set_ushort($maxp, 30, $maxComponentDepth); // levels of recursion, set to 0 if font has only simple glyphs | ||
1181 | } | ||
1182 | $this->add('maxp', $maxp); | ||
1183 | |||
1184 | |||
1185 | /////////////////////////////////// | ||
1186 | // OS/2 - OS/2 | ||
1187 | /////////////////////////////////// | ||
1188 | if (isset($this->tables['OS/2'])) { | ||
1189 | $os2_offset = $this->seek_table("OS/2"); | ||
1190 | if (_RECALC_PROFILE) { | ||
1191 | $fsSelection = $this->get_ushort($os2_offset+62); | ||
1192 | $fsSelection = ($fsSelection & ~(1 << 6)); // 2-byte bit field containing information concerning the nature of the font patterns | ||
1193 | // bit#0 = Italic; bit#5=Bold | ||
1194 | // Match name table's font subfamily string | ||
1195 | // Clear bit#6 used for 'Regular' and optional | ||
1196 | } | ||
1197 | |||
1198 | // NB Currently this method never subsets characters above BMP | ||
1199 | // Could set nonBMP bit according to $this->maxUni | ||
1200 | $nonBMP = $this->get_ushort($os2_offset+46); | ||
1201 | $nonBMP = ($nonBMP & ~(1 << 9)); // Unset Bit 57 (indicates non-BMP) - for interactive forms | ||
1202 | |||
1203 | $os2 = $this->get_table('OS/2'); | ||
1204 | if (_RECALC_PROFILE) { | ||
1205 | $os2 = $this->_set_ushort($os2, 62, $fsSelection); | ||
1206 | $os2 = $this->_set_ushort($os2, 66, $fsLastCharIndex); | ||
1207 | $os2 = $this->_set_ushort($os2, 42, 0x0000); // ulCharRange (ulUnicodeRange) bits 24-31 | 16-23 | ||
1208 | $os2 = $this->_set_ushort($os2, 44, 0x0000); // ulCharRange (Unicode ranges) bits 8-15 | 0-7 | ||
1209 | $os2 = $this->_set_ushort($os2, 46, $nonBMP); // ulCharRange (Unicode ranges) bits 56-63 | 48-55 | ||
1210 | $os2 = $this->_set_ushort($os2, 48, 0x0000); // ulCharRange (Unicode ranges) bits 40-47 | 32-39 | ||
1211 | $os2 = $this->_set_ushort($os2, 50, 0x0000); // ulCharRange (Unicode ranges) bits 88-95 | 80-87 | ||
1212 | $os2 = $this->_set_ushort($os2, 52, 0x0000); // ulCharRange (Unicode ranges) bits 72-79 | 64-71 | ||
1213 | $os2 = $this->_set_ushort($os2, 54, 0x0000); // ulCharRange (Unicode ranges) bits 120-127 | 112-119 | ||
1214 | $os2 = $this->_set_ushort($os2, 56, 0x0000); // ulCharRange (Unicode ranges) bits 104-111 | 96-103 | ||
1215 | } | ||
1216 | $os2 = $this->_set_ushort($os2, 46, $nonBMP); // Unset Bit 57 (indicates non-BMP) - for interactive forms | ||
1217 | |||
1218 | $this->add('OS/2', $os2 ); | ||
1219 | } | ||
1220 | |||
1221 | fclose($this->fh); | ||
1222 | // Put the TTF file together | ||
1223 | $stm = ''; | ||
1224 | $this->endTTFile($stm); | ||
1225 | //file_put_contents('testfont.ttf', $stm); exit; | ||
1226 | return $stm ; | ||
1227 | } | ||
1228 | |||
1229 | //================================================================================ | ||
1230 | |||
1231 | // Also does SMP | ||
1232 | function makeSubsetSIP($file, &$subset, $TTCfontID=0, $debug=false) { | ||
1233 | $this->fh = fopen($file ,'rb') or die('Can\'t open file ' . $file); | ||
1234 | $this->filename = $file; | ||
1235 | $this->_pos = 0; | ||
1236 | $this->unAGlyphs = false; // mPDF 5.4.05 | ||
1237 | $this->charWidths = ''; | ||
1238 | $this->glyphPos = array(); | ||
1239 | $this->charToGlyph = array(); | ||
1240 | $this->tables = array(); | ||
1241 | $this->otables = array(); | ||
1242 | $this->ascent = 0; | ||
1243 | $this->descent = 0; | ||
1244 | $this->numTTCFonts = 0; | ||
1245 | $this->TTCFonts = array(); | ||
1246 | $this->skip(4); | ||
1247 | if ($TTCfontID > 0) { | ||
1248 | $this->version = $version = $this->read_ulong(); // TTC Header version now | ||
1249 | if (!in_array($version, array(0x00010000,0x00020000))) | ||
1250 | die("ERROR - Error parsing TrueType Collection: version=".$version." - " . $file); | ||
1251 | $this->numTTCFonts = $this->read_ulong(); | ||
1252 | for ($i=1; $i<=$this->numTTCFonts; $i++) { | ||
1253 | $this->TTCFonts[$i]['offset'] = $this->read_ulong(); | ||
1254 | } | ||
1255 | $this->seek($this->TTCFonts[$TTCfontID]['offset']); | ||
1256 | $this->version = $version = $this->read_ulong(); // TTFont version again now | ||
1257 | } | ||
1258 | $this->readTableDirectory($debug); | ||
1259 | |||
1260 | |||
1261 | |||
1262 | /////////////////////////////////// | ||
1263 | // head - Font header table | ||
1264 | /////////////////////////////////// | ||
1265 | $this->seek_table("head"); | ||
1266 | $this->skip(50); | ||
1267 | $indexToLocFormat = $this->read_ushort(); | ||
1268 | $glyphDataFormat = $this->read_ushort(); | ||
1269 | |||
1270 | /////////////////////////////////// | ||
1271 | // hhea - Horizontal header table | ||
1272 | /////////////////////////////////// | ||
1273 | $this->seek_table("hhea"); | ||
1274 | $this->skip(32); | ||
1275 | $metricDataFormat = $this->read_ushort(); | ||
1276 | $orignHmetrics = $numberOfHMetrics = $this->read_ushort(); | ||
1277 | |||
1278 | /////////////////////////////////// | ||
1279 | // maxp - Maximum profile table | ||
1280 | /////////////////////////////////// | ||
1281 | $this->seek_table("maxp"); | ||
1282 | $this->skip(4); | ||
1283 | $numGlyphs = $this->read_ushort(); | ||
1284 | |||
1285 | |||
1286 | /////////////////////////////////// | ||
1287 | // cmap - Character to glyph index mapping table | ||
1288 | /////////////////////////////////// | ||
1289 | |||
1290 | $cmap_offset = $this->seek_table("cmap"); | ||
1291 | $this->skip(2); | ||
1292 | $cmapTableCount = $this->read_ushort(); | ||
1293 | $unicode_cmap_offset = 0; | ||
1294 | for ($i=0;$i<$cmapTableCount;$i++) { | ||
1295 | $platformID = $this->read_ushort(); | ||
1296 | $encodingID = $this->read_ushort(); | ||
1297 | $offset = $this->read_ulong(); | ||
1298 | $save_pos = $this->_pos; | ||
1299 | if (($platformID == 3 && $encodingID == 10) || $platformID == 0) { // Microsoft, Unicode Format 12 table HKCS | ||
1300 | $format = $this->get_ushort($cmap_offset + $offset); | ||
1301 | if ($format == 12) { | ||
1302 | $unicode_cmap_offset = $cmap_offset + $offset; | ||
1303 | break; | ||
1304 | } | ||
1305 | } | ||
1306 | $this->seek($save_pos ); | ||
1307 | } | ||
1308 | |||
1309 | if (!$unicode_cmap_offset) | ||
1310 | die('Font does not have cmap for Unicode (platform 3, encoding 1, format 4, or platform 0, any encoding, format 4)'); | ||
1311 | // Format 12 CMAP does characters above Unicode BMP i.e. some HKCS characters U+20000 and above | ||
1312 | if ($format == 12) { | ||
1313 | $this->maxUniChar = 0; | ||
1314 | $this->seek($unicode_cmap_offset + 4); | ||
1315 | $length = $this->read_ulong(); | ||
1316 | $limit = $unicode_cmap_offset + $length; | ||
1317 | $this->skip(4); | ||
1318 | |||
1319 | $nGroups = $this->read_ulong(); | ||
1320 | |||
1321 | $glyphToChar = array(); | ||
1322 | $charToGlyph = array(); | ||
1323 | for($i=0; $i<$nGroups ; $i++) { | ||
1324 | $startCharCode = $this->read_ulong(); | ||
1325 | $endCharCode = $this->read_ulong(); | ||
1326 | $startGlyphCode = $this->read_ulong(); | ||
1327 | $offset = 0; | ||
1328 | for ($unichar=$startCharCode;$unichar<=$endCharCode;$unichar++) { | ||
1329 | $glyph = $startGlyphCode + $offset ; | ||
1330 | $offset++; | ||
1331 | $charToGlyph[$unichar] = $glyph; | ||
1332 | if ($unichar < 196608) { $this->maxUniChar = max($unichar,$this->maxUniChar); } | ||
1333 | $glyphToChar[$glyph][] = $unichar; | ||
1334 | } | ||
1335 | } | ||
1336 | } | ||
1337 | else | ||
1338 | die('Font does not have cmap for Unicode (format 12)'); | ||
1339 | |||
1340 | |||
1341 | /////////////////////////////////// | ||
1342 | // hmtx - Horizontal metrics table | ||
1343 | /////////////////////////////////// | ||
1344 | $scale = 1; // not used here | ||
1345 | $this->getHMTX($numberOfHMetrics, $numGlyphs, $glyphToChar, $scale); | ||
1346 | |||
1347 | /////////////////////////////////// | ||
1348 | // loca - Index to location | ||
1349 | /////////////////////////////////// | ||
1350 | $this->getLOCA($indexToLocFormat, $numGlyphs); | ||
1351 | |||
1352 | /////////////////////////////////////////////////////////////////// | ||
1353 | |||
1354 | $glyphMap = array(0=>0); | ||
1355 | $glyphSet = array(0=>0); | ||
1356 | $codeToGlyph = array(); | ||
1357 | // Set a substitute if ASCII characters do not have glyphs | ||
1358 | if (isset($charToGlyph[0x3F])) { $subs = $charToGlyph[0x3F]; } // Question mark | ||
1359 | else { $subs = $charToGlyph[32]; } | ||
1360 | foreach($subset AS $code) { | ||
1361 | if (isset($charToGlyph[$code])) | ||
1362 | $originalGlyphIdx = $charToGlyph[$code]; | ||
1363 | else if ($code<128) { | ||
1364 | $originalGlyphIdx = $subs; | ||
1365 | } | ||
1366 | else { $originalGlyphIdx = 0; } | ||
1367 | if (!isset($glyphSet[$originalGlyphIdx])) { | ||
1368 | $glyphSet[$originalGlyphIdx] = count($glyphMap); | ||
1369 | $glyphMap[] = $originalGlyphIdx; | ||
1370 | } | ||
1371 | $codeToGlyph[$code] = $glyphSet[$originalGlyphIdx]; | ||
1372 | } | ||
1373 | |||
1374 | list($start,$dummy) = $this->get_table_pos('glyf'); | ||
1375 | |||
1376 | $n = 0; | ||
1377 | while ($n < count($glyphMap)) { | ||
1378 | $originalGlyphIdx = $glyphMap[$n]; | ||
1379 | $glyphPos = $this->glyphPos[$originalGlyphIdx]; | ||
1380 | $glyphLen = $this->glyphPos[$originalGlyphIdx + 1] - $glyphPos; | ||
1381 | $n += 1; | ||
1382 | if (!$glyphLen) continue; | ||
1383 | $this->seek($start + $glyphPos); | ||
1384 | $numberOfContours = $this->read_short(); | ||
1385 | if ($numberOfContours < 0) { | ||
1386 | $this->skip(8); | ||
1387 | $flags = GF_MORE; | ||
1388 | while ($flags & GF_MORE) { | ||
1389 | $flags = $this->read_ushort(); | ||
1390 | $glyphIdx = $this->read_ushort(); | ||
1391 | if (!isset($glyphSet[$glyphIdx])) { | ||
1392 | $glyphSet[$glyphIdx] = count($glyphMap); | ||
1393 | $glyphMap[] = $glyphIdx; | ||
1394 | } | ||
1395 | if ($flags & GF_WORDS) | ||
1396 | $this->skip(4); | ||
1397 | else | ||
1398 | $this->skip(2); | ||
1399 | if ($flags & GF_SCALE) | ||
1400 | $this->skip(2); | ||
1401 | else if ($flags & GF_XYSCALE) | ||
1402 | $this->skip(4); | ||
1403 | else if ($flags & GF_TWOBYTWO) | ||
1404 | $this->skip(8); | ||
1405 | } | ||
1406 | } | ||
1407 | } | ||
1408 | |||
1409 | $numGlyphs = $n = count($glyphMap); | ||
1410 | $numberOfHMetrics = $n; | ||
1411 | |||
1412 | /////////////////////////////////// | ||
1413 | // name | ||
1414 | /////////////////////////////////// | ||
1415 | // Needs to have a name entry in 3,0 (e.g. symbol) - original font will be 3,1 (i.e. Unicode) | ||
1416 | $name = $this->get_table('name'); | ||
1417 | $name_offset = $this->seek_table("name"); | ||
1418 | $format = $this->read_ushort(); | ||
1419 | $numRecords = $this->read_ushort(); | ||
1420 | $string_data_offset = $name_offset + $this->read_ushort(); | ||
1421 | for ($i=0;$i<$numRecords; $i++) { | ||
1422 | $platformId = $this->read_ushort(); | ||
1423 | $encodingId = $this->read_ushort(); | ||
1424 | if ($platformId == 3 && $encodingId == 1) { | ||
1425 | $pos = 6 + ($i * 12) + 2; | ||
1426 | $name = $this->_set_ushort($name, $pos, 0x00); // Change encoding to 3,0 rather than 3,1 | ||
1427 | } | ||
1428 | $this->skip(8); | ||
1429 | } | ||
1430 | $this->add('name', $name); | ||
1431 | |||
1432 | /////////////////////////////////// | ||
1433 | // OS/2 | ||
1434 | /////////////////////////////////// | ||
1435 | if (isset($this->tables['OS/2'])) { | ||
1436 | $os2 = $this->get_table('OS/2'); | ||
1437 | $os2 = $this->_set_ushort($os2, 42, 0x00); // ulCharRange (Unicode ranges) | ||
1438 | $os2 = $this->_set_ushort($os2, 44, 0x00); // ulCharRange (Unicode ranges) | ||
1439 | $os2 = $this->_set_ushort($os2, 46, 0x00); // ulCharRange (Unicode ranges) | ||
1440 | $os2 = $this->_set_ushort($os2, 48, 0x00); // ulCharRange (Unicode ranges) | ||
1441 | |||
1442 | $os2 = $this->_set_ushort($os2, 50, 0x00); // ulCharRange (Unicode ranges) | ||
1443 | $os2 = $this->_set_ushort($os2, 52, 0x00); // ulCharRange (Unicode ranges) | ||
1444 | $os2 = $this->_set_ushort($os2, 54, 0x00); // ulCharRange (Unicode ranges) | ||
1445 | $os2 = $this->_set_ushort($os2, 56, 0x00); // ulCharRange (Unicode ranges) | ||
1446 | // Set Symbol character only in ulCodePageRange | ||
1447 | $os2 = $this->_set_ushort($os2, 78, 0x8000); // ulCodePageRange = Bit #31 Symbol **** 78 = Bit 16-31 | ||
1448 | $os2 = $this->_set_ushort($os2, 80, 0x0000); // ulCodePageRange = Bit #31 Symbol **** 80 = Bit 0-15 | ||
1449 | $os2 = $this->_set_ushort($os2, 82, 0x0000); // ulCodePageRange = Bit #32- Symbol **** 82 = Bits 48-63 | ||
1450 | $os2 = $this->_set_ushort($os2, 84, 0x0000); // ulCodePageRange = Bit #32- Symbol **** 84 = Bits 32-47 | ||
1451 | |||
1452 | $os2 = $this->_set_ushort($os2, 64, 0x01); // FirstCharIndex | ||
1453 | $os2 = $this->_set_ushort($os2, 66, count($subset)); // LastCharIndex | ||
1454 | // Set PANOSE first bit to 5 for Symbol | ||
1455 | $os2 = $this->splice($os2, 32, chr(5).chr(0).chr(1).chr(0).chr(1).chr(0).chr(0).chr(0).chr(0).chr(0)); | ||
1456 | $this->add('OS/2', $os2 ); | ||
1457 | } | ||
1458 | |||
1459 | |||
1460 | /////////////////////////////////// | ||
1461 | //tables copied from the original | ||
1462 | /////////////////////////////////// | ||
1463 | $tags = array ('cvt ', 'fpgm', 'prep', 'gasp'); | ||
1464 | foreach($tags AS $tag) { // 1.02 | ||
1465 | if (isset($this->tables[$tag])) { $this->add($tag, $this->get_table($tag)); } | ||
1466 | } | ||
1467 | |||
1468 | /////////////////////////////////// | ||
1469 | // post - PostScript | ||
1470 | /////////////////////////////////// | ||
1471 | if (isset($this->tables['post'])) { | ||
1472 | $opost = $this->get_table('post'); | ||
1473 | $post = "\x00\x03\x00\x00" . substr($opost,4,12) . "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; | ||
1474 | } | ||
1475 | $this->add('post', $post); | ||
1476 | |||
1477 | /////////////////////////////////// | ||
1478 | // hhea - Horizontal Header | ||
1479 | /////////////////////////////////// | ||
1480 | $hhea = $this->get_table('hhea'); | ||
1481 | $hhea = $this->_set_ushort($hhea, 34, $numberOfHMetrics); | ||
1482 | $this->add('hhea', $hhea); | ||
1483 | |||
1484 | /////////////////////////////////// | ||
1485 | // maxp - Maximum Profile | ||
1486 | /////////////////////////////////// | ||
1487 | $maxp = $this->get_table('maxp'); | ||
1488 | $maxp = $this->_set_ushort($maxp, 4, $numGlyphs); | ||
1489 | $this->add('maxp', $maxp); | ||
1490 | |||
1491 | |||
1492 | /////////////////////////////////// | ||
1493 | // CMap table Formats [1,0,]6 and [3,0,]4 | ||
1494 | /////////////////////////////////// | ||
1495 | /////////////////////////////////// | ||
1496 | // Sort CID2GID map into segments of contiguous codes | ||
1497 | /////////////////////////////////// | ||
1498 | $rangeid = 0; | ||
1499 | $range = array(); | ||
1500 | $prevcid = -2; | ||
1501 | $prevglidx = -1; | ||
1502 | // for each character | ||
1503 | foreach ($subset as $cid => $code) { | ||
1504 | $glidx = $codeToGlyph[$code]; | ||
1505 | if ($cid == ($prevcid + 1) && $glidx == ($prevglidx + 1)) { | ||
1506 | $range[$rangeid][] = $glidx; | ||
1507 | } else { | ||
1508 | // new range | ||
1509 | $rangeid = $cid; | ||
1510 | $range[$rangeid] = array(); | ||
1511 | $range[$rangeid][] = $glidx; | ||
1512 | } | ||
1513 | $prevcid = $cid; | ||
1514 | $prevglidx = $glidx; | ||
1515 | } | ||
1516 | // cmap - Character to glyph mapping | ||
1517 | $segCount = count($range) + 1; // + 1 Last segment has missing character 0xFFFF | ||
1518 | $searchRange = 1; | ||
1519 | $entrySelector = 0; | ||
1520 | while ($searchRange * 2 <= $segCount ) { | ||
1521 | $searchRange = $searchRange * 2; | ||
1522 | $entrySelector = $entrySelector + 1; | ||
1523 | } | ||
1524 | $searchRange = $searchRange * 2; | ||
1525 | $rangeShift = $segCount * 2 - $searchRange; | ||
1526 | $length = 16 + (8*$segCount ) + ($numGlyphs+1); | ||
1527 | $cmap = array( | ||
1528 | 4, $length, 0, // Format 4 Mapping subtable: format, length, language | ||
1529 | $segCount*2, | ||
1530 | $searchRange, | ||
1531 | $entrySelector, | ||
1532 | $rangeShift); | ||
1533 | |||
1534 | // endCode(s) | ||
1535 | foreach($range AS $start=>$subrange) { | ||
1536 | $endCode = $start + (count($subrange)-1); | ||
1537 | $cmap[] = $endCode; // endCode(s) | ||
1538 | } | ||
1539 | $cmap[] = 0xFFFF; // endCode of last Segment | ||
1540 | $cmap[] = 0; // reservedPad | ||
1541 | |||
1542 | // startCode(s) | ||
1543 | foreach($range AS $start=>$subrange) { | ||
1544 | $cmap[] = $start; // startCode(s) | ||
1545 | } | ||
1546 | $cmap[] = 0xFFFF; // startCode of last Segment | ||
1547 | // idDelta(s) | ||
1548 | foreach($range AS $start=>$subrange) { | ||
1549 | $idDelta = -($start-$subrange[0]); | ||
1550 | $n += count($subrange); | ||
1551 | $cmap[] = $idDelta; // idDelta(s) | ||
1552 | } | ||
1553 | $cmap[] = 1; // idDelta of last Segment | ||
1554 | // idRangeOffset(s) | ||
1555 | foreach($range AS $subrange) { | ||
1556 | $cmap[] = 0; // idRangeOffset[segCount] Offset in bytes to glyph indexArray, or 0 | ||
1557 | |||
1558 | } | ||
1559 | $cmap[] = 0; // idRangeOffset of last Segment | ||
1560 | foreach($range AS $subrange) { | ||
1561 | foreach($subrange AS $glidx) { | ||
1562 | $cmap[] = $glidx; | ||
1563 | } | ||
1564 | } | ||
1565 | $cmap[] = 0; // Mapping for last character | ||
1566 | $cmapstr4 = ''; | ||
1567 | foreach($cmap AS $cm) { $cmapstr4 .= pack("n",$cm); } | ||
1568 | |||
1569 | /////////////////////////////////// | ||
1570 | // cmap - Character to glyph mapping | ||
1571 | /////////////////////////////////// | ||
1572 | $entryCount = count($subset); | ||
1573 | $length = 10 + $entryCount * 2; | ||
1574 | |||
1575 | $off = 20 + $length; | ||
1576 | $hoff = $off >> 16; | ||
1577 | $loff = $off & 0xFFFF; | ||
1578 | |||
1579 | $cmap = array(0, 2, // Index : version, number of subtables | ||
1580 | 1, 0, // Subtable : platform, encoding | ||
1581 | 0, 20, // offset (hi,lo) | ||
1582 | 3, 0, // Subtable : platform, encoding | ||
1583 | $hoff, $loff, // offset (hi,lo) | ||
1584 | 6, $length, // Format 6 Mapping table: format, length | ||
1585 | 0, 1, // language, First char code | ||
1586 | $entryCount | ||
1587 | ); | ||
1588 | $cmapstr = ''; | ||
1589 | foreach($subset AS $code) { $cmap[] = $codeToGlyph[$code]; } | ||
1590 | foreach($cmap AS $cm) { $cmapstr .= pack("n",$cm); } | ||
1591 | $cmapstr .= $cmapstr4; | ||
1592 | $this->add('cmap', $cmapstr); | ||
1593 | |||
1594 | /////////////////////////////////// | ||
1595 | // hmtx - Horizontal Metrics | ||
1596 | /////////////////////////////////// | ||
1597 | $hmtxstr = ''; | ||
1598 | for($n=0;$n<$numGlyphs;$n++) { | ||
1599 | $originalGlyphIdx = $glyphMap[$n]; | ||
1600 | $hm = $this->getHMetric($orignHmetrics, $originalGlyphIdx); | ||
1601 | $hmtxstr .= $hm; | ||
1602 | } | ||
1603 | $this->add('hmtx', $hmtxstr); | ||
1604 | |||
1605 | /////////////////////////////////// | ||
1606 | // glyf - Glyph data | ||
1607 | /////////////////////////////////// | ||
1608 | list($glyfOffset,$glyfLength) = $this->get_table_pos('glyf'); | ||
1609 | if ($glyfLength < $this->maxStrLenRead) { | ||
1610 | $glyphData = $this->get_table('glyf'); | ||
1611 | } | ||
1612 | |||
1613 | $offsets = array(); | ||
1614 | $glyf = ''; | ||
1615 | $pos = 0; | ||
1616 | for ($n=0;$n<$numGlyphs;$n++) { | ||
1617 | $offsets[] = $pos; | ||
1618 | $originalGlyphIdx = $glyphMap[$n]; | ||
1619 | $glyphPos = $this->glyphPos[$originalGlyphIdx]; | ||
1620 | $glyphLen = $this->glyphPos[$originalGlyphIdx + 1] - $glyphPos; | ||
1621 | if ($glyfLength < $this->maxStrLenRead) { | ||
1622 | $data = substr($glyphData,$glyphPos,$glyphLen); | ||
1623 | } | ||
1624 | else { | ||
1625 | if ($glyphLen > 0) $data = $this->get_chunk($glyfOffset+$glyphPos,$glyphLen); | ||
1626 | else $data = ''; | ||
1627 | } | ||
1628 | if ($glyphLen > 0) $up = unpack("n", substr($data,0,2)); | ||
1629 | if ($glyphLen > 2 && ($up[1] & (1 << 15)) ) { | ||
1630 | $pos_in_glyph = 10; | ||
1631 | $flags = GF_MORE; | ||
1632 | while ($flags & GF_MORE) { | ||
1633 | $up = unpack("n", substr($data,$pos_in_glyph,2)); | ||
1634 | $flags = $up[1]; | ||
1635 | $up = unpack("n", substr($data,$pos_in_glyph+2,2)); | ||
1636 | $glyphIdx = $up[1]; | ||
1637 | $data = $this->_set_ushort($data, $pos_in_glyph + 2, $glyphSet[$glyphIdx]); | ||
1638 | $pos_in_glyph += 4; | ||
1639 | if ($flags & GF_WORDS) { $pos_in_glyph += 4; } | ||
1640 | else { $pos_in_glyph += 2; } | ||
1641 | if ($flags & GF_SCALE) { $pos_in_glyph += 2; } | ||
1642 | else if ($flags & GF_XYSCALE) { $pos_in_glyph += 4; } | ||
1643 | else if ($flags & GF_TWOBYTWO) { $pos_in_glyph += 8; } | ||
1644 | } | ||
1645 | } | ||
1646 | $glyf .= $data; | ||
1647 | $pos += $glyphLen; | ||
1648 | if ($pos % 4 != 0) { | ||
1649 | $padding = 4 - ($pos % 4); | ||
1650 | $glyf .= str_repeat("\0",$padding); | ||
1651 | $pos += $padding; | ||
1652 | } | ||
1653 | } | ||
1654 | $offsets[] = $pos; | ||
1655 | $this->add('glyf', $glyf); | ||
1656 | |||
1657 | /////////////////////////////////// | ||
1658 | // loca - Index to location | ||
1659 | /////////////////////////////////// | ||
1660 | $locastr = ''; | ||
1661 | if ((($pos + 1) >> 1) > 0xFFFF) { | ||
1662 | $indexToLocFormat = 1; // long format | ||
1663 | foreach($offsets AS $offset) { $locastr .= pack("N",$offset); } | ||
1664 | } | ||
1665 | else { | ||
1666 | $indexToLocFormat = 0; // short format | ||
1667 | foreach($offsets AS $offset) { $locastr .= pack("n",($offset/2)); } | ||
1668 | } | ||
1669 | $this->add('loca', $locastr); | ||
1670 | |||
1671 | /////////////////////////////////// | ||
1672 | // head - Font header | ||
1673 | /////////////////////////////////// | ||
1674 | $head = $this->get_table('head'); | ||
1675 | $head = $this->_set_ushort($head, 50, $indexToLocFormat); | ||
1676 | $this->add('head', $head); | ||
1677 | |||
1678 | fclose($this->fh); | ||
1679 | |||
1680 | // Put the TTF file together | ||
1681 | $stm = ''; | ||
1682 | $this->endTTFile($stm); | ||
1683 | //file_put_contents('testfont.ttf', $stm); exit; | ||
1684 | return $stm ; | ||
1685 | } | ||
1686 | |||
1687 | ////////////////////////////////////////////////////////////////////////////////// | ||
1688 | // Recursively get composite glyph data | ||
1689 | function getGlyphData($originalGlyphIdx, &$maxdepth, &$depth, &$points, &$contours) { | ||
1690 | $depth++; | ||
1691 | $maxdepth = max($maxdepth, $depth); | ||
1692 | if (count($this->glyphdata[$originalGlyphIdx]['compGlyphs'])) { | ||
1693 | foreach($this->glyphdata[$originalGlyphIdx]['compGlyphs'] AS $glyphIdx) { | ||
1694 | $this->getGlyphData($glyphIdx, $maxdepth, $depth, $points, $contours); | ||
1695 | } | ||
1696 | } | ||
1697 | else if (($this->glyphdata[$originalGlyphIdx]['nContours'] > 0) && $depth > 0) { // simple | ||
1698 | $contours += $this->glyphdata[$originalGlyphIdx]['nContours']; | ||
1699 | $points += $this->glyphdata[$originalGlyphIdx]['nPoints']; | ||
1700 | } | ||
1701 | $depth--; | ||
1702 | } | ||
1703 | |||
1704 | |||
1705 | ////////////////////////////////////////////////////////////////////////////////// | ||
1706 | // Recursively get composite glyphs | ||
1707 | function getGlyphs($originalGlyphIdx, &$start, &$glyphSet, &$subsetglyphs) { | ||
1708 | $glyphPos = $this->glyphPos[$originalGlyphIdx]; | ||
1709 | $glyphLen = $this->glyphPos[$originalGlyphIdx + 1] - $glyphPos; | ||
1710 | if (!$glyphLen) { | ||
1711 | return; | ||
1712 | } | ||
1713 | $this->seek($start + $glyphPos); | ||
1714 | $numberOfContours = $this->read_short(); | ||
1715 | if ($numberOfContours < 0) { | ||
1716 | $this->skip(8); | ||
1717 | $flags = GF_MORE; | ||
1718 | while ($flags & GF_MORE) { | ||
1719 | $flags = $this->read_ushort(); | ||
1720 | $glyphIdx = $this->read_ushort(); | ||
1721 | if (!isset($glyphSet[$glyphIdx])) { | ||
1722 | $glyphSet[$glyphIdx] = count($subsetglyphs); // old glyphID to new glyphID | ||
1723 | $subsetglyphs[$glyphIdx] = true; | ||
1724 | } | ||
1725 | $savepos = ftell($this->fh); | ||
1726 | $this->getGlyphs($glyphIdx, $start, $glyphSet, $subsetglyphs); | ||
1727 | $this->seek($savepos); | ||
1728 | if ($flags & GF_WORDS) | ||
1729 | $this->skip(4); | ||
1730 | else | ||
1731 | $this->skip(2); | ||
1732 | if ($flags & GF_SCALE) | ||
1733 | $this->skip(2); | ||
1734 | else if ($flags & GF_XYSCALE) | ||
1735 | $this->skip(4); | ||
1736 | else if ($flags & GF_TWOBYTWO) | ||
1737 | $this->skip(8); | ||
1738 | } | ||
1739 | } | ||
1740 | } | ||
1741 | |||
1742 | ////////////////////////////////////////////////////////////////////////////////// | ||
1743 | |||
1744 | function getHMTX($numberOfHMetrics, $numGlyphs, &$glyphToChar, $scale) { | ||
1745 | $start = $this->seek_table("hmtx"); | ||
1746 | $aw = 0; | ||
1747 | $this->charWidths = str_pad('', 256*256*2, "\x00"); | ||
1748 | if ($this->maxUniChar > 65536) { $this->charWidths .= str_pad('', 256*256*2, "\x00"); } // Plane 1 SMP | ||
1749 | if ($this->maxUniChar > 131072) { $this->charWidths .= str_pad('', 256*256*2, "\x00"); } // Plane 2 SMP | ||
1750 | $nCharWidths = 0; | ||
1751 | if (($numberOfHMetrics*4) < $this->maxStrLenRead) { | ||
1752 | $data = $this->get_chunk($start,($numberOfHMetrics*4)); | ||
1753 | $arr = unpack("n*", $data); | ||
1754 | } | ||
1755 | else { $this->seek($start); } | ||
1756 | for( $glyph=0; $glyph<$numberOfHMetrics; $glyph++) { | ||
1757 | if (($numberOfHMetrics*4) < $this->maxStrLenRead) { | ||
1758 | $aw = $arr[($glyph*2)+1]; | ||
1759 | } | ||
1760 | else { | ||
1761 | $aw = $this->read_ushort(); | ||
1762 | $lsb = $this->read_ushort(); | ||
1763 | } | ||
1764 | if (isset($glyphToChar[$glyph]) || $glyph == 0) { | ||
1765 | |||
1766 | if ($aw >= (1 << 15) ) { $aw = 0; } // 1.03 Some (arabic) fonts have -ve values for width | ||
1767 | // although should be unsigned value - comes out as e.g. 65108 (intended -50) | ||
1768 | if ($glyph == 0) { | ||
1769 | $this->defaultWidth = $scale*$aw; | ||
1770 | continue; | ||
1771 | } | ||
1772 | foreach($glyphToChar[$glyph] AS $char) { | ||
1773 | //$this->charWidths[$char] = intval(round($scale*$aw)); | ||
1774 | if ($char != 0 && $char != 65535) { | ||
1775 | $w = intval(round($scale*$aw)); | ||
1776 | if ($w == 0) { $w = 65535; } | ||
1777 | if ($char < 196608) { | ||
1778 | $this->charWidths[$char*2] = chr($w >> 8); | ||
1779 | $this->charWidths[$char*2 + 1] = chr($w & 0xFF); | ||
1780 | $nCharWidths++; | ||
1781 | } | ||
1782 | } | ||
1783 | } | ||
1784 | } | ||
1785 | } | ||
1786 | $data = $this->get_chunk(($start+$numberOfHMetrics*4),($numGlyphs*2)); | ||
1787 | $arr = unpack("n*", $data); | ||
1788 | $diff = $numGlyphs-$numberOfHMetrics; | ||
1789 | $w = intval(round($scale*$aw)); | ||
1790 | if ($w == 0) { $w = 65535; } | ||
1791 | for( $pos=0; $pos<$diff; $pos++) { | ||
1792 | $glyph = $pos + $numberOfHMetrics; | ||
1793 | if (isset($glyphToChar[$glyph])) { | ||
1794 | foreach($glyphToChar[$glyph] AS $char) { | ||
1795 | if ($char != 0 && $char != 65535) { | ||
1796 | if ($char < 196608) { | ||
1797 | $this->charWidths[$char*2] = chr($w >> 8); | ||
1798 | $this->charWidths[$char*2 + 1] = chr($w & 0xFF); | ||
1799 | $nCharWidths++; | ||
1800 | } | ||
1801 | } | ||
1802 | } | ||
1803 | } | ||
1804 | } | ||
1805 | // NB 65535 is a set width of 0 | ||
1806 | // First bytes define number of chars in font | ||
1807 | $this->charWidths[0] = chr($nCharWidths >> 8); | ||
1808 | $this->charWidths[1] = chr($nCharWidths & 0xFF); | ||
1809 | } | ||
1810 | |||
1811 | function getHMetric($numberOfHMetrics, $gid) { | ||
1812 | $start = $this->seek_table("hmtx"); | ||
1813 | if ($gid < $numberOfHMetrics) { | ||
1814 | $this->seek($start+($gid*4)); | ||
1815 | $hm = fread($this->fh,4); | ||
1816 | } | ||
1817 | else { | ||
1818 | $this->seek($start+(($numberOfHMetrics-1)*4)); | ||
1819 | $hm = fread($this->fh,2); | ||
1820 | $this->seek($start+($numberOfHMetrics*2)+($gid*2)); | ||
1821 | $hm .= fread($this->fh,2); | ||
1822 | } | ||
1823 | return $hm; | ||
1824 | } | ||
1825 | |||
1826 | function getLOCA($indexToLocFormat, $numGlyphs) { | ||
1827 | $start = $this->seek_table('loca'); | ||
1828 | $this->glyphPos = array(); | ||
1829 | if ($indexToLocFormat == 0) { | ||
1830 | $data = $this->get_chunk($start,($numGlyphs*2)+2); | ||
1831 | $arr = unpack("n*", $data); | ||
1832 | for ($n=0; $n<=$numGlyphs; $n++) { | ||
1833 | $this->glyphPos[] = ($arr[$n+1] * 2); | ||
1834 | } | ||
1835 | } | ||
1836 | else if ($indexToLocFormat == 1) { | ||
1837 | $data = $this->get_chunk($start,($numGlyphs*4)+4); | ||
1838 | $arr = unpack("N*", $data); | ||
1839 | for ($n=0; $n<=$numGlyphs; $n++) { | ||
1840 | $this->glyphPos[] = ($arr[$n+1]); | ||
1841 | } | ||
1842 | } | ||
1843 | else | ||
1844 | die('Unknown location table format '.$indexToLocFormat); | ||
1845 | } | ||
1846 | |||
1847 | |||
1848 | // CMAP Format 4 | ||
1849 | function getCMAP4($unicode_cmap_offset, &$glyphToChar, &$charToGlyph ) { | ||
1850 | $this->maxUniChar = 0; | ||
1851 | $this->seek($unicode_cmap_offset + 2); | ||
1852 | $length = $this->read_ushort(); | ||
1853 | $limit = $unicode_cmap_offset + $length; | ||
1854 | $this->skip(2); | ||
1855 | |||
1856 | $segCount = $this->read_ushort() / 2; | ||
1857 | $this->skip(6); | ||
1858 | $endCount = array(); | ||
1859 | for($i=0; $i<$segCount; $i++) { $endCount[] = $this->read_ushort(); } | ||
1860 | $this->skip(2); | ||
1861 | $startCount = array(); | ||
1862 | for($i=0; $i<$segCount; $i++) { $startCount[] = $this->read_ushort(); } | ||
1863 | $idDelta = array(); | ||
1864 | for($i=0; $i<$segCount; $i++) { $idDelta[] = $this->read_short(); } // ???? was unsigned short | ||
1865 | $idRangeOffset_start = $this->_pos; | ||
1866 | $idRangeOffset = array(); | ||
1867 | for($i=0; $i<$segCount; $i++) { $idRangeOffset[] = $this->read_ushort(); } | ||
1868 | |||
1869 | for ($n=0;$n<$segCount;$n++) { | ||
1870 | $endpoint = ($endCount[$n] + 1); | ||
1871 | for ($unichar=$startCount[$n];$unichar<$endpoint;$unichar++) { | ||
1872 | if ($idRangeOffset[$n] == 0) | ||
1873 | $glyph = ($unichar + $idDelta[$n]) & 0xFFFF; | ||
1874 | else { | ||
1875 | $offset = ($unichar - $startCount[$n]) * 2 + $idRangeOffset[$n]; | ||
1876 | $offset = $idRangeOffset_start + 2 * $n + $offset; | ||
1877 | if ($offset >= $limit) | ||
1878 | $glyph = 0; | ||
1879 | else { | ||
1880 | $glyph = $this->get_ushort($offset); | ||
1881 | if ($glyph != 0) | ||
1882 | $glyph = ($glyph + $idDelta[$n]) & 0xFFFF; | ||
1883 | } | ||
1884 | } | ||
1885 | $charToGlyph[$unichar] = $glyph; | ||
1886 | if ($unichar < 196608) { $this->maxUniChar = max($unichar,$this->maxUniChar); } | ||
1887 | $glyphToChar[$glyph][] = $unichar; | ||
1888 | } | ||
1889 | } | ||
1890 | |||
1891 | // mPDF 5.4.05 | ||
1892 | if ($this->unAGlyphs) { | ||
1893 | if (isset($this->tables['post'])) { | ||
1894 | $this->seek_table("post"); | ||
1895 | $formata = $this->read_ushort(); | ||
1896 | $formatb = $this->read_ushort(); | ||
1897 | // Only works on Format 2.0 | ||
1898 | if ($formata != 2 || $formatb != 0) { die("Cannot set unAGlyphs for this font (".$file."). POST table must be in Format 2."); } | ||
1899 | $this->skip(28); | ||
1900 | $nGlyfs = $this->read_ushort(); | ||
1901 | $glyphNameIndex = array(); | ||
1902 | for ($i=0; $i<$nGlyfs; $i++) { | ||
1903 | $glyphNameIndex[($this->read_ushort())] = $i; | ||
1904 | } | ||
1905 | |||
1906 | $opost = $this->get_table('post'); | ||
1907 | $ptr = 34+($nGlyfs*2); | ||
1908 | for ($i=0; $i<$nGlyfs; $i++) { | ||
1909 | $len = ord(substr($opost,$ptr,1)); | ||
1910 | $ptr++; | ||
1911 | $name = substr($opost,$ptr,$len); | ||
1912 | $gid = $glyphNameIndex[$i+258]; | ||
1913 | // Select uni0600.xxx(x) - uni06FF.xxx(x) | ||
1914 | if (preg_match('/^uni(06[0-9a-f]{2})\.(fina|medi|init|fin|med|ini)$/i',$name,$m)) { | ||
1915 | if (!isset($glyphToChar[$gid]) || (isset($glyphToChar[$gid]) && is_array($glyphToChar[$gid]) && count($glyphToChar[$gid])==1 && $glyphToChar[$gid][0]>57343 && $glyphToChar[$gid][0]<63489)) { // if set in PUA private use area E000-F8FF, or NOT Unicode mapped | ||
1916 | $uni = hexdec($m[1]); | ||
1917 | $form = strtoupper(substr($m[2],0,1)); | ||
1918 | // Assign new PUA Unicode between F500 - F7FF | ||
1919 | $bit = $uni & 0xFF; | ||
1920 | if ($form == 'I') { $bit += 0xF600; } | ||
1921 | else if ($form == 'M') { $bit += 0xF700; } | ||
1922 | else { $bit += 0xF500; } | ||
1923 | // ADD TO CMAP | ||
1924 | $glyphToChar[$gid][] = $bit; | ||
1925 | $charToGlyph[$bit] = $gid; | ||
1926 | } | ||
1927 | } | ||
1928 | // LAM with ALEF ligatures (Mandatory ligatures) | ||
1929 | else if (preg_match('/^uni064406(22|23|25|27)(\.fina|\.fin){0,1}$/i',$name,$m)) { | ||
1930 | if ($m[1]=='22') { | ||
1931 | if ($m[2]) { $uni = hexdec('FEF6'); } else { $uni = hexdec('FEF5'); } | ||
1932 | } | ||
1933 | else if ($m[1]=='23') { | ||
1934 | if ($m[2]) { $uni = hexdec('FEF8'); } else { $uni = hexdec('FEF7'); } | ||
1935 | } | ||
1936 | else if ($m[1]=='25') { | ||
1937 | if ($m[2]) { $uni = hexdec('FEFA'); } else { $uni = hexdec('FEF9'); } | ||
1938 | } | ||
1939 | else if ($m[1]=='27') { | ||
1940 | if ($m[2]) { $uni = hexdec('FEFC'); } else { $uni = hexdec('FEFB'); } | ||
1941 | } | ||
1942 | if (!isset($glyphToChar[$gid]) || (isset($glyphToChar[$gid]) && is_array($glyphToChar[$gid]) && count($glyphToChar[$gid])==1 && $glyphToChar[$gid][0]>57343 && $glyphToChar[$gid][0]<63489)) { // if set in PUA private use area E000-F8FF, or NOT Unicode mapped | ||
1943 | // ADD TO CMAP | ||
1944 | $glyphToChar[$gid][] = $uni; | ||
1945 | $charToGlyph[$uni] = $gid; | ||
1946 | } | ||
1947 | } | ||
1948 | $ptr += $len; | ||
1949 | } | ||
1950 | } | ||
1951 | } | ||
1952 | |||
1953 | } | ||
1954 | |||
1955 | |||
1956 | // Put the TTF file together | ||
1957 | function endTTFile(&$stm) { | ||
1958 | $stm = ''; | ||
1959 | $numTables = count($this->otables); | ||
1960 | $searchRange = 1; | ||
1961 | $entrySelector = 0; | ||
1962 | while ($searchRange * 2 <= $numTables) { | ||
1963 | $searchRange = $searchRange * 2; | ||
1964 | $entrySelector = $entrySelector + 1; | ||
1965 | } | ||
1966 | $searchRange = $searchRange * 16; | ||
1967 | $rangeShift = $numTables * 16 - $searchRange; | ||
1968 | |||
1969 | // Header | ||
1970 | if (_TTF_MAC_HEADER) { | ||
1971 | $stm .= (pack("Nnnnn", 0x74727565, $numTables, $searchRange, $entrySelector, $rangeShift)); // Mac | ||
1972 | } | ||
1973 | else { | ||
1974 | $stm .= (pack("Nnnnn", 0x00010000 , $numTables, $searchRange, $entrySelector, $rangeShift)); // Windows | ||
1975 | } | ||
1976 | |||
1977 | // Table directory | ||
1978 | $tables = $this->otables; | ||
1979 | ksort ($tables); | ||
1980 | $offset = 12 + $numTables * 16; | ||
1981 | foreach ($tables AS $tag=>$data) { | ||
1982 | if ($tag == 'head') { $head_start = $offset; } | ||
1983 | $stm .= $tag; | ||
1984 | $checksum = $this->calcChecksum($data); | ||
1985 | $stm .= pack("nn", $checksum[0],$checksum[1]); | ||
1986 | $stm .= pack("NN", $offset, strlen($data)); | ||
1987 | $paddedLength = (strlen($data)+3)&~3; | ||
1988 | $offset = $offset + $paddedLength; | ||
1989 | } | ||
1990 | |||
1991 | // Table data | ||
1992 | foreach ($tables AS $tag=>$data) { | ||
1993 | $data .= "\0\0\0"; | ||
1994 | $stm .= substr($data,0,(strlen($data)&~3)); | ||
1995 | } | ||
1996 | |||
1997 | $checksum = $this->calcChecksum($stm); | ||
1998 | $checksum = $this->sub32(array(0xB1B0,0xAFBA), $checksum); | ||
1999 | $chk = pack("nn", $checksum[0],$checksum[1]); | ||
2000 | $stm = $this->splice($stm,($head_start + 8),$chk); | ||
2001 | return $stm ; | ||
2002 | } | ||
2003 | |||
2004 | |||
2005 | function repackageTTF($file, $TTCfontID=0, $debug=false, $unAGlyphs=false) { // mPDF 5.4.05 | ||
2006 | $this->unAGlyphs = $unAGlyphs; // mPDF 5.4.05 | ||
2007 | $this->filename = $file; | ||
2008 | $this->fh = fopen($file ,'rb') or die('Can\'t open file ' . $file); | ||
2009 | $this->_pos = 0; | ||
2010 | $this->charWidths = ''; | ||
2011 | $this->glyphPos = array(); | ||
2012 | $this->charToGlyph = array(); | ||
2013 | $this->tables = array(); | ||
2014 | $this->otables = array(); | ||
2015 | $this->ascent = 0; | ||
2016 | $this->descent = 0; | ||
2017 | $this->numTTCFonts = 0; | ||
2018 | $this->TTCFonts = array(); | ||
2019 | $this->skip(4); | ||
2020 | $this->maxUni = 0; | ||
2021 | if ($TTCfontID > 0) { | ||
2022 | $this->version = $version = $this->read_ulong(); // TTC Header version now | ||
2023 | if (!in_array($version, array(0x00010000,0x00020000))) | ||
2024 | die("ERROR - Error parsing TrueType Collection: version=".$version." - " . $file); | ||
2025 | $this->numTTCFonts = $this->read_ulong(); | ||
2026 | for ($i=1; $i<=$this->numTTCFonts; $i++) { | ||
2027 | $this->TTCFonts[$i]['offset'] = $this->read_ulong(); | ||
2028 | } | ||
2029 | $this->seek($this->TTCFonts[$TTCfontID]['offset']); | ||
2030 | $this->version = $version = $this->read_ulong(); // TTFont version again now | ||
2031 | } | ||
2032 | $this->readTableDirectory($debug); | ||
2033 | $tags = array ('OS/2', 'cmap', 'glyf', 'head', 'hhea', 'hmtx', 'loca', 'maxp', 'name', 'post', 'cvt ', 'fpgm', 'gasp', 'prep'); | ||
2034 | /* | ||
2035 | Tables which require glyphIndex | ||
2036 | hdmx | ||
2037 | kern | ||
2038 | LTSH | ||
2039 | |||
2040 | Tables which do NOT require glyphIndex | ||
2041 | VDMX | ||
2042 | |||
2043 | GDEF | ||
2044 | GPOS | ||
2045 | GSUB | ||
2046 | JSTF | ||
2047 | |||
2048 | DSIG | ||
2049 | PCLT - not recommended | ||
2050 | */ | ||
2051 | |||
2052 | foreach($tags AS $tag) { | ||
2053 | if (isset($this->tables[$tag])) { $this->add($tag, $this->get_table($tag)); } | ||
2054 | } | ||
2055 | fclose($this->fh); | ||
2056 | $stm = ''; | ||
2057 | $this->endTTFile($stm); | ||
2058 | return $stm ; | ||
2059 | } | ||
2060 | |||
2061 | |||
2062 | } | ||
2063 | |||
2064 | |||
2065 | ?> \ No newline at end of file | ||
diff --git a/inc/3rdparty/libraries/mpdf/classes/ttfontsuni_analysis.php b/inc/3rdparty/libraries/mpdf/classes/ttfontsuni_analysis.php new file mode 100644 index 00000000..3f2cccef --- /dev/null +++ b/inc/3rdparty/libraries/mpdf/classes/ttfontsuni_analysis.php | |||
@@ -0,0 +1,463 @@ | |||
1 | <?php | ||
2 | |||
3 | require_once(_MPDF_PATH.'classes/ttfontsuni.php'); | ||
4 | |||
5 | class TTFontFile_Analysis EXTENDS TTFontFile { | ||
6 | |||
7 | // Used to get font information from files in directory | ||
8 | function extractCoreInfo($file, $TTCfontID=0) { | ||
9 | $this->filename = $file; | ||
10 | $this->fh = fopen($file,'rb'); | ||
11 | if (!$this->fh) { return ('ERROR - Can\'t open file ' . $file); } | ||
12 | $this->_pos = 0; | ||
13 | $this->charWidths = ''; | ||
14 | $this->glyphPos = array(); | ||
15 | $this->charToGlyph = array(); | ||
16 | $this->tables = array(); | ||
17 | $this->otables = array(); | ||
18 | $this->ascent = 0; | ||
19 | $this->descent = 0; | ||
20 | $this->numTTCFonts = 0; | ||
21 | $this->TTCFonts = array(); | ||
22 | $this->version = $version = $this->read_ulong(); | ||
23 | $this->panose = array(); // mPDF 5.0 | ||
24 | if ($version==0x4F54544F) | ||
25 | return("ERROR - NOT ADDED as Postscript outlines are not supported - " . $file); | ||
26 | if ($version==0x74746366) { | ||
27 | if ($TTCfontID > 0) { | ||
28 | $this->version = $version = $this->read_ulong(); // TTC Header version now | ||
29 | if (!in_array($version, array(0x00010000,0x00020000))) | ||
30 | return("ERROR - NOT ADDED as Error parsing TrueType Collection: version=".$version." - " . $file); | ||
31 | } | ||
32 | else return("ERROR - Error parsing TrueType Collection - " . $file); | ||
33 | $this->numTTCFonts = $this->read_ulong(); | ||
34 | for ($i=1; $i<=$this->numTTCFonts; $i++) { | ||
35 | $this->TTCFonts[$i]['offset'] = $this->read_ulong(); | ||
36 | } | ||
37 | $this->seek($this->TTCFonts[$TTCfontID]['offset']); | ||
38 | $this->version = $version = $this->read_ulong(); // TTFont version again now | ||
39 | $this->readTableDirectory(false); | ||
40 | } | ||
41 | else { | ||
42 | if (!in_array($version, array(0x00010000,0x74727565))) | ||
43 | return("ERROR - NOT ADDED as Not a TrueType font: version=".$version." - " . $file); | ||
44 | $this->readTableDirectory(false); | ||
45 | } | ||
46 | |||
47 | /* Included for testing... | ||
48 | $cmap_offset = $this->seek_table("cmap"); | ||
49 | $this->skip(2); | ||
50 | $cmapTableCount = $this->read_ushort(); | ||
51 | $unicode_cmap_offset = 0; | ||
52 | for ($i=0;$i<$cmapTableCount;$i++) { | ||
53 | $x[$i]['platformId'] = $this->read_ushort(); | ||
54 | $x[$i]['encodingId'] = $this->read_ushort(); | ||
55 | $x[$i]['offset'] = $this->read_ulong(); | ||
56 | $save_pos = $this->_pos; | ||
57 | $x[$i]['format'] = $this->get_ushort($cmap_offset + $x[$i]['offset'] ); | ||
58 | $this->seek($save_pos ); | ||
59 | } | ||
60 | print_r($x); exit; | ||
61 | */ | ||
62 | /////////////////////////////////// | ||
63 | // name - Naming table | ||
64 | /////////////////////////////////// | ||
65 | |||
66 | /* Test purposes - displays table of names | ||
67 | $name_offset = $this->seek_table("name"); | ||
68 | $format = $this->read_ushort(); | ||
69 | if ($format != 0 && $format != 1) // mPDF 5.3.73 | ||
70 | die("Unknown name table format ".$format); | ||
71 | $numRecords = $this->read_ushort(); | ||
72 | $string_data_offset = $name_offset + $this->read_ushort(); | ||
73 | for ($i=0;$i<$numRecords; $i++) { | ||
74 | $x[$i]['platformId'] = $this->read_ushort(); | ||
75 | $x[$i]['encodingId'] = $this->read_ushort(); | ||
76 | $x[$i]['languageId'] = $this->read_ushort(); | ||
77 | $x[$i]['nameId'] = $this->read_ushort(); | ||
78 | $x[$i]['length'] = $this->read_ushort(); | ||
79 | $x[$i]['offset'] = $this->read_ushort(); | ||
80 | |||
81 | $N = ''; | ||
82 | if ($x[$i]['platformId'] == 1 && $x[$i]['encodingId'] == 0 && $x[$i]['languageId'] == 0) { // Roman | ||
83 | $opos = $this->_pos; | ||
84 | $N = $this->get_chunk($string_data_offset + $x[$i]['offset'] , $x[$i]['length'] ); | ||
85 | $this->_pos = $opos; | ||
86 | $this->seek($opos); | ||
87 | } | ||
88 | else { // Unicode | ||
89 | $opos = $this->_pos; | ||
90 | $this->seek($string_data_offset + $x[$i]['offset'] ); | ||
91 | $length = $x[$i]['length'] ; | ||
92 | if ($length % 2 != 0) | ||
93 | $length -= 1; | ||
94 | // die("PostScript name is UTF-16BE string of odd length"); | ||
95 | $length /= 2; | ||
96 | $N = ''; | ||
97 | while ($length > 0) { | ||
98 | $char = $this->read_ushort(); | ||
99 | $N .= (chr($char)); | ||
100 | $length -= 1; | ||
101 | } | ||
102 | $this->_pos = $opos; | ||
103 | $this->seek($opos); | ||
104 | } | ||
105 | $x[$i]['names'][$nameId] = $N; | ||
106 | } | ||
107 | print_r($x); exit; | ||
108 | */ | ||
109 | |||
110 | $name_offset = $this->seek_table("name"); | ||
111 | $format = $this->read_ushort(); | ||
112 | if ($format != 0 && $format != 1) // mPDF 5.3.73 | ||
113 | return("ERROR - NOT ADDED as Unknown name table format ".$format." - " . $file); | ||
114 | $numRecords = $this->read_ushort(); | ||
115 | $string_data_offset = $name_offset + $this->read_ushort(); | ||
116 | $names = array(1=>'',2=>'',3=>'',4=>'',6=>''); | ||
117 | $K = array_keys($names); | ||
118 | $nameCount = count($names); | ||
119 | for ($i=0;$i<$numRecords; $i++) { | ||
120 | $platformId = $this->read_ushort(); | ||
121 | $encodingId = $this->read_ushort(); | ||
122 | $languageId = $this->read_ushort(); | ||
123 | $nameId = $this->read_ushort(); | ||
124 | $length = $this->read_ushort(); | ||
125 | $offset = $this->read_ushort(); | ||
126 | if (!in_array($nameId,$K)) continue; | ||
127 | $N = ''; | ||
128 | if ($platformId == 3 && $encodingId == 1 && $languageId == 0x409) { // Microsoft, Unicode, US English, PS Name | ||
129 | $opos = $this->_pos; | ||
130 | $this->seek($string_data_offset + $offset); | ||
131 | if ($length % 2 != 0) | ||
132 | $length += 1; | ||
133 | $length /= 2; | ||
134 | $N = ''; | ||
135 | while ($length > 0) { | ||
136 | $char = $this->read_ushort(); | ||
137 | $N .= (chr($char)); | ||
138 | $length -= 1; | ||
139 | } | ||
140 | $this->_pos = $opos; | ||
141 | $this->seek($opos); | ||
142 | } | ||
143 | else if ($platformId == 1 && $encodingId == 0 && $languageId == 0) { // Macintosh, Roman, English, PS Name | ||
144 | $opos = $this->_pos; | ||
145 | $N = $this->get_chunk($string_data_offset + $offset, $length); | ||
146 | $this->_pos = $opos; | ||
147 | $this->seek($opos); | ||
148 | } | ||
149 | if ($N && $names[$nameId]=='') { | ||
150 | $names[$nameId] = $N; | ||
151 | $nameCount -= 1; | ||
152 | if ($nameCount==0) break; | ||
153 | } | ||
154 | } | ||
155 | if ($names[6]) | ||
156 | $psName = preg_replace('/ /','-',$names[6]); | ||
157 | else if ($names[4]) | ||
158 | $psName = preg_replace('/ /','-',$names[4]); | ||
159 | else if ($names[1]) | ||
160 | $psName = preg_replace('/ /','-',$names[1]); | ||
161 | else | ||
162 | $psName = ''; | ||
163 | if (!$names[1] && !$psName) | ||
164 | return("ERROR - NOT ADDED as Could not find valid font name - " . $file); | ||
165 | $this->name = $psName; | ||
166 | if ($names[1]) { $this->familyName = $names[1]; } else { $this->familyName = $psName; } | ||
167 | if ($names[2]) { $this->styleName = $names[2]; } else { $this->styleName = 'Regular'; } | ||
168 | |||
169 | /////////////////////////////////// | ||
170 | // head - Font header table | ||
171 | /////////////////////////////////// | ||
172 | $this->seek_table("head"); | ||
173 | $ver_maj = $this->read_ushort(); | ||
174 | $ver_min = $this->read_ushort(); | ||
175 | if ($ver_maj != 1) | ||
176 | return('ERROR - NOT ADDED as Unknown head table version '. $ver_maj .'.'. $ver_min." - " . $file); | ||
177 | $this->fontRevision = $this->read_ushort() . $this->read_ushort(); | ||
178 | $this->skip(4); | ||
179 | $magic = $this->read_ulong(); | ||
180 | if ($magic != 0x5F0F3CF5) | ||
181 | return('ERROR - NOT ADDED as Invalid head table magic ' .$magic." - " . $file); | ||
182 | $this->skip(2); | ||
183 | $this->unitsPerEm = $unitsPerEm = $this->read_ushort(); | ||
184 | $scale = 1000 / $unitsPerEm; | ||
185 | $this->skip(24); | ||
186 | $macStyle = $this->read_short(); | ||
187 | $this->skip(4); | ||
188 | $indexLocFormat = $this->read_short(); | ||
189 | |||
190 | /////////////////////////////////// | ||
191 | // OS/2 - OS/2 and Windows metrics table | ||
192 | /////////////////////////////////// | ||
193 | $sFamily = ''; | ||
194 | $panose = ''; | ||
195 | $fsSelection = ''; | ||
196 | if (isset($this->tables["OS/2"])) { | ||
197 | $this->seek_table("OS/2"); | ||
198 | $this->skip(30); | ||
199 | $sF = $this->read_short(); | ||
200 | $sFamily = ($sF >> 8); | ||
201 | $this->_pos += 10; //PANOSE = 10 byte length | ||
202 | $panose = fread($this->fh,10); | ||
203 | $this->panose = array(); | ||
204 | for ($p=0;$p<strlen($panose);$p++) { $this->panose[] = ord($panose[$p]); } | ||
205 | $this->skip(20); | ||
206 | $fsSelection = $this->read_short(); | ||
207 | } | ||
208 | |||
209 | /////////////////////////////////// | ||
210 | // post - PostScript table | ||
211 | /////////////////////////////////// | ||
212 | $this->seek_table("post"); | ||
213 | $this->skip(4); | ||
214 | $this->italicAngle = $this->read_short() + $this->read_ushort() / 65536.0; | ||
215 | $this->skip(4); | ||
216 | $isFixedPitch = $this->read_ulong(); | ||
217 | |||
218 | |||
219 | |||
220 | /////////////////////////////////// | ||
221 | // cmap - Character to glyph index mapping table | ||
222 | /////////////////////////////////// | ||
223 | $cmap_offset = $this->seek_table("cmap"); | ||
224 | $this->skip(2); | ||
225 | $cmapTableCount = $this->read_ushort(); | ||
226 | $unicode_cmap_offset = 0; | ||
227 | for ($i=0;$i<$cmapTableCount;$i++) { | ||
228 | $platformID = $this->read_ushort(); | ||
229 | $encodingID = $this->read_ushort(); | ||
230 | $offset = $this->read_ulong(); | ||
231 | $save_pos = $this->_pos; | ||
232 | if (($platformID == 3 && $encodingID == 1) || $platformID == 0) { // Microsoft, Unicode | ||
233 | $format = $this->get_ushort($cmap_offset + $offset); | ||
234 | if ($format == 4) { | ||
235 | if (!$unicode_cmap_offset) $unicode_cmap_offset = $cmap_offset + $offset; | ||
236 | } | ||
237 | } | ||
238 | else if ((($platformID == 3 && $encodingID == 10) || $platformID == 0)) { // Microsoft, Unicode Format 12 table HKCS | ||
239 | $format = $this->get_ushort($cmap_offset + $offset); | ||
240 | if ($format == 12) { | ||
241 | $unicode_cmap_offset = $cmap_offset + $offset; | ||
242 | break; | ||
243 | } | ||
244 | } | ||
245 | $this->seek($save_pos ); | ||
246 | } | ||
247 | |||
248 | if (!$unicode_cmap_offset) | ||
249 | return('ERROR - Font ('.$this->filename .') NOT ADDED as it is not Unicode encoded, and cannot be used by mPDF'); | ||
250 | |||
251 | $rtl = false; | ||
252 | $indic = false; | ||
253 | $cjk = false; | ||
254 | $sip = false; | ||
255 | $smp = false; | ||
256 | $pua = false; | ||
257 | $puaag = false; | ||
258 | $glyphToChar = array(); | ||
259 | $unAGlyphs = ''; | ||
260 | // Format 12 CMAP does characters above Unicode BMP i.e. some HKCS characters U+20000 and above | ||
261 | if ($format == 12) { | ||
262 | $this->seek($unicode_cmap_offset + 4); | ||
263 | $length = $this->read_ulong(); | ||
264 | $limit = $unicode_cmap_offset + $length; | ||
265 | $this->skip(4); | ||
266 | $nGroups = $this->read_ulong(); | ||
267 | for($i=0; $i<$nGroups ; $i++) { | ||
268 | $startCharCode = $this->read_ulong(); | ||
269 | $endCharCode = $this->read_ulong(); | ||
270 | $startGlyphCode = $this->read_ulong(); | ||
271 | if (($endCharCode > 0x20000 && $endCharCode < 0x2A6DF) || ($endCharCode > 0x2F800 && $endCharCode < 0x2FA1F)) { | ||
272 | $sip = true; | ||
273 | } | ||
274 | if ($endCharCode > 0x10000 && $endCharCode < 0x1FFFF) { | ||
275 | $smp = true; | ||
276 | } | ||
277 | if (($endCharCode > 0x0590 && $endCharCode < 0x077F) || ($endCharCode > 0xFE70 && $endCharCode < 0xFEFF) || ($endCharCode > 0xFB50 && $endCharCode < 0xFDFF)) { | ||
278 | $rtl = true; | ||
279 | } | ||
280 | if ($endCharCode > 0x0900 && $endCharCode < 0x0DFF) { | ||
281 | $indic = true; | ||
282 | } | ||
283 | if ($endCharCode > 0xE000 && $endCharCode < 0xF8FF) { | ||
284 | $pua = true; | ||
285 | if ($endCharCode > 0xF500 && $endCharCode < 0xF7FF) { | ||
286 | $puaag = true; | ||
287 | } | ||
288 | } | ||
289 | if (($endCharCode > 0x2E80 && $endCharCode < 0x4DC0) || ($endCharCode > 0x4E00 && $endCharCode < 0xA4CF) || ($endCharCode > 0xAC00 && $endCharCode < 0xD7AF) || ($endCharCode > 0xF900 && $endCharCode < 0xFAFF) || ($endCharCode > 0xFE30 && $endCharCode < 0xFE4F)) { | ||
290 | $cjk = true; | ||
291 | } | ||
292 | |||
293 | $offset = 0; | ||
294 | // Get each glyphToChar - only point if going to analyse un-mapped Arabic Glyphs | ||
295 | if (isset($this->tables['post'])) { | ||
296 | for ($unichar=$startCharCode;$unichar<=$endCharCode;$unichar++) { | ||
297 | $glyph = $startGlyphCode + $offset ; | ||
298 | $offset++; | ||
299 | $glyphToChar[$glyph][] = $unichar; | ||
300 | } | ||
301 | } | ||
302 | |||
303 | |||
304 | } | ||
305 | } | ||
306 | |||
307 | else { // Format 4 CMap | ||
308 | $this->seek($unicode_cmap_offset + 2); | ||
309 | $length = $this->read_ushort(); | ||
310 | $limit = $unicode_cmap_offset + $length; | ||
311 | $this->skip(2); | ||
312 | |||
313 | $segCount = $this->read_ushort() / 2; | ||
314 | $this->skip(6); | ||
315 | $endCount = array(); | ||
316 | for($i=0; $i<$segCount; $i++) { $endCount[] = $this->read_ushort(); } | ||
317 | $this->skip(2); | ||
318 | $startCount = array(); | ||
319 | for($i=0; $i<$segCount; $i++) { $startCount[] = $this->read_ushort(); } | ||
320 | $idDelta = array(); | ||
321 | for($i=0; $i<$segCount; $i++) { $idDelta[] = $this->read_short(); } | ||
322 | $idRangeOffset_start = $this->_pos; | ||
323 | $idRangeOffset = array(); | ||
324 | for($i=0; $i<$segCount; $i++) { $idRangeOffset[] = $this->read_ushort(); } | ||
325 | |||
326 | for ($n=0;$n<$segCount;$n++) { | ||
327 | if (($endCount[$n] > 0x0590 && $endCount[$n] < 0x077F) || ($endCount[$n] > 0xFE70 && $endCount[$n] < 0xFEFF) || ($endCount[$n] > 0xFB50 && $endCount[$n] < 0xFDFF)) { | ||
328 | $rtl = true; | ||
329 | } | ||
330 | if ($endCount[$n] > 0x0900 && $endCount[$n] < 0x0DFF) { | ||
331 | $indic = true; | ||
332 | } | ||
333 | if (($endCount[$n] > 0x2E80 && $endCount[$n] < 0x4DC0) || ($endCount[$n] > 0x4E00 && $endCount[$n] < 0xA4CF) || ($endCount[$n] > 0xAC00 && $endCount[$n] < 0xD7AF) || ($endCount[$n] > 0xF900 && $endCount[$n] < 0xFAFF) || ($endCount[$n] > 0xFE30 && $endCount[$n] < 0xFE4F)) { | ||
334 | $cjk = true; | ||
335 | } | ||
336 | if ($endCount[$n] > 0xE000 && $endCount[$n] < 0xF8FF) { | ||
337 | $pua = true; | ||
338 | if ($endCount[$n] > 0xF500 && $endCount[$n] < 0xF7FF) { | ||
339 | $puaag = true; | ||
340 | } | ||
341 | } | ||
342 | // Get each glyphToChar - only point if going to analyse un-mapped Arabic Glyphs | ||
343 | if (isset($this->tables['post'])) { | ||
344 | $endpoint = ($endCount[$n] + 1); | ||
345 | for ($unichar=$startCount[$n];$unichar<$endpoint;$unichar++) { | ||
346 | if ($idRangeOffset[$n] == 0) | ||
347 | $glyph = ($unichar + $idDelta[$n]) & 0xFFFF; | ||
348 | else { | ||
349 | $offset = ($unichar - $startCount[$n]) * 2 + $idRangeOffset[$n]; | ||
350 | $offset = $idRangeOffset_start + 2 * $n + $offset; | ||
351 | if ($offset >= $limit) | ||
352 | $glyph = 0; | ||
353 | else { | ||
354 | $glyph = $this->get_ushort($offset); | ||
355 | if ($glyph != 0) | ||
356 | $glyph = ($glyph + $idDelta[$n]) & 0xFFFF; | ||
357 | } | ||
358 | } | ||
359 | $glyphToChar[$glyph][] = $unichar; | ||
360 | } | ||
361 | } | ||
362 | |||
363 | } | ||
364 | } | ||
365 | // 'POST' table for un-mapped arabic glyphs | ||
366 | if (isset($this->tables['post'])) { | ||
367 | $this->seek_table("post"); | ||
368 | // Only works on Format 2.0 | ||
369 | $formata = $this->read_ushort(); | ||
370 | $formatb = $this->read_ushort(); | ||
371 | if ($formata == 2 && $formatb == 0) { | ||
372 | $this->skip(28); | ||
373 | $nGlyfs = $this->read_ushort(); | ||
374 | $glyphNameIndex = array(); | ||
375 | for ($i=0; $i<$nGlyfs; $i++) { | ||
376 | $glyphNameIndex[($this->read_ushort())] = $i; | ||
377 | } | ||
378 | |||
379 | $opost = $this->get_table('post'); | ||
380 | $ptr = 34+($nGlyfs*2); | ||
381 | for ($i=0; $i<$nGlyfs; $i++) { | ||
382 | $len = ord(substr($opost,$ptr,1)); | ||
383 | $ptr++; | ||
384 | $name = substr($opost,$ptr,$len); | ||
385 | $gid = $glyphNameIndex[$i+258]; | ||
386 | // Select uni0600.xxx(x) - uni06FF.xxx(x) | ||
387 | if (preg_match('/^uni(06[0-9a-f]{2})\.(fina|medi|init|fin|med|ini)$/i',$name,$m)) { | ||
388 | if (!isset($glyphToChar[$gid]) || (isset($glyphToChar[$gid]) && is_array($glyphToChar[$gid]) && count($glyphToChar[$gid])==1 && $glyphToChar[$gid][0]>57343 && $glyphToChar[$gid][0]<63489)) { // if set in PUA private use area E000-F8FF, or NOT Unicode mapped | ||
389 | $uni = hexdec($m[1]); | ||
390 | $form = strtoupper(substr($m[2],0,1)); | ||
391 | // Assign new PUA Unicode between F500 - F7FF | ||
392 | $bit = $uni & 0xFF; | ||
393 | if ($form == 'I') { $bit += 0xF600; } | ||
394 | else if ($form == 'M') { $bit += 0xF700; } | ||
395 | else { $bit += 0xF500; } | ||
396 | $unAGlyphs .= $gid; | ||
397 | $name = 'uni'.strtoupper($m[1]).'.'.strtolower($m[2]); | ||
398 | $unAGlyphs .= ' : '.$name; | ||
399 | $unihexstr = $m[1]; | ||
400 | $unAGlyphs .= ' : '.$unihexstr; | ||
401 | $unAGlyphs .= ' : '.$uni; | ||
402 | $unAGlyphs .= ' : '.$form; | ||
403 | // if already set in PUA private use area E000-F8FF | ||
404 | if (isset($glyphToChar[$gid]) && $glyphToChar[$gid][0]>57343 && $glyphToChar[$gid][0]<63489) { | ||
405 | $unAGlyphs .= ' : '.$glyphToChar[$gid][0].' {'.dechex($glyphToChar[$gid][0]).'}'; | ||
406 | } | ||
407 | //else $unAGlyphs .= ':'; | ||
408 | $unAGlyphs .= ' : '.strtoupper(dechex($bit)); | ||
409 | $unAGlyphs .= '<br />'; | ||
410 | } | ||
411 | } | ||
412 | $ptr += $len; | ||
413 | } | ||
414 | if ($unAGlyphs) { | ||
415 | $unAGlyphs = 'GID:Name:Unicode base Hex:Dec:Form:PUA Unicode<br />'.$unAGlyphs ; | ||
416 | } | ||
417 | } | ||
418 | } | ||
419 | |||
420 | |||
421 | |||
422 | $bold = false; | ||
423 | $italic = false; | ||
424 | $ftype = ''; | ||
425 | if ($macStyle & (1 << 0)) { $bold = true; } // bit 0 bold | ||
426 | else if ($fsSelection & (1 << 5)) { $bold = true; } // 5 BOLD Characters are emboldened | ||
427 | |||
428 | if ($macStyle & (1 << 1)) { $italic = true; } // bit 1 italic | ||
429 | else if ($fsSelection & (1 << 0)) { $italic = true; } // 0 ITALIC Font contains Italic characters, otherwise they are upright | ||
430 | else if ($this->italicAngle <> 0) { $italic = true; } | ||
431 | |||
432 | if ($isFixedPitch ) { $ftype = 'mono'; } | ||
433 | else if ($sFamily >0 && $sFamily <8) { $ftype = 'serif'; } | ||
434 | else if ($sFamily ==8) { $ftype = 'sans'; } | ||
435 | else if ($sFamily ==10) { $ftype = 'cursive'; } | ||
436 | // Use PANOSE | ||
437 | if ($panose) { | ||
438 | $bFamilyType=ord($panose[0]); | ||
439 | if ($bFamilyType==2) { | ||
440 | $bSerifStyle=ord($panose[1]); | ||
441 | if (!$ftype) { | ||
442 | if ($bSerifStyle>1 && $bSerifStyle<11) { $ftype = 'serif'; } | ||
443 | else if ($bSerifStyle>10) { $ftype = 'sans'; } | ||
444 | } | ||
445 | $bProportion=ord($panose[3]); | ||
446 | if ($bProportion==9 || $bProportion==1) { $ftype = 'mono'; } // ==1 i.e. No Fit needed for OCR-a and -b | ||
447 | } | ||
448 | else if ($bFamilyType==3) { | ||
449 | $ftype = 'cursive'; | ||
450 | } | ||
451 | } | ||
452 | |||
453 | fclose($this->fh); | ||
454 | return array($this->familyName, $bold, $italic, $ftype, $TTCfontID, $rtl, $indic, $cjk, $sip, $smp, $puaag, $pua, $unAGlyphs); | ||
455 | } | ||
456 | |||
457 | |||
458 | |||
459 | |||
460 | } | ||
461 | |||
462 | |||
463 | ?> \ No newline at end of file | ||
diff --git a/inc/3rdparty/libraries/mpdf/classes/wmf.php b/inc/3rdparty/libraries/mpdf/classes/wmf.php new file mode 100644 index 00000000..2efef00b --- /dev/null +++ b/inc/3rdparty/libraries/mpdf/classes/wmf.php | |||
@@ -0,0 +1,236 @@ | |||
1 | <?php | ||
2 | |||
3 | class wmf { | ||
4 | |||
5 | var $mpdf = null; | ||
6 | var $gdiObjectArray; | ||
7 | |||
8 | function wmf(&$mpdf) { | ||
9 | $this->mpdf = $mpdf; | ||
10 | } | ||
11 | |||
12 | |||
13 | function _getWMFimage($data) { | ||
14 | $k = _MPDFK; | ||
15 | |||
16 | $this->gdiObjectArray = array(); | ||
17 | $a=unpack('stest',"\1\0"); | ||
18 | if ($a['test']!=1) | ||
19 | return array(0, 'Error parsing WMF image - Big-endian architecture not supported'); | ||
20 | // check for Aldus placeable metafile header | ||
21 | $key = unpack('Lmagic', substr($data, 0, 4)); | ||
22 | $p = 18; // WMF header | ||
23 | if ($key['magic'] == (int)0x9AC6CDD7) { $p +=22; } // Aldus header | ||
24 | // define some state variables | ||
25 | $wo=null; // window origin | ||
26 | $we=null; // window extent | ||
27 | $polyFillMode = 0; | ||
28 | $nullPen = false; | ||
29 | $nullBrush = false; | ||
30 | $endRecord = false; | ||
31 | $wmfdata = ''; | ||
32 | while ($p < strlen($data) && !$endRecord) { | ||
33 | $recordInfo = unpack('Lsize/Sfunc', substr($data, $p, 6)); $p += 6; | ||
34 | // size of record given in WORDs (= 2 bytes) | ||
35 | $size = $recordInfo['size']; | ||
36 | // func is number of GDI function | ||
37 | $func = $recordInfo['func']; | ||
38 | if ($size > 3) { | ||
39 | $parms = substr($data, $p, 2*($size-3)); $p += 2*($size-3); | ||
40 | } | ||
41 | switch ($func) { | ||
42 | case 0x020b: // SetWindowOrg | ||
43 | // do not allow window origin to be changed | ||
44 | // after drawing has begun | ||
45 | if (!$wmfdata) | ||
46 | $wo = array_reverse(unpack('s2', $parms)); | ||
47 | break; | ||
48 | case 0x020c: // SetWindowExt | ||
49 | // do not allow window extent to be changed | ||
50 | // after drawing has begun | ||
51 | if (!$wmfdata) | ||
52 | $we = array_reverse(unpack('s2', $parms)); | ||
53 | break; | ||
54 | case 0x02fc: // CreateBrushIndirect | ||
55 | $brush = unpack('sstyle/Cr/Cg/Cb/Ca/Shatch', $parms); | ||
56 | $brush['type'] = 'B'; | ||
57 | $this->_AddGDIObject($brush); | ||
58 | break; | ||
59 | case 0x02fa: // CreatePenIndirect | ||
60 | $pen = unpack('Sstyle/swidth/sdummy/Cr/Cg/Cb/Ca', $parms); | ||
61 | // convert width from twips to user unit | ||
62 | $pen['width'] /= (20 * $k); | ||
63 | $pen['type'] = 'P'; | ||
64 | $this->_AddGDIObject($pen); | ||
65 | break; | ||
66 | |||
67 | // MUST create other GDI objects even if we don't handle them | ||
68 | case 0x06fe: // CreateBitmap | ||
69 | case 0x02fd: // CreateBitmapIndirect | ||
70 | case 0x00f8: // CreateBrush | ||
71 | case 0x02fb: // CreateFontIndirect | ||
72 | case 0x00f7: // CreatePalette | ||
73 | case 0x01f9: // CreatePatternBrush | ||
74 | case 0x06ff: // CreateRegion | ||
75 | case 0x0142: // DibCreatePatternBrush | ||
76 | $dummyObject = array('type'=>'D'); | ||
77 | $this->_AddGDIObject($dummyObject); | ||
78 | break; | ||
79 | case 0x0106: // SetPolyFillMode | ||
80 | $polyFillMode = unpack('smode', $parms); | ||
81 | $polyFillMode = $polyFillMode['mode']; | ||
82 | break; | ||
83 | case 0x01f0: // DeleteObject | ||
84 | $idx = unpack('Sidx', $parms); | ||
85 | $idx = $idx['idx']; | ||
86 | $this->_DeleteGDIObject($idx); | ||
87 | break; | ||
88 | case 0x012d: // SelectObject | ||
89 | $idx = unpack('Sidx', $parms); | ||
90 | $idx = $idx['idx']; | ||
91 | $obj = $this->_GetGDIObject($idx); | ||
92 | switch ($obj['type']) { | ||
93 | case 'B': | ||
94 | $nullBrush = false; | ||
95 | if ($obj['style'] == 1) { $nullBrush = true; } | ||
96 | else { | ||
97 | $wmfdata .= $this->mpdf->SetFColor($this->mpdf->ConvertColor('rgb('.$obj['r'].','.$obj['g'].','.$obj['b'].')'), true)."\n"; | ||
98 | } | ||
99 | break; | ||
100 | case 'P': | ||
101 | $nullPen = false; | ||
102 | $dashArray = array(); | ||
103 | // dash parameters are custom | ||
104 | switch ($obj['style']) { | ||
105 | case 0: // PS_SOLID | ||
106 | break; | ||
107 | case 1: // PS_DASH | ||
108 | $dashArray = array(3,1); | ||
109 | break; | ||
110 | case 2: // PS_DOT | ||
111 | $dashArray = array(0.5,0.5); | ||
112 | break; | ||
113 | case 3: // PS_DASHDOT | ||
114 | $dashArray = array(2,1,0.5,1); | ||
115 | break; | ||
116 | case 4: // PS_DASHDOTDOT | ||
117 | $dashArray = array(2,1,0.5,1,0.5,1); | ||
118 | break; | ||
119 | case 5: // PS_NULL | ||
120 | $nullPen = true; | ||
121 | break; | ||
122 | } | ||
123 | if (!$nullPen) { | ||
124 | $wmfdata .= $this->mpdf->SetDColor($this->mpdf->ConvertColor('rgb('.$obj['r'].','.$obj['g'].','.$obj['b'].')'), true)."\n"; | ||
125 | $wmfdata .= sprintf("%.3F w\n",$obj['width']*$k); | ||
126 | } | ||
127 | if (!empty($dashArray)) { | ||
128 | $s = '['; | ||
129 | for ($i=0; $i<count($dashArray);$i++) { | ||
130 | $s .= $dashArray[$i] * $k; | ||
131 | if ($i != count($dashArray)-1) { $s .= ' '; } | ||
132 | } | ||
133 | $s .= '] 0 d'; | ||
134 | $wmfdata .= $s."\n"; | ||
135 | } | ||
136 | break; | ||
137 | } | ||
138 | break; | ||
139 | case 0x0325: // Polyline | ||
140 | case 0x0324: // Polygon | ||
141 | $coords = unpack('s'.($size-3), $parms); | ||
142 | $numpoints = $coords[1]; | ||
143 | for ($i = $numpoints; $i > 0; $i--) { | ||
144 | $px = $coords[2*$i]; | ||
145 | $py = $coords[2*$i+1]; | ||
146 | |||
147 | if ($i < $numpoints) { $wmfdata .= $this->_LineTo($px, $py); } | ||
148 | else { $wmfdata .= $this->_MoveTo($px, $py); } | ||
149 | } | ||
150 | if ($func == 0x0325) { $op = 's'; } | ||
151 | else if ($func == 0x0324) { | ||
152 | if ($nullPen) { | ||
153 | if ($nullBrush) { $op = 'n'; } // no op | ||
154 | else { $op = 'f'; } // fill | ||
155 | } | ||
156 | else { | ||
157 | if ($nullBrush) { $op = 's'; } // stroke | ||
158 | else { $op = 'b'; } // stroke and fill | ||
159 | } | ||
160 | if ($polyFillMode==1 && ($op=='b' || $op=='f')) { $op .= '*'; } // use even-odd fill rule | ||
161 | } | ||
162 | $wmfdata .= $op."\n"; | ||
163 | break; | ||
164 | case 0x0538: // PolyPolygon | ||
165 | $coords = unpack('s'.($size-3), $parms); | ||
166 | $numpolygons = $coords[1]; | ||
167 | $adjustment = $numpolygons; | ||
168 | for ($j = 1; $j <= $numpolygons; $j++) { | ||
169 | $numpoints = $coords[$j + 1]; | ||
170 | for ($i = $numpoints; $i > 0; $i--) { | ||
171 | $px = $coords[2*$i + $adjustment]; | ||
172 | $py = $coords[2*$i+1 + $adjustment]; | ||
173 | if ($i == $numpoints) { $wmfdata .= $this->_MoveTo($px, $py); } | ||
174 | else { $wmfdata .= $this->_LineTo($px, $py); } | ||
175 | } | ||
176 | $adjustment += $numpoints * 2; | ||
177 | } | ||
178 | |||
179 | if ($nullPen) { | ||
180 | if ($nullBrush) { $op = 'n'; } // no op | ||
181 | else { $op = 'f'; } // fill | ||
182 | } | ||
183 | else { | ||
184 | if ($nullBrush) { $op = 's'; } // stroke | ||
185 | else { $op = 'b'; } // stroke and fill | ||
186 | } | ||
187 | if ($polyFillMode==1 && ($op=='b' || $op=='f')) { $op .= '*'; } // use even-odd fill rule | ||
188 | $wmfdata .= $op."\n"; | ||
189 | break; | ||
190 | case 0x0000: | ||
191 | $endRecord = true; | ||
192 | break; | ||
193 | } | ||
194 | } | ||
195 | |||
196 | |||
197 | return array(1,$wmfdata,$wo,$we); | ||
198 | } | ||
199 | |||
200 | |||
201 | function _MoveTo($x, $y) { | ||
202 | return "$x $y m\n"; | ||
203 | } | ||
204 | |||
205 | // a line must have been started using _MoveTo() first | ||
206 | function _LineTo($x, $y) { | ||
207 | return "$x $y l\n"; | ||
208 | } | ||
209 | |||
210 | function _AddGDIObject($obj) { | ||
211 | // find next available slot | ||
212 | $idx = 0; | ||
213 | if (!empty($this->gdiObjectArray)) { | ||
214 | $empty = false; | ||
215 | $i = 0; | ||
216 | while (!$empty) { | ||
217 | $empty = !isset($this->gdiObjectArray[$i]); | ||
218 | $i++; | ||
219 | } | ||
220 | $idx = $i-1; | ||
221 | } | ||
222 | $this->gdiObjectArray[$idx] = $obj; | ||
223 | } | ||
224 | |||
225 | function _GetGDIObject($idx) { | ||
226 | return $this->gdiObjectArray[$idx]; | ||
227 | } | ||
228 | |||
229 | function _DeleteGDIObject($idx) { | ||
230 | unset($this->gdiObjectArray[$idx]); | ||
231 | } | ||
232 | |||
233 | |||
234 | } | ||
235 | |||
236 | ?> \ No newline at end of file | ||