aboutsummaryrefslogtreecommitdiffhomepage
path: root/inc/3rdparty/libraries/mpdf/classes
diff options
context:
space:
mode:
Diffstat (limited to 'inc/3rdparty/libraries/mpdf/classes')
-rw-r--r--inc/3rdparty/libraries/mpdf/classes/barcode.php1966
-rw-r--r--inc/3rdparty/libraries/mpdf/classes/bmp.php248
-rw-r--r--inc/3rdparty/libraries/mpdf/classes/cssmgr.php1572
-rw-r--r--inc/3rdparty/libraries/mpdf/classes/directw.php408
-rw-r--r--inc/3rdparty/libraries/mpdf/classes/form.php1498
-rw-r--r--inc/3rdparty/libraries/mpdf/classes/gif.php700
-rw-r--r--inc/3rdparty/libraries/mpdf/classes/grad.php723
-rw-r--r--inc/3rdparty/libraries/mpdf/classes/indic.php433
-rw-r--r--inc/3rdparty/libraries/mpdf/classes/meter.php224
-rw-r--r--inc/3rdparty/libraries/mpdf/classes/svg.php2703
-rw-r--r--inc/3rdparty/libraries/mpdf/classes/tocontents.php467
-rw-r--r--inc/3rdparty/libraries/mpdf/classes/ttfontsuni.php2065
-rw-r--r--inc/3rdparty/libraries/mpdf/classes/ttfontsuni_analysis.php463
-rw-r--r--inc/3rdparty/libraries/mpdf/classes/wmf.php236
14 files changed, 0 insertions, 13706 deletions
diff --git a/inc/3rdparty/libraries/mpdf/classes/barcode.php b/inc/3rdparty/libraries/mpdf/classes/barcode.php
deleted file mode 100644
index 9a230f0e..00000000
--- a/inc/3rdparty/libraries/mpdf/classes/barcode.php
+++ /dev/null
@@ -1,1966 +0,0 @@
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
45class 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 $code = strcode2utf($code); // mPDF 5.7.1 Allows e.g. <barcode code="5432&#013;1068" type="C128A" />
875 $chr = array(
876 '212222', /* 00 */
877 '222122', /* 01 */
878 '222221', /* 02 */
879 '121223', /* 03 */
880 '121322', /* 04 */
881 '131222', /* 05 */
882 '122213', /* 06 */
883 '122312', /* 07 */
884 '132212', /* 08 */
885 '221213', /* 09 */
886 '221312', /* 10 */
887 '231212', /* 11 */
888 '112232', /* 12 */
889 '122132', /* 13 */
890 '122231', /* 14 */
891 '113222', /* 15 */
892 '123122', /* 16 */
893 '123221', /* 17 */
894 '223211', /* 18 */
895 '221132', /* 19 */
896 '221231', /* 20 */
897 '213212', /* 21 */
898 '223112', /* 22 */
899 '312131', /* 23 */
900 '311222', /* 24 */
901 '321122', /* 25 */
902 '321221', /* 26 */
903 '312212', /* 27 */
904 '322112', /* 28 */
905 '322211', /* 29 */
906 '212123', /* 30 */
907 '212321', /* 31 */
908 '232121', /* 32 */
909 '111323', /* 33 */
910 '131123', /* 34 */
911 '131321', /* 35 */
912 '112313', /* 36 */
913 '132113', /* 37 */
914 '132311', /* 38 */
915 '211313', /* 39 */
916 '231113', /* 40 */
917 '231311', /* 41 */
918 '112133', /* 42 */
919 '112331', /* 43 */
920 '132131', /* 44 */
921 '113123', /* 45 */
922 '113321', /* 46 */
923 '133121', /* 47 */
924 '313121', /* 48 */
925 '211331', /* 49 */
926 '231131', /* 50 */
927 '213113', /* 51 */
928 '213311', /* 52 */
929 '213131', /* 53 */
930 '311123', /* 54 */
931 '311321', /* 55 */
932 '331121', /* 56 */
933 '312113', /* 57 */
934 '312311', /* 58 */
935 '332111', /* 59 */
936 '314111', /* 60 */
937 '221411', /* 61 */
938 '431111', /* 62 */
939 '111224', /* 63 */
940 '111422', /* 64 */
941 '121124', /* 65 */
942 '121421', /* 66 */
943 '141122', /* 67 */
944 '141221', /* 68 */
945 '112214', /* 69 */
946 '112412', /* 70 */
947 '122114', /* 71 */
948 '122411', /* 72 */
949 '142112', /* 73 */
950 '142211', /* 74 */
951 '241211', /* 75 */
952 '221114', /* 76 */
953 '413111', /* 77 */
954 '241112', /* 78 */
955 '134111', /* 79 */
956 '111242', /* 80 */
957 '121142', /* 81 */
958 '121241', /* 82 */
959 '114212', /* 83 */
960 '124112', /* 84 */
961 '124211', /* 85 */
962 '411212', /* 86 */
963 '421112', /* 87 */
964 '421211', /* 88 */
965 '212141', /* 89 */
966 '214121', /* 90 */
967 '412121', /* 91 */
968 '111143', /* 92 */
969 '111341', /* 93 */
970 '131141', /* 94 */
971 '114113', /* 95 */
972 '114311', /* 96 */
973 '411113', /* 97 */
974 '411311', /* 98 */
975 '113141', /* 99 */
976 '114131', /* 100 */
977 '311141', /* 101 */
978 '411131', /* 102 */
979 '211412', /* 103 START A */
980 '211214', /* 104 START B */
981 '211232', /* 105 START C */
982 '233111', /* STOP */
983 '200000' /* END */
984 );
985 $keys = '';
986 switch(strtoupper($type)) {
987 case 'A': {
988 $startid = 103;
989 $keys = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_';
990 for ($i = 0; $i < 32; ++$i) {
991 $keys .= chr($i);
992 }
993 break;
994 }
995 case 'B': {
996 $startid = 104;
997 $keys = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'.chr(127);
998 break;
999 }
1000 case 'C': {
1001 $startid = 105;
1002 $keys = '';
1003 if ((strlen($code) % 2) != 0) {
1004 // The length of barcode value must be even ($code). You must pad the number with zeros
1005 return false;
1006 }
1007 for ($i = 0; $i <= 99; ++$i) {
1008 $keys .= chr($i);
1009 }
1010 $new_code = '';
1011 $hclen = (strlen($code) / 2);
1012 for ($i = 0; $i < $hclen; ++$i) {
1013 $new_code .= chr(intval($code{(2 * $i)}.$code{(2 * $i + 1)}));
1014 }
1015 $code = $new_code;
1016 break;
1017 }
1018 default: {
1019 return false;
1020 }
1021 }
1022
1023 // calculate check character
1024 $sum = $startid;
1025 if ($ean) { $code = chr(102) . $code; } // Add FNC 1 - which identifies it as EAN-128
1026 $clen = strlen($code);
1027 for ($i = 0; $i < $clen; ++$i) {
1028 if ($ean && $i==0) { $sum += 102; }
1029 else { $sum += (strpos($keys, $code[$i]) * ($i+1)); }
1030 }
1031 $check = ($sum % 103);
1032 $checkdigit = $check ;
1033 // add start, check and stop codes
1034 $code = chr($startid).$code.chr($check).chr(106).chr(107);
1035 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1036 $k = 0;
1037 $len = strlen($code);
1038 for ($i = 0; $i < $len; ++$i) {
1039 $ck = strpos($keys, $code[$i]);
1040 if (($i == 0) || ($ean && $i==1) | ($i > ($len-4))) {
1041 $char_num = ord($code[$i]);
1042 $seq = $chr[$char_num];
1043 } elseif(($ck >= 0) AND isset($chr[$ck])) {
1044 $seq = $chr[$ck];
1045 } else {
1046 // invalid character
1047 return false;
1048 }
1049 for ($j = 0; $j < 6; ++$j) {
1050 if (($j % 2) == 0) {
1051 $t = true; // bar
1052 } else {
1053 $t = false; // space
1054 }
1055 $w = $seq[$j];
1056 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1057 $bararray['maxw'] += $w;
1058 ++$k;
1059 }
1060 }
1061 $bararray['checkdigit'] = $checkdigit;
1062 return $bararray;
1063 }
1064
1065 /**
1066 * EAN13 and UPC-A barcodes.
1067 * EAN13: European Article Numbering international retail product code
1068 * UPC-A: Universal product code seen on almost all retail products in the USA and Canada
1069 * UPC-E: Short version of UPC symbol
1070 */
1071 protected function barcode_eanupc($code, $len=13) {
1072 $upce = false;
1073 $checkdigit = false;
1074 if ($len == 6) {
1075 $len = 12; // UPC-A
1076 $upce = true; // UPC-E mode
1077 }
1078 $data_len = $len - 1;
1079 //Padding
1080 $code = str_pad($code, $data_len, '0', STR_PAD_LEFT);
1081 $code_len = strlen($code);
1082 // calculate check digit
1083 $sum_a = 0;
1084 for ($i = 1; $i < $data_len; $i+=2) {
1085 $sum_a += $code[$i];
1086 }
1087 if ($len > 12) {
1088 $sum_a *= 3;
1089 }
1090 $sum_b = 0;
1091 for ($i = 0; $i < $data_len; $i+=2) {
1092 $sum_b += ($code[$i]);
1093 }
1094 if ($len < 13) {
1095 $sum_b *= 3;
1096 }
1097 $r = ($sum_a + $sum_b) % 10;
1098 if($r > 0) {
1099 $r = (10 - $r);
1100 }
1101 if ($code_len == $data_len) {
1102 // add check digit
1103 $code .= $r;
1104 $checkdigit = $r;
1105 } elseif ($r !== intval($code[$data_len])) {
1106 // wrong checkdigit
1107 return false;
1108 }
1109 if ($len == 12) {
1110 // UPC-A
1111 $code = '0'.$code;
1112 ++$len;
1113 }
1114 if ($upce) {
1115 // convert UPC-A to UPC-E
1116 $tmp = substr($code, 4, 3);
1117 $prod_code = intval(substr($code,7,5)); // product code
1118 $invalid_upce = false;
1119 if (($tmp == '000') OR ($tmp == '100') OR ($tmp == '200')) {
1120 // manufacturer code ends in 000, 100, or 200
1121 $upce_code = substr($code, 2, 2).substr($code, 9, 3).substr($code, 4, 1);
1122 if ($prod_code > 999) { $invalid_upce = true; }
1123 } else {
1124 $tmp = substr($code, 5, 2);
1125 if ($tmp == '00') {
1126 // manufacturer code ends in 00
1127 $upce_code = substr($code, 2, 3).substr($code, 10, 2).'3';
1128 if ($prod_code > 99) { $invalid_upce = true; }
1129 } else {
1130 $tmp = substr($code, 6, 1);
1131 if ($tmp == '0') {
1132 // manufacturer code ends in 0
1133 $upce_code = substr($code, 2, 4).substr($code, 11, 1).'4';
1134 if ($prod_code > 9) { $invalid_upce = true; }
1135 } else {
1136 // manufacturer code does not end in zero
1137 $upce_code = substr($code, 2, 5).substr($code, 11, 1);
1138 if ($prod_code > 9) { $invalid_upce = true; }
1139 }
1140 }
1141 }
1142 if ($invalid_upce) { die("Error - UPC-A cannot produce a valid UPC-E barcode"); } // Error generating a UPCE code
1143 }
1144 //Convert digits to bars
1145 $codes = array(
1146 'A'=>array( // left odd parity
1147 '0'=>'0001101',
1148 '1'=>'0011001',
1149 '2'=>'0010011',
1150 '3'=>'0111101',
1151 '4'=>'0100011',
1152 '5'=>'0110001',
1153 '6'=>'0101111',
1154 '7'=>'0111011',
1155 '8'=>'0110111',
1156 '9'=>'0001011'),
1157 'B'=>array( // left even parity
1158 '0'=>'0100111',
1159 '1'=>'0110011',
1160 '2'=>'0011011',
1161 '3'=>'0100001',
1162 '4'=>'0011101',
1163 '5'=>'0111001',
1164 '6'=>'0000101',
1165 '7'=>'0010001',
1166 '8'=>'0001001',
1167 '9'=>'0010111'),
1168 'C'=>array( // right
1169 '0'=>'1110010',
1170 '1'=>'1100110',
1171 '2'=>'1101100',
1172 '3'=>'1000010',
1173 '4'=>'1011100',
1174 '5'=>'1001110',
1175 '6'=>'1010000',
1176 '7'=>'1000100',
1177 '8'=>'1001000',
1178 '9'=>'1110100')
1179 );
1180 $parities = array(
1181 '0'=>array('A','A','A','A','A','A'),
1182 '1'=>array('A','A','B','A','B','B'),
1183 '2'=>array('A','A','B','B','A','B'),
1184 '3'=>array('A','A','B','B','B','A'),
1185 '4'=>array('A','B','A','A','B','B'),
1186 '5'=>array('A','B','B','A','A','B'),
1187 '6'=>array('A','B','B','B','A','A'),
1188 '7'=>array('A','B','A','B','A','B'),
1189 '8'=>array('A','B','A','B','B','A'),
1190 '9'=>array('A','B','B','A','B','A')
1191 );
1192 $upce_parities = array();
1193 $upce_parities[0] = array(
1194 '0'=>array('B','B','B','A','A','A'),
1195 '1'=>array('B','B','A','B','A','A'),
1196 '2'=>array('B','B','A','A','B','A'),
1197 '3'=>array('B','B','A','A','A','B'),
1198 '4'=>array('B','A','B','B','A','A'),
1199 '5'=>array('B','A','A','B','B','A'),
1200 '6'=>array('B','A','A','A','B','B'),
1201 '7'=>array('B','A','B','A','B','A'),
1202 '8'=>array('B','A','B','A','A','B'),
1203 '9'=>array('B','A','A','B','A','B')
1204 );
1205 $upce_parities[1] = array(
1206 '0'=>array('A','A','A','B','B','B'),
1207 '1'=>array('A','A','B','A','B','B'),
1208 '2'=>array('A','A','B','B','A','B'),
1209 '3'=>array('A','A','B','B','B','A'),
1210 '4'=>array('A','B','A','A','B','B'),
1211 '5'=>array('A','B','B','A','A','B'),
1212 '6'=>array('A','B','B','B','A','A'),
1213 '7'=>array('A','B','A','B','A','B'),
1214 '8'=>array('A','B','A','B','B','A'),
1215 '9'=>array('A','B','B','A','B','A')
1216 );
1217 $k = 0;
1218 $seq = '101'; // left guard bar
1219 if ($upce) {
1220 $bararray = array('code' => $upce_code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1221 $p = $upce_parities[$code{1}][$r];
1222 for ($i = 0; $i < 6; ++$i) {
1223 $seq .= $codes[$p[$i]][$upce_code[$i]];
1224 }
1225 $seq .= '010101'; // right guard bar
1226 } else {
1227 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1228 $half_len = ceil($len / 2);
1229 if ($len == 8) {
1230 for ($i = 0; $i < $half_len; ++$i) {
1231 $seq .= $codes['A'][$code[$i]];
1232 }
1233 } else {
1234 $p = $parities[$code{0}];
1235 for ($i = 1; $i < $half_len; ++$i) {
1236 $seq .= $codes[$p[$i-1]][$code[$i]];
1237 }
1238 }
1239 $seq .= '01010'; // center guard bar
1240 for ($i = $half_len; $i < $len; ++$i) {
1241 $seq .= $codes['C'][$code[$i]];
1242 }
1243 $seq .= '101'; // right guard bar
1244 }
1245 $clen = strlen($seq);
1246 $w = 0;
1247 for ($i = 0; $i < $clen; ++$i) {
1248 $w += 1;
1249 if (($i == ($clen - 1)) OR (($i < ($clen - 1)) AND ($seq[$i] != $seq[($i+1)]))) {
1250 if ($seq[$i] == '1') {
1251 $t = true; // bar
1252 } else {
1253 $t = false; // space
1254 }
1255 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1256 $bararray['maxw'] += $w;
1257 ++$k;
1258 $w = 0;
1259 }
1260 }
1261 $bararray['checkdigit'] = $checkdigit;
1262 return $bararray;
1263 }
1264
1265 /**
1266 * UPC-Based Extentions
1267 * 2-Digit Ext.: Used to indicate magazines and newspaper issue numbers
1268 * 5-Digit Ext.: Used to mark suggested retail price of books
1269 */
1270 protected function barcode_eanext($code, $len=5) {
1271 //Padding
1272 $code = str_pad($code, $len, '0', STR_PAD_LEFT);
1273 // calculate check digit
1274 if ($len == 2) {
1275 $r = $code % 4;
1276 } elseif ($len == 5) {
1277 $r = (3 * ($code{0} + $code{2} + $code{4})) + (9 * ($code{1} + $code{3}));
1278 $r %= 10;
1279 } else {
1280 return false;
1281 }
1282 //Convert digits to bars
1283 $codes = array(
1284 'A'=>array( // left odd parity
1285 '0'=>'0001101',
1286 '1'=>'0011001',
1287 '2'=>'0010011',
1288 '3'=>'0111101',
1289 '4'=>'0100011',
1290 '5'=>'0110001',
1291 '6'=>'0101111',
1292 '7'=>'0111011',
1293 '8'=>'0110111',
1294 '9'=>'0001011'),
1295 'B'=>array( // left even parity
1296 '0'=>'0100111',
1297 '1'=>'0110011',
1298 '2'=>'0011011',
1299 '3'=>'0100001',
1300 '4'=>'0011101',
1301 '5'=>'0111001',
1302 '6'=>'0000101',
1303 '7'=>'0010001',
1304 '8'=>'0001001',
1305 '9'=>'0010111')
1306 );
1307 $parities = array();
1308 $parities[2] = array(
1309 '0'=>array('A','A'),
1310 '1'=>array('A','B'),
1311 '2'=>array('B','A'),
1312 '3'=>array('B','B')
1313 );
1314 $parities[5] = array(
1315 '0'=>array('B','B','A','A','A'),
1316 '1'=>array('B','A','B','A','A'),
1317 '2'=>array('B','A','A','B','A'),
1318 '3'=>array('B','A','A','A','B'),
1319 '4'=>array('A','B','B','A','A'),
1320 '5'=>array('A','A','B','B','A'),
1321 '6'=>array('A','A','A','B','B'),
1322 '7'=>array('A','B','A','B','A'),
1323 '8'=>array('A','B','A','A','B'),
1324 '9'=>array('A','A','B','A','B')
1325 );
1326 $p = $parities[$len][$r];
1327 $seq = '1011'; // left guard bar
1328 $seq .= $codes[$p[0]][$code{0}];
1329 for ($i = 1; $i < $len; ++$i) {
1330 $seq .= '01'; // separator
1331 $seq .= $codes[$p[$i]][$code[$i]];
1332 }
1333 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1334 return $this->binseq_to_array($seq, $bararray);
1335 }
1336
1337 /**
1338 * POSTNET and PLANET barcodes.
1339 * Used by U.S. Postal Service for automated mail sorting
1340 */
1341 protected function barcode_postnet($code, $planet=false) {
1342 // bar lenght
1343 if ($planet) {
1344 $barlen = Array(
1345 0 => Array(1,1,2,2,2),
1346 1 => Array(2,2,2,1,1),
1347 2 => Array(2,2,1,2,1),
1348 3 => Array(2,2,1,1,2),
1349 4 => Array(2,1,2,2,1),
1350 5 => Array(2,1,2,1,2),
1351 6 => Array(2,1,1,2,2),
1352 7 => Array(1,2,2,2,1),
1353 8 => Array(1,2,2,1,2),
1354 9 => Array(1,2,1,2,2)
1355 );
1356 } else {
1357 $barlen = Array(
1358 0 => Array(2,2,1,1,1),
1359 1 => Array(1,1,1,2,2),
1360 2 => Array(1,1,2,1,2),
1361 3 => Array(1,1,2,2,1),
1362 4 => Array(1,2,1,1,2),
1363 5 => Array(1,2,1,2,1),
1364 6 => Array(1,2,2,1,1),
1365 7 => Array(2,1,1,1,2),
1366 8 => Array(2,1,1,2,1),
1367 9 => Array(2,1,2,1,1)
1368 );
1369 }
1370 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 5, 'bcode' => array());
1371 $k = 0;
1372 $code = str_replace('-', '', $code);
1373 $code = str_replace(' ', '', $code);
1374 $len = strlen($code);
1375 // calculate checksum
1376 $sum = 0;
1377 for ($i = 0; $i < $len; ++$i) {
1378 $sum += intval($code[$i]);
1379 }
1380 $chkd = ($sum % 10);
1381 if($chkd > 0) {
1382 $chkd = (10 - $chkd);
1383 }
1384 $code .= $chkd;
1385 $checkdigit = $chkd;
1386 $len = strlen($code);
1387 // start bar
1388 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 5, 'p' => 0);
1389 $bararray['bcode'][$k++] = array('t' => 0, 'w' => $this->gapwidth , 'h' => 5, 'p' => 0);
1390 $bararray['maxw'] += (1 + $this->gapwidth );
1391 for ($i = 0; $i < $len; ++$i) {
1392 for ($j = 0; $j < 5; ++$j) {
1393 $bh = $barlen[$code[$i]][$j];
1394 if ($bh == 2) {
1395 $h = 5;
1396 $p = 0;
1397 }
1398 else {
1399 $h = 2;
1400 $p = 3;
1401 }
1402 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
1403 $bararray['bcode'][$k++] = array('t' => 0, 'w' => $this->gapwidth , 'h' => 2, 'p' => 0);
1404 $bararray['maxw'] += (1 + $this->gapwidth );
1405 }
1406 }
1407 // end bar
1408 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => 5, 'p' => 0);
1409 $bararray['maxw'] += 1;
1410 $bararray['checkdigit'] = $checkdigit;
1411 return $bararray;
1412 }
1413
1414 /**
1415 * RM4SCC - CBC - KIX
1416 * RM4SCC (Royal Mail 4-state Customer Code) - CBC (Customer Bar Code) - KIX (Klant index - Customer index)
1417 * RM4SCC is the name of the barcode symbology used by the Royal Mail for its Cleanmail service.
1418 */
1419 protected function barcode_rm4scc($code, $kix=false) {
1420 $notkix = !$kix;
1421 // bar mode
1422 // 1 = pos 1, length 2
1423 // 2 = pos 1, length 3
1424 // 3 = pos 2, length 1
1425 // 4 = pos 2, length 2
1426 $barmode = array(
1427 '0' => array(3,3,2,2),
1428 '1' => array(3,4,1,2),
1429 '2' => array(3,4,2,1),
1430 '3' => array(4,3,1,2),
1431 '4' => array(4,3,2,1),
1432 '5' => array(4,4,1,1),
1433 '6' => array(3,1,4,2),
1434 '7' => array(3,2,3,2),
1435 '8' => array(3,2,4,1),
1436 '9' => array(4,1,3,2),
1437 'A' => array(4,1,4,1),
1438 'B' => array(4,2,3,1),
1439 'C' => array(3,1,2,4),
1440 'D' => array(3,2,1,4),
1441 'E' => array(3,2,2,3),
1442 'F' => array(4,1,1,4),
1443 'G' => array(4,1,2,3),
1444 'H' => array(4,2,1,3),
1445 'I' => array(1,3,4,2),
1446 'J' => array(1,4,3,2),
1447 'K' => array(1,4,4,1),
1448 'L' => array(2,3,3,2),
1449 'M' => array(2,3,4,1),
1450 'N' => array(2,4,3,1),
1451 'O' => array(1,3,2,4),
1452 'P' => array(1,4,1,4),
1453 'Q' => array(1,4,2,3),
1454 'R' => array(2,3,1,4),
1455 'S' => array(2,3,2,3),
1456 'T' => array(2,4,1,3),
1457 'U' => array(1,1,4,4),
1458 'V' => array(1,2,3,4),
1459 'W' => array(1,2,4,3),
1460 'X' => array(2,1,3,4),
1461 'Y' => array(2,1,4,3),
1462 'Z' => array(2,2,3,3)
1463 );
1464 $code = strtoupper($code);
1465 $len = strlen($code);
1466 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => $this->daft['F'], 'bcode' => array());
1467 if ($notkix) {
1468 // table for checksum calculation (row,col)
1469 $checktable = array(
1470 '0' => array(1,1),
1471 '1' => array(1,2),
1472 '2' => array(1,3),
1473 '3' => array(1,4),
1474 '4' => array(1,5),
1475 '5' => array(1,0),
1476 '6' => array(2,1),
1477 '7' => array(2,2),
1478 '8' => array(2,3),
1479 '9' => array(2,4),
1480 'A' => array(2,5),
1481 'B' => array(2,0),
1482 'C' => array(3,1),
1483 'D' => array(3,2),
1484 'E' => array(3,3),
1485 'F' => array(3,4),
1486 'G' => array(3,5),
1487 'H' => array(3,0),
1488 'I' => array(4,1),
1489 'J' => array(4,2),
1490 'K' => array(4,3),
1491 'L' => array(4,4),
1492 'M' => array(4,5),
1493 'N' => array(4,0),
1494 'O' => array(5,1),
1495 'P' => array(5,2),
1496 'Q' => array(5,3),
1497 'R' => array(5,4),
1498 'S' => array(5,5),
1499 'T' => array(5,0),
1500 'U' => array(0,1),
1501 'V' => array(0,2),
1502 'W' => array(0,3),
1503 'X' => array(0,4),
1504 'Y' => array(0,5),
1505 'Z' => array(0,0)
1506 );
1507 $row = 0;
1508 $col = 0;
1509 for ($i = 0; $i < $len; ++$i) {
1510 $row += $checktable[$code[$i]][0];
1511 $col += $checktable[$code[$i]][1];
1512 }
1513 $row %= 6;
1514 $col %= 6;
1515 $chk = array_keys($checktable, array($row,$col));
1516 $code .= $chk[0];
1517 $bararray['checkdigit'] = $chk[0];
1518 ++$len;
1519 }
1520 $k = 0;
1521 if ($notkix) {
1522 // start bar
1523 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $this->daft['A'] , 'p' => 0);
1524 $bararray['bcode'][$k++] = array('t' => 0, 'w' => $this->gapwidth , 'h' => $this->daft['A'] , 'p' => 0);
1525 $bararray['maxw'] += (1 + $this->gapwidth) ;
1526 }
1527 for ($i = 0; $i < $len; ++$i) {
1528 for ($j = 0; $j < 4; ++$j) {
1529 switch ($barmode[$code[$i]][$j]) {
1530 case 1: {
1531 // ascender (A)
1532 $p = 0;
1533 $h = $this->daft['A'];
1534 break;
1535 }
1536 case 2: {
1537 // full bar (F)
1538 $p = 0;
1539 $h = $this->daft['F'];
1540 break;
1541 }
1542 case 3: {
1543 // tracker (T)
1544 $p = ($this->daft['F'] - $this->daft['T'])/2;
1545 $h = $this->daft['T'];
1546 break;
1547 }
1548 case 4: {
1549 // descender (D)
1550 $p = $this->daft['F'] - $this->daft['D'];
1551 $h = $this->daft['D'];
1552 break;
1553 }
1554 }
1555
1556 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
1557 $bararray['bcode'][$k++] = array('t' => 0, 'w' => $this->gapwidth, 'h' => 2, 'p' => 0);
1558 $bararray['maxw'] += (1 + $this->gapwidth) ;
1559 }
1560 }
1561 if ($notkix) {
1562 // stop bar
1563 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $this->daft['F'], 'p' => 0);
1564 $bararray['maxw'] += 1;
1565 }
1566 return $bararray;
1567 }
1568
1569 /**
1570 * CODABAR barcodes.
1571 * Older code often used in library systems, sometimes in blood banks
1572 */
1573 protected function barcode_codabar($code) {
1574 $chr = array(
1575 '0' => '11111221',
1576 '1' => '11112211',
1577 '2' => '11121121',
1578 '3' => '22111111',
1579 '4' => '11211211',
1580 '5' => '21111211',
1581 '6' => '12111121',
1582 '7' => '12112111',
1583 '8' => '12211111',
1584 '9' => '21121111',
1585 '-' => '11122111',
1586 '$' => '11221111',
1587 ':' => '21112121',
1588 '/' => '21211121',
1589 '.' => '21212111',
1590 '+' => '11222221',
1591 'A' => '11221211',
1592 'B' => '12121121',
1593 'C' => '11121221',
1594 'D' => '11122211'
1595 );
1596 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1597 $k = 0;
1598 $w = 0;
1599 $seq = '';
1600 $code = strtoupper($code);
1601 $len = strlen($code);
1602 for ($i = 0; $i < $len; ++$i) {
1603 if (!isset($chr[$code[$i]])) {
1604 return false;
1605 }
1606 $seq = $chr[$code[$i]];
1607 for ($j = 0; $j < 8; ++$j) {
1608 if (($j % 2) == 0) {
1609 $t = true; // bar
1610 } else {
1611 $t = false; // space
1612 }
1613 $x = $seq[$j];
1614 if ($x == 2) { $w = $this->print_ratio; }
1615 else { $w = 1; }
1616 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1617 $bararray['maxw'] += $w;
1618 ++$k;
1619 }
1620 }
1621 return $bararray;
1622 }
1623
1624 /**
1625 * CODE11 barcodes.
1626 * Used primarily for labeling telecommunications equipment
1627 */
1628 protected function barcode_code11($code) {
1629 $chr = array(
1630 '0' => '111121',
1631 '1' => '211121',
1632 '2' => '121121',
1633 '3' => '221111',
1634 '4' => '112121',
1635 '5' => '212111',
1636 '6' => '122111',
1637 '7' => '111221',
1638 '8' => '211211',
1639 '9' => '211111',
1640 '-' => '112111',
1641 'S' => '112211'
1642 );
1643
1644 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => 1, 'bcode' => array());
1645 $k = 0;
1646 $w = 0;
1647 $seq = '';
1648 $len = strlen($code);
1649 // calculate check digit C
1650 $p = 1;
1651 $check = 0;
1652 for ($i = ($len - 1); $i >= 0; --$i) {
1653 $digit = $code[$i];
1654 if ($digit == '-') {
1655 $dval = 10;
1656 } else {
1657 $dval = intval($digit);
1658 }
1659 $check += ($dval * $p);
1660 ++$p;
1661 if ($p > 10) {
1662 $p = 1;
1663 }
1664 }
1665 $check %= 11;
1666 if ($check == 10) {
1667 $check = '-';
1668 }
1669 $code .= $check;
1670 $checkdigit = $check;
1671 if ($len > 10) {
1672 // calculate check digit K
1673 $p = 1;
1674 $check = 0;
1675 for ($i = $len; $i >= 0; --$i) {
1676 $digit = $code[$i];
1677 if ($digit == '-') {
1678 $dval = 10;
1679 } else {
1680 $dval = intval($digit);
1681 }
1682 $check += ($dval * $p);
1683 ++$p;
1684 if ($p > 9) {
1685 $p = 1;
1686 }
1687 }
1688 $check %= 11;
1689 $code .= $check;
1690 $checkdigit .= $check;
1691 ++$len;
1692 }
1693 $code = 'S'.$code.'S';
1694 $len += 3;
1695 for ($i = 0; $i < $len; ++$i) {
1696 if (!isset($chr[$code[$i]])) {
1697 return false;
1698 }
1699 $seq = $chr[$code[$i]];
1700 for ($j = 0; $j < 6; ++$j) {
1701 if (($j % 2) == 0) {
1702 $t = true; // bar
1703 } else {
1704 $t = false; // space
1705 }
1706 $x = $seq[$j];
1707 if ($x == 2) { $w = $this->print_ratio; }
1708 else { $w = 1; }
1709 $bararray['bcode'][$k] = array('t' => $t, 'w' => $w, 'h' => 1, 'p' => 0);
1710 $bararray['maxw'] += $w;
1711 ++$k;
1712 }
1713 }
1714 $bararray['checkdigit'] = $checkdigit;
1715 return $bararray;
1716 }
1717
1718
1719 /**
1720 * IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200
1721 * (requires PHP bcmath extension)
1722 * Intelligent Mail barcode is a 65-bar code for use on mail in the United States.
1723 * 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>
1724 */
1725 protected function barcode_imb($code) {
1726 $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);
1727 $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);
1728 $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);
1729 $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);
1730 $code_arr = explode('-', $code);
1731 $tracking_number = $code_arr[0];
1732 if (isset($code_arr[1])) {
1733 $routing_code = $code_arr[1];
1734 } else {
1735 $routing_code = '';
1736 }
1737 // Conversion of Routing Code
1738 switch (strlen($routing_code)) {
1739 case 0: {
1740 $binary_code = 0;
1741 break;
1742 }
1743 case 5: {
1744 $binary_code = bcadd($routing_code, '1');
1745 break;
1746 }
1747 case 9: {
1748 $binary_code = bcadd($routing_code, '100001');
1749 break;
1750 }
1751 case 11: {
1752 $binary_code = bcadd($routing_code, '1000100001');
1753 break;
1754 }
1755 default: {
1756 return false;
1757 break;
1758 }
1759 }
1760 $binary_code = bcmul($binary_code, 10);
1761 $binary_code = bcadd($binary_code, $tracking_number{0});
1762 $binary_code = bcmul($binary_code, 5);
1763 $binary_code = bcadd($binary_code, $tracking_number{1});
1764 $binary_code .= substr($tracking_number, 2, 18);
1765 // convert to hexadecimal
1766 $binary_code = $this->dec_to_hex($binary_code);
1767 // pad to get 13 bytes
1768 $binary_code = str_pad($binary_code, 26, '0', STR_PAD_LEFT);
1769 // convert string to array of bytes
1770 $binary_code_arr = chunk_split($binary_code, 2, "\r");
1771 $binary_code_arr = substr($binary_code_arr, 0, -1);
1772 $binary_code_arr = explode("\r", $binary_code_arr);
1773 // calculate frame check sequence
1774 $fcs = $this->imb_crc11fcs($binary_code_arr);
1775 // exclude first 2 bits from first byte
1776 $first_byte = sprintf('%2s', dechex((hexdec($binary_code_arr[0]) << 2) >> 2));
1777 $binary_code_102bit = $first_byte.substr($binary_code, 2);
1778 // convert binary data to codewords
1779 $codewords = array();
1780 $data = $this->hex_to_dec($binary_code_102bit);
1781 $codewords[0] = bcmod($data, 636) * 2;
1782 $data = bcdiv($data, 636);
1783 for ($i = 1; $i < 9; ++$i) {
1784 $codewords[$i] = bcmod($data, 1365);
1785 $data = bcdiv($data, 1365);
1786 }
1787 $codewords[9] = $data;
1788 if (($fcs >> 10) == 1) {
1789 $codewords[9] += 659;
1790 }
1791 // generate lookup tables
1792 $table2of13 = $this->imb_tables(2, 78);
1793 $table5of13 = $this->imb_tables(5, 1287);
1794 // convert codewords to characters
1795 $characters = array();
1796 $bitmask = 512;
1797 foreach($codewords as $k => $val) {
1798 if ($val <= 1286) {
1799 $chrcode = $table5of13[$val];
1800 } else {
1801 $chrcode = $table2of13[($val - 1287)];
1802 }
1803 if (($fcs & $bitmask) > 0) {
1804 // bitwise invert
1805 $chrcode = ((~$chrcode) & 8191);
1806 }
1807 $characters[] = $chrcode;
1808 $bitmask /= 2;
1809 }
1810 $characters = array_reverse($characters);
1811 // build bars
1812 $k = 0;
1813 $bararray = array('code' => $code, 'maxw' => 0, 'maxh' => $this->daft['F'], 'bcode' => array());
1814 for ($i = 0; $i < 65; ++$i) {
1815 $asc = (($characters[$asc_chr[$i]] & pow(2, $asc_pos[$i])) > 0);
1816 $dsc = (($characters[$dsc_chr[$i]] & pow(2, $dsc_pos[$i])) > 0);
1817 if ($asc AND $dsc) {
1818 // full bar (F)
1819 $p = 0;
1820 $h = $this->daft['F'];
1821 } elseif ($asc) {
1822 // ascender (A)
1823 $p = 0;
1824 $h = $this->daft['A'];
1825 } elseif ($dsc) {
1826 // descender (D)
1827 $p = $this->daft['F'] - $this->daft['D'];
1828 $h = $this->daft['D'];
1829 } else {
1830 // tracker (T)
1831 $p = ($this->daft['F'] - $this->daft['T'])/2;
1832 $h = $this->daft['T'];
1833 }
1834 $bararray['bcode'][$k++] = array('t' => 1, 'w' => 1, 'h' => $h, 'p' => $p);
1835 // Gap
1836 $bararray['bcode'][$k++] = array('t' => 0, 'w' => $this->gapwidth , 'h' => 1, 'p' => 0);
1837 $bararray['maxw'] += (1 + $this->gapwidth );
1838 }
1839 unset($bararray['bcode'][($k - 1)]);
1840 $bararray['maxw'] -= $this->gapwidth ;
1841 return $bararray;
1842 }
1843
1844 /**
1845 * Convert large integer number to hexadecimal representation.
1846 * (requires PHP bcmath extension)
1847 */
1848 public function dec_to_hex($number) {
1849 $i = 0;
1850 $hex = array();
1851 if($number == 0) {
1852 return '00';
1853 }
1854 while($number > 0) {
1855 if($number == 0) {
1856 array_push($hex, '0');
1857 } else {
1858 array_push($hex, strtoupper(dechex(bcmod($number, '16'))));
1859 $number = bcdiv($number, '16', 0);
1860 }
1861 }
1862 $hex = array_reverse($hex);
1863 return implode($hex);
1864 }
1865
1866 /**
1867 * Convert large hexadecimal number to decimal representation (string).
1868 * (requires PHP bcmath extension)
1869 */
1870 public function hex_to_dec($hex) {
1871 $dec = 0;
1872 $bitval = 1;
1873 $len = strlen($hex);
1874 for($pos = ($len - 1); $pos >= 0; --$pos) {
1875 $dec = bcadd($dec, bcmul(hexdec($hex[$pos]), $bitval));
1876 $bitval = bcmul($bitval, 16);
1877 }
1878 return $dec;
1879 }
1880
1881 /**
1882 * Intelligent Mail Barcode calculation of Frame Check Sequence
1883 */
1884 protected function imb_crc11fcs($code_arr) {
1885 $genpoly = 0x0F35; // generator polynomial
1886 $fcs = 0x07FF; // Frame Check Sequence
1887 // do most significant byte skipping the 2 most significant bits
1888 $data = hexdec($code_arr[0]) << 5;
1889 for ($bit = 2; $bit < 8; ++$bit) {
1890 if (($fcs ^ $data) & 0x400) {
1891 $fcs = ($fcs << 1) ^ $genpoly;
1892 } else {
1893 $fcs = ($fcs << 1);
1894 }
1895 $fcs &= 0x7FF;
1896 $data <<= 1;
1897 }
1898 // do rest of bytes
1899 for ($byte = 1; $byte < 13; ++$byte) {
1900 $data = hexdec($code_arr[$byte]) << 3;
1901 for ($bit = 0; $bit < 8; ++$bit) {
1902 if (($fcs ^ $data) & 0x400) {
1903 $fcs = ($fcs << 1) ^ $genpoly;
1904 } else {
1905 $fcs = ($fcs << 1);
1906 }
1907 $fcs &= 0x7FF;
1908 $data <<= 1;
1909 }
1910 }
1911 return $fcs;
1912 }
1913
1914 /**
1915 * Reverse unsigned short value
1916 */
1917 protected function imb_reverse_us($num) {
1918 $rev = 0;
1919 for ($i = 0; $i < 16; ++$i) {
1920 $rev <<= 1;
1921 $rev |= ($num & 1);
1922 $num >>= 1;
1923 }
1924 return $rev;
1925 }
1926
1927 /**
1928 * generate Nof13 tables used for Intelligent Mail Barcode
1929 */
1930 protected function imb_tables($n, $size) {
1931 $table = array();
1932 $lli = 0; // LUT lower index
1933 $lui = $size - 1; // LUT upper index
1934 for ($count = 0; $count < 8192; ++$count) {
1935 $bit_count = 0;
1936 for ($bit_index = 0; $bit_index < 13; ++$bit_index) {
1937 $bit_count += intval(($count & (1 << $bit_index)) != 0);
1938 }
1939 // if we don't have the right number of bits on, go on to the next value
1940 if ($bit_count == $n) {
1941 $reverse = ($this->imb_reverse_us($count) >> 3);
1942 // if the reverse is less than count, we have already visited this pair before
1943 if ($reverse >= $count) {
1944 // If count is symmetric, place it at the first free slot from the end of the list.
1945 // 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
1946 if ($reverse == $count) {
1947 $table[$lui] = $count;
1948 --$lui;
1949 } else {
1950 $table[$lli] = $count;
1951 ++$lli;
1952 $table[$lli] = $reverse;
1953 ++$lli;
1954 }
1955 }
1956 }
1957 }
1958 return $table;
1959 }
1960
1961} // end of class
1962
1963//============================================================+
1964// END OF FILE
1965//============================================================+
1966?> \ No newline at end of file
diff --git a/inc/3rdparty/libraries/mpdf/classes/bmp.php b/inc/3rdparty/libraries/mpdf/classes/bmp.php
deleted file mode 100644
index 896ced89..00000000
--- a/inc/3rdparty/libraries/mpdf/classes/bmp.php
+++ /dev/null
@@ -1,248 +0,0 @@
1<?php
2
3class bmp {
4
5var $mpdf = null;
6
7function bmp(&$mpdf) {
8 $this->mpdf = $mpdf;
9}
10
11
12function _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
145function _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
150function _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
158function 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
195function 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
deleted file mode 100644
index db325034..00000000
--- a/inc/3rdparty/libraries/mpdf/classes/cssmgr.php
+++ /dev/null
@@ -1,1572 +0,0 @@
1<?php
2
3class cssmgr {
4
5var $mpdf = null;
6
7var $tablecascadeCSS;
8var $listcascadeCSS;
9var $cascadeCSS;
10var $CSS;
11var $tbCSSlvl;
12var $listCSSlvl;
13
14
15function 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
26function 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
75function 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 // Replace any background: url(data:image... with temporary image file reference
225 preg_match_all("/(url\(data:image\/(jpeg|gif|png);base64,(.*?)\))/si", $CSSstr, $idata); // mPDF 5.7.2
226 if (count($idata[0])) {
227 for($i=0;$i<count($idata[0]);$i++) {
228 $file = _MPDF_TEMP_PATH.'_tempCSSidata'.RAND(1,10000).'_'.$i.'.'.$idata[2][$i];
229 //Save to local file
230 file_put_contents($file, base64_decode($idata[3][$i]));
231 // $this->mpdf->GetFullPath($file); // ? is this needed - NO mPDF 5.6.03
232 $CSSstr = str_replace($idata[0][$i], 'url("'.$file.'")', $CSSstr); // mPDF 5.5.17
233 }
234 }
235
236 $CSSstr = preg_replace('/(<\!\-\-|\-\->)/s',' ',$CSSstr);
237 if ($CSSstr ) {
238 preg_match_all('/(.*?)\{(.*?)\}/',$CSSstr,$styles);
239 for($i=0; $i < count($styles[1]) ; $i++) {
240 // SET array e.g. $classproperties['COLOR'] = '#ffffff';
241 $stylestr= trim($styles[2][$i]);
242 $stylearr = explode(';',$stylestr);
243 foreach($stylearr AS $sta) {
244 if (trim($sta)) {
245 // Changed to allow style="background: url('http://www.bpm1.com/bg.jpg')"
246 list($property,$value) = explode(':',$sta,2);
247 $property = trim($property);
248 $value = preg_replace('/\s*!important/i','',$value);
249 $value = trim($value);
250 if ($property && ($value || $value==='0')) {
251 // Ignores -webkit-gradient so doesn't override -moz-
252 if ((strtoupper($property)=='BACKGROUND-IMAGE' || strtoupper($property)=='BACKGROUND') && preg_match('/-webkit-gradient/i',$value)) {
253 continue;
254 }
255 $classproperties[strtoupper($property)] = $value;
256 }
257 }
258 }
259 $classproperties = $this->fixCSS($classproperties);
260 $tagstr = strtoupper(trim($styles[1][$i]));
261 $tagarr = explode(',',$tagstr);
262 $pageselectors = false; // used to turn on $this->mpdf->mirrorMargins
263 foreach($tagarr AS $tg) {
264 $tags = preg_split('/\s+/',trim($tg));
265 $level = count($tags);
266 $t = '';
267 $t2 = '';
268 $t3 = '';
269 if (trim($tags[0])=='@PAGE') {
270 if (isset($tags[0])) { $t = trim($tags[0]); }
271 if (isset($tags[1])) { $t2 = trim($tags[1]); }
272 if (isset($tags[2])) { $t3 = trim($tags[2]); }
273 $tag = '';
274 if ($level==1) { $tag = $t; }
275 else if ($level==2 && preg_match('/^[:](.*)$/',$t2,$m)) {
276 $tag = $t.'>>PSEUDO>>'.$m[1];
277 if ($m[1]=='LEFT' || $m[1]=='RIGHT') { $pageselectors = true; } // used to turn on $this->mpdf->mirrorMargins
278 }
279 else if ($level==2) { $tag = $t.'>>NAMED>>'.$t2; }
280 else if ($level==3 && preg_match('/^[:](.*)$/',$t3,$m)) {
281 $tag = $t.'>>NAMED>>'.$t2.'>>PSEUDO>>'.$m[1];
282 if ($m[1]=='LEFT' || $m[1]=='RIGHT') { $pageselectors = true; } // used to turn on $this->mpdf->mirrorMargins
283 }
284 if (isset($this->CSS[$tag]) && $tag) { $this->CSS[$tag] = $this->array_merge_recursive_unique($this->CSS[$tag], $classproperties); }
285 else if ($tag) { $this->CSS[$tag] = $classproperties; }
286 }
287
288 else if ($level == 1) { // e.g. p or .class or #id or p.class or p#id
289 if (isset($tags[0])) { $t = trim($tags[0]); }
290 if ($t) {
291 $tag = '';
292 if (preg_match('/^[.](.*)$/',$t,$m)) { $tag = 'CLASS>>'.$m[1]; }
293 else if (preg_match('/^[#](.*)$/',$t,$m)) { $tag = 'ID>>'.$m[1]; }
294 else if (preg_match('/^('.$this->mpdf->allowedCSStags.')[.](.*)$/',$t,$m)) { $tag = $m[1].'>>CLASS>>'.$m[2]; }
295 else if (preg_match('/^('.$this->mpdf->allowedCSStags.')\s*:NTH-CHILD\((.*)\)$/',$t,$m)) { $tag = $m[1].'>>SELECTORNTHCHILD>>'.$m[2]; }
296 else if (preg_match('/^('.$this->mpdf->allowedCSStags.')[#](.*)$/',$t,$m)) { $tag = $m[1].'>>ID>>'.$m[2]; }
297 else if (preg_match('/^('.$this->mpdf->allowedCSStags.')$/',$t)) { $tag= $t; }
298 if (isset($this->CSS[$tag]) && $tag) { $this->CSS[$tag] = $this->array_merge_recursive_unique($this->CSS[$tag], $classproperties); }
299 else if ($tag) { $this->CSS[$tag] = $classproperties; }
300 }
301 }
302 else {
303 $tmp = array();
304 for($n=0;$n<$level;$n++) {
305 if (isset($tags[$n])) { $t = trim($tags[$n]); }
306 else { $t = ''; }
307 if ($t) {
308 $tag = '';
309 if (preg_match('/^[.](.*)$/',$t,$m)) { $tag = 'CLASS>>'.$m[1]; }
310 else if (preg_match('/^[#](.*)$/',$t,$m)) { $tag = 'ID>>'.$m[1]; }
311 else if (preg_match('/^('.$this->mpdf->allowedCSStags.')[.](.*)$/',$t,$m)) { $tag = $m[1].'>>CLASS>>'.$m[2]; }
312 else if (preg_match('/^('.$this->mpdf->allowedCSStags.')\s*:NTH-CHILD\((.*)\)$/',$t,$m)) { $tag = $m[1].'>>SELECTORNTHCHILD>>'.$m[2]; }
313 else if (preg_match('/^('.$this->mpdf->allowedCSStags.')[#](.*)$/',$t,$m)) { $tag = $m[1].'>>ID>>'.$m[2]; }
314 else if (preg_match('/^('.$this->mpdf->allowedCSStags.')$/',$t)) { $tag= $t; }
315
316 if ($tag) $tmp[] = $tag;
317 else { break; }
318 }
319 }
320
321 if ($tag) {
322 $x = &$this->cascadeCSS;
323 foreach($tmp AS $tp) { $x = &$x[$tp]; }
324 $x = $this->array_merge_recursive_unique($x, $classproperties);
325 $x['depth'] = $level;
326 }
327 }
328 }
329 if ($pageselectors) { $this->mpdf->mirrorMargins = true; }
330 $properties = array();
331 $values = array();
332 $classproperties = array();
333 }
334 } // end of if
335 //Remove CSS (tags and content), if any
336 $regexp = '/<style.*?>(.*?)<\/style>/si'; // it can be <style> or <style type="txt/css">
337 $html = preg_replace($regexp,'',$html);
338//print_r($this->CSS); exit;
339//print_r($this->cascadeCSS); exit;
340 return $html;
341}
342
343
344
345function readInlineCSS($html) {
346 //Fix incomplete CSS code
347 $size = strlen($html)-1;
348 if (substr($html,$size,1) != ';') $html .= ';';
349 //Make CSS[Name-of-the-class] = array(key => value)
350 $regexp = '|\\s*?(\\S+?):(.+?);|i';
351 preg_match_all( $regexp, $html, $styleinfo);
352 $properties = $styleinfo[1];
353 $values = $styleinfo[2];
354 //Array-properties and Array-values must have the SAME SIZE!
355 $classproperties = array();
356 for($i = 0; $i < count($properties) ; $i++) {
357 // Ignores -webkit-gradient so doesn't override -moz-
358 if ((strtoupper($properties[$i])=='BACKGROUND-IMAGE' || strtoupper($properties[$i])=='BACKGROUND') && preg_match('/-webkit-gradient/i',$values[$i])) {
359 continue;
360 }
361 $classproperties[strtoupper($properties[$i])] = trim($values[$i]);
362 }
363 return $this->fixCSS($classproperties);
364}
365
366
367
368function _fix_borderStr($bd) {
369 preg_match_all("/\((.*?)\)/", $bd, $m);
370 if (count($m[1])) {
371 for($i=0;$i<count($m[1]);$i++) {
372 $sub = preg_replace("/ /", "", $m[1][$i]);
373 $bd = preg_replace('/'.preg_quote($m[1][$i], '/').'/si', $sub, $bd);
374 }
375 }
376
377 $prop = preg_split('/\s+/',trim($bd));
378 $w = 'medium';
379 $c = '#000000';
380 $s = 'none';
381
382 if ( count($prop) == 1 ) {
383 // solid
384 if (in_array($prop[0],$this->mpdf->borderstyles) || $prop[0] == 'none' || $prop[0] == 'hidden' ) { $s = $prop[0]; }
385 // #000000
386 else if (is_array($this->mpdf->ConvertColor($prop[0]))) { $c = $prop[0]; }
387 // 1px
388 else { $w = $prop[0]; }
389 }
390 else if (count($prop) == 2 ) {
391 // 1px solid
392 if (in_array($prop[1],$this->mpdf->borderstyles) || $prop[1] == 'none' || $prop[1] == 'hidden' ) { $w = $prop[0]; $s = $prop[1]; }
393 // solid #000000
394 else if (in_array($prop[0],$this->mpdf->borderstyles) || $prop[0] == 'none' || $prop[0] == 'hidden' ) { $s = $prop[0]; $c = $prop[1]; }
395 // 1px #000000
396 else { $w = $prop[0]; $c = $prop[1]; }
397 }
398 else if ( count($prop) == 3 ) {
399 // Change #000000 1px solid to 1px solid #000000 (proper)
400 if (substr($prop[0],0,1) == '#') { $c = $prop[0]; $w = $prop[1]; $s = $prop[2]; }
401 // Change solid #000000 1px to 1px solid #000000 (proper)
402 else if (substr($prop[0],1,1) == '#') { $s = $prop[0]; $c = $prop[1]; $w = $prop[2]; }
403 // Change solid 1px #000000 to 1px solid #000000 (proper)
404 else if (in_array($prop[0],$this->mpdf->borderstyles) || $prop[0] == 'none' || $prop[0] == 'hidden' ) {
405 $s = $prop[0]; $w = $prop[1]; $c = $prop[2];
406 }
407 else { $w = $prop[0]; $s = $prop[1]; $c = $prop[2]; }
408 }
409 else { return ''; }
410 $s = strtolower($s);
411 return $w.' '.$s.' '.$c;
412}
413
414
415
416function fixCSS($prop) {
417 if (!is_array($prop) || (count($prop)==0)) return array();
418 $newprop = array();
419 foreach($prop AS $k => $v) {
420 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') {
421 $v = strtolower($v);
422 }
423
424 if ($k == 'FONT') {
425 $s = trim($v);
426 preg_match_all('/\"(.*?)\"/',$s,$ff);
427 if (count($ff[1])) {
428 foreach($ff[1] AS $ffp) {
429 $w = preg_split('/\s+/',$ffp);
430 $s = preg_replace('/\"'.$ffp.'\"/',$w[0],$s);
431 }
432 }
433 preg_match_all('/\'(.*?)\'/',$s,$ff);
434 if (count($ff[1])) {
435 foreach($ff[1] AS $ffp) {
436 $w = preg_split('/\s+/',$ffp);
437 $s = preg_replace('/\''.$ffp.'\'/',$w[0],$s);
438 }
439 }
440 $s = preg_replace('/\s*,\s*/',',',$s);
441 $bits = preg_split('/\s+/',$s);
442 if (count($bits)>1) {
443 $k = 'FONT-FAMILY'; $v = $bits[(count($bits)-1)];
444 $fs = $bits[(count($bits)-2)];
445 if (preg_match('/(.*?)\/(.*)/',$fs, $fsp)) {
446 $newprop['FONT-SIZE'] = $fsp[1];
447 $newprop['LINE-HEIGHT'] = $fsp[2];
448 }
449 else { $newprop['FONT-SIZE'] = $fs; }
450 if (preg_match('/(italic|oblique)/i',$s)) { $newprop['FONT-STYLE'] = 'italic'; }
451 else { $newprop['FONT-STYLE'] = 'normal'; }
452 if (preg_match('/bold/i',$s)) { $newprop['FONT-WEIGHT'] = 'bold'; }
453 else { $newprop['FONT-WEIGHT'] = 'normal'; }
454 if (preg_match('/small-caps/i',$s)) { $newprop['TEXT-TRANSFORM'] = 'uppercase'; }
455 }
456 }
457 if ($k == 'FONT-FAMILY') {
458 $aux_fontlist = explode(",",$v);
459 $found = 0;
460 foreach($aux_fontlist AS $f) {
461 $fonttype = trim($f);
462 $fonttype = preg_replace('/["\']*(.*?)["\']*/','\\1',$fonttype);
463 $fonttype = preg_replace('/ /','',$fonttype);
464 $v = strtolower(trim($fonttype));
465 if (isset($this->mpdf->fonttrans[$v]) && $this->mpdf->fonttrans[$v]) { $v = $this->mpdf->fonttrans[$v]; }
466 if ((!$this->mpdf->onlyCoreFonts && in_array($v,$this->mpdf->available_unifonts)) ||
467 in_array($v,array('ccourier','ctimes','chelvetica')) ||
468 ($this->mpdf->onlyCoreFonts && in_array($v,array('courier','times','helvetica','arial'))) ||
469 in_array($v, array('sjis','uhc','big5','gb'))) {
470 $newprop[$k] = $v;
471 $found = 1;
472 break;
473 }
474 }
475 if (!$found) {
476 foreach($aux_fontlist AS $f) {
477 $fonttype = trim($f);
478 $fonttype = preg_replace('/["\']*(.*?)["\']*/','\\1',$fonttype);
479 $fonttype = preg_replace('/ /','',$fonttype);
480 $v = strtolower(trim($fonttype));
481 if (isset($this->mpdf->fonttrans[$v]) && $this->mpdf->fonttrans[$v]) { $v = $this->mpdf->fonttrans[$v]; }
482 if (in_array($v,$this->mpdf->sans_fonts) || in_array($v,$this->mpdf->serif_fonts) || in_array($v,$this->mpdf->mono_fonts) ) {
483 $newprop[$k] = $v;
484 break;
485 }
486 }
487 }
488 }
489 else if ($k == 'MARGIN') {
490 $tmp = $this->expand24($v);
491 $newprop['MARGIN-TOP'] = $tmp['T'];
492 $newprop['MARGIN-RIGHT'] = $tmp['R'];
493 $newprop['MARGIN-BOTTOM'] = $tmp['B'];
494 $newprop['MARGIN-LEFT'] = $tmp['L'];
495 }
496/*-- BORDER-RADIUS --*/
497 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') {
498 $tmp = $this->border_radius_expand($v,$k);
499 if (isset($tmp['TL-H'])) $newprop['BORDER-TOP-LEFT-RADIUS-H'] = $tmp['TL-H'];
500 if (isset($tmp['TL-V'])) $newprop['BORDER-TOP-LEFT-RADIUS-V'] = $tmp['TL-V'];
501 if (isset($tmp['TR-H'])) $newprop['BORDER-TOP-RIGHT-RADIUS-H'] = $tmp['TR-H'];
502 if (isset($tmp['TR-V'])) $newprop['BORDER-TOP-RIGHT-RADIUS-V'] = $tmp['TR-V'];
503 if (isset($tmp['BL-H'])) $newprop['BORDER-BOTTOM-LEFT-RADIUS-H'] = $tmp['BL-H'];
504 if (isset($tmp['BL-V'])) $newprop['BORDER-BOTTOM-LEFT-RADIUS-V'] = $tmp['BL-V'];
505 if (isset($tmp['BR-H'])) $newprop['BORDER-BOTTOM-RIGHT-RADIUS-H'] = $tmp['BR-H'];
506 if (isset($tmp['BR-V'])) $newprop['BORDER-BOTTOM-RIGHT-RADIUS-V'] = $tmp['BR-V'];
507 }
508/*-- END BORDER-RADIUS --*/
509 else if ($k == 'PADDING') {
510 $tmp = $this->expand24($v);
511 $newprop['PADDING-TOP'] = $tmp['T'];
512 $newprop['PADDING-RIGHT'] = $tmp['R'];
513 $newprop['PADDING-BOTTOM'] = $tmp['B'];
514 $newprop['PADDING-LEFT'] = $tmp['L'];
515 }
516 else if ($k == 'BORDER') {
517 if ($v == '1') { $v = '1px solid #000000'; }
518 else { $v = $this->_fix_borderStr($v); }
519 $newprop['BORDER-TOP'] = $v;
520 $newprop['BORDER-RIGHT'] = $v;
521 $newprop['BORDER-BOTTOM'] = $v;
522 $newprop['BORDER-LEFT'] = $v;
523 }
524 else if ($k == 'BORDER-TOP') {
525 $newprop['BORDER-TOP'] = $this->_fix_borderStr($v);
526 }
527 else if ($k == 'BORDER-RIGHT') {
528 $newprop['BORDER-RIGHT'] = $this->_fix_borderStr($v);
529 }
530 else if ($k == 'BORDER-BOTTOM') {
531 $newprop['BORDER-BOTTOM'] = $this->_fix_borderStr($v);
532 }
533 else if ($k == 'BORDER-LEFT') {
534 $newprop['BORDER-LEFT'] = $this->_fix_borderStr($v);
535 }
536 else if ($k == 'BORDER-STYLE') {
537 $e = $this->expand24($v);
538 $newprop['BORDER-TOP-STYLE'] = $e['T'];
539 $newprop['BORDER-RIGHT-STYLE'] = $e['R'];
540 $newprop['BORDER-BOTTOM-STYLE'] = $e['B'];
541 $newprop['BORDER-LEFT-STYLE'] = $e['L'];
542 }
543 else if ($k == 'BORDER-WIDTH') {
544 $e = $this->expand24($v);
545 $newprop['BORDER-TOP-WIDTH'] = $e['T'];
546 $newprop['BORDER-RIGHT-WIDTH'] = $e['R'];
547 $newprop['BORDER-BOTTOM-WIDTH'] = $e['B'];
548 $newprop['BORDER-LEFT-WIDTH'] = $e['L'];
549 }
550 else if ($k == 'BORDER-COLOR') {
551 $e = $this->expand24($v);
552 $newprop['BORDER-TOP-COLOR'] = $e['T'];
553 $newprop['BORDER-RIGHT-COLOR'] = $e['R'];
554 $newprop['BORDER-BOTTOM-COLOR'] = $e['B'];
555 $newprop['BORDER-LEFT-COLOR'] = $e['L'];
556 }
557
558 else if ($k == 'BORDER-SPACING') {
559 $prop = preg_split('/\s+/',trim($v));
560 if (count($prop) == 1 ) {
561 $newprop['BORDER-SPACING-H'] = $prop[0];
562 $newprop['BORDER-SPACING-V'] = $prop[0];
563 }
564 else if (count($prop) == 2 ) {
565 $newprop['BORDER-SPACING-H'] = $prop[0];
566 $newprop['BORDER-SPACING-V'] = $prop[1];
567 }
568 }
569 else if ($k == 'TEXT-OUTLINE') { // mPDF 5.6.07
570 $prop = preg_split('/\s+/',trim($v));
571 if (trim(strtolower($v)) == 'none' ) {
572 $newprop['TEXT-OUTLINE'] = 'none';
573 }
574 else if (count($prop) == 2 ) {
575 $newprop['TEXT-OUTLINE-WIDTH'] = $prop[0];
576 $newprop['TEXT-OUTLINE-COLOR'] = $prop[1];
577 }
578 else if (count($prop) == 3 ) {
579 $newprop['TEXT-OUTLINE-WIDTH'] = $prop[0];
580 $newprop['TEXT-OUTLINE-COLOR'] = $prop[2];
581 }
582 }
583 else if ($k == 'SIZE') {
584 $prop = preg_split('/\s+/',trim($v));
585 if (preg_match('/(auto|portrait|landscape)/',$prop[0])) {
586 $newprop['SIZE'] = strtoupper($prop[0]);
587 }
588 else if (count($prop) == 1 ) {
589 $newprop['SIZE']['W'] = $this->mpdf->ConvertSize($prop[0]);
590 $newprop['SIZE']['H'] = $this->mpdf->ConvertSize($prop[0]);
591 }
592 else if (count($prop) == 2 ) {
593 $newprop['SIZE']['W'] = $this->mpdf->ConvertSize($prop[0]);
594 $newprop['SIZE']['H'] = $this->mpdf->ConvertSize($prop[1]);
595 }
596 }
597 else if ($k == 'SHEET-SIZE') {
598 $prop = preg_split('/\s+/',trim($v));
599 if (count($prop) == 2 ) {
600 $newprop['SHEET-SIZE'] = array($this->mpdf->ConvertSize($prop[0]), $this->mpdf->ConvertSize($prop[1]));
601 }
602 else {
603 if(preg_match('/([0-9a-zA-Z]*)-L/i',$v,$m)) { // e.g. A4-L = A$ landscape
604 $ft = $this->mpdf->_getPageFormat($m[1]);
605 $format = array($ft[1],$ft[0]);
606 }
607 else { $format = $this->mpdf->_getPageFormat($v); }
608 if ($format) { $newprop['SHEET-SIZE'] = array($format[0]/_MPDFK, $format[1]/_MPDFK); }
609 }
610 }
611 else if ($k == 'BACKGROUND') {
612 $bg = $this->parseCSSbackground($v);
613 if ($bg['c']) { $newprop['BACKGROUND-COLOR'] = $bg['c']; }
614 else { $newprop['BACKGROUND-COLOR'] = 'transparent'; }
615/*-- BACKGROUNDS --*/
616 if ($bg['i']) {
617 $newprop['BACKGROUND-IMAGE'] = $bg['i'];
618 if ($bg['r']) { $newprop['BACKGROUND-REPEAT'] = $bg['r']; }
619 if ($bg['p']) { $newprop['BACKGROUND-POSITION'] = $bg['p']; }
620 }
621 else { $newprop['BACKGROUND-IMAGE'] = ''; }
622/*-- END BACKGROUNDS --*/
623 }
624/*-- BACKGROUNDS --*/
625 else if ($k == 'BACKGROUND-IMAGE') {
626 if (preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient\(.*\)/i',$v,$m)) {
627 $newprop['BACKGROUND-IMAGE'] = $m[0];
628 continue;
629 }
630 if (preg_match('/url\([\'\"]{0,1}(.*?)[\'\"]{0,1}\)/i',$v,$m)) {
631 $newprop['BACKGROUND-IMAGE'] = $m[1];
632 }
633
634 else if (strtolower($v)=='none') { $newprop['BACKGROUND-IMAGE'] = ''; }
635
636 }
637 else if ($k == 'BACKGROUND-REPEAT') {
638 if (preg_match('/(repeat-x|repeat-y|no-repeat|repeat)/i',$v,$m)) {
639 $newprop['BACKGROUND-REPEAT'] = strtolower($m[1]);
640 }
641 }
642 else if ($k == 'BACKGROUND-POSITION') {
643 $s = $v;
644 $bits = preg_split('/\s+/',trim($s));
645 // These should be Position x1 or x2
646 if (count($bits)==1) {
647 if (preg_match('/bottom/',$bits[0])) { $bg['p'] = '50% 100%'; }
648 else if (preg_match('/top/',$bits[0])) { $bg['p'] = '50% 0%'; }
649 else { $bg['p'] = $bits[0] . ' 50%'; }
650 }
651 else if (count($bits)==2) {
652 // Can be either right center or center right
653 if (preg_match('/(top|bottom)/',$bits[0]) || preg_match('/(left|right)/',$bits[1])) {
654 $bg['p'] = $bits[1] . ' '.$bits[0];
655 }
656 else {
657 $bg['p'] = $bits[0] . ' '.$bits[1];
658 }
659 }
660 if ($bg['p']) {
661 $bg['p'] = preg_replace('/(left|top)/','0%',$bg['p']);
662 $bg['p'] = preg_replace('/(right|bottom)/','100%',$bg['p']);
663 $bg['p'] = preg_replace('/(center)/','50%',$bg['p']);
664 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'])) {
665 $bg['p'] = false;
666 }
667 }
668 if ($bg['p']) { $newprop['BACKGROUND-POSITION'] = $bg['p']; }
669 }
670/*-- END BACKGROUNDS --*/
671 else if ($k == 'IMAGE-ORIENTATION') {
672 if (preg_match('/([\-]*[0-9\.]+)(deg|grad|rad)/i',$v,$m)) {
673 $angle = $m[1] + 0;
674 if (strtolower($m[2])=='deg') { $angle = $angle; }
675 else if (strtolower($m[2])=='grad') { $angle *= (360/400); }
676 else if (strtolower($m[2])=='rad') { $angle = rad2deg($angle); }
677 while($angle < 0) { $angle += 360; }
678 $angle = ($angle % 360);
679 $angle /= 90;
680 $angle = round($angle) * 90;
681 $newprop['IMAGE-ORIENTATION'] = $angle;
682 }
683 }
684 // mPDF 5.6.13
685 else if ($k == 'TEXT-ALIGN') {
686 if (preg_match('/["\'](.){1}["\']/i',$v,$m)) {
687 $d = array_search($m[1],$this->mpdf->decimal_align);
688 if ($d !== false) { $newprop['TEXT-ALIGN'] = $d; }
689 if (preg_match('/(center|left|right)/i',$v,$m)) { $newprop['TEXT-ALIGN'] .= strtoupper(substr($m[1],0,1)); }
690 else { $newprop['TEXT-ALIGN'] .= 'R'; } // default = R
691 }
692 else if (preg_match('/["\'](\\\[a-fA-F0-9]{1,6})["\']/i',$v,$m)) {
693 $utf8 = codeHex2utf(substr($m[1],1,6));
694 $d = array_search($utf8,$this->mpdf->decimal_align);
695 if ($d !== false) { $newprop['TEXT-ALIGN'] = $d; }
696 if (preg_match('/(center|left|right)/i',$v,$m)) { $newprop['TEXT-ALIGN'] .= strtoupper(substr($m[1],0,1)); }
697 else { $newprop['TEXT-ALIGN'] .= 'R'; } // default = R
698 }
699 else { $newprop[$k] = $v; }
700 }
701 else if ($k == 'LIST-STYLE') { // mPDF 5.7.2
702 if (preg_match('/(lower-roman|upper-roman|lower-latin|lower-alpha|upper-latin|upper-alpha|none|decimal|disc|circle|square|arabic-indic|bengali|devanagari|gujarati|gurmukhi|kannada|malayalam|oriya|persian|tamil|telugu|thai|urdu|cambodian|khmer|lao)/i',$v,$m)
703 || preg_match('/U\+([a-fA-F0-9]+)/i',$v,$m)) {
704 $newprop['LIST-STYLE-TYPE'] = strtolower(trim($m[1]));
705 }
706 }
707
708
709 else {
710 $newprop[$k] = $v;
711 }
712 }
713
714 return $newprop;
715}
716
717function setCSSboxshadow($v) {
718 $sh = array();
719 $c = preg_match_all('/(rgba|rgb|device-cmyka|cmyka|device-cmyk|cmyk|hsla|hsl)\(.*?\)/',$v,$x); // mPDF 5.6.05
720 for($i=0; $i<$c; $i++) {
721 $col = preg_replace('/,/','*',$x[0][$i]);
722 $v = preg_replace('/'.preg_quote($x[0][$i],'/').'/',$col,$v);
723 }
724 $ss = explode(',',$v);
725 foreach ($ss AS $s) {
726 $new = array('inset'=>false, 'blur'=>0, 'spread'=>0);
727 if (preg_match('/inset/i',$s)) { $new['inset'] = true; $s = preg_replace('/\s*inset\s*/','',$s); }
728 $p = explode(' ',trim($s));
729 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); }
730 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); }
731 if (isset($p[2])) {
732 if (preg_match('/^\s*[\.\-0-9]/',$p[2])) {
733 $new['blur'] = $this->mpdf->ConvertSize(trim($p[2]),$this->mpdf->blk[$this->mpdf->blklvl-1]['inner_width'],$this->mpdf->FontSize,false);
734 }
735 else { $new['col'] = $this->mpdf->ConvertColor(preg_replace('/\*/',',',$p[2])); }
736 if (isset($p[3])) {
737 if (preg_match('/^\s*[\.\-0-9]/',$p[3])) {
738 $new['spread'] = $this->mpdf->ConvertSize(trim($p[3]),$this->mpdf->blk[$this->mpdf->blklvl-1]['inner_width'],$this->mpdf->FontSize,false);
739 }
740 else { $new['col'] = $this->mpdf->ConvertColor(preg_replace('/\*/',',',$p[3])); }
741 if (isset($p[4])) {
742 $new['col'] = $this->mpdf->ConvertColor(preg_replace('/\*/',',',$p[4]));
743 }
744 }
745 }
746 if (!$new['col']) { $new['col'] = $this->mpdf->ConvertColor('#888888'); }
747 if (isset($new['y'])) { array_unshift($sh, $new); }
748 }
749 return $sh;
750}
751
752function setCSStextshadow($v) {
753 $sh = array();
754 $c = preg_match_all('/(rgba|rgb|device-cmyka|cmyka|device-cmyk|cmyk|hsla|hsl)\(.*?\)/',$v,$x); // mPDF 5.6.05
755 for($i=0; $i<$c; $i++) {
756 $col = preg_replace('/,/','*',$x[0][$i]);
757 $v = preg_replace('/'.preg_quote($x[0][$i],'/').'/',$col,$v);
758 }
759 $ss = explode(',',$v);
760 foreach ($ss AS $s) {
761 $new = array('blur'=>0);
762 $p = explode(' ',trim($s));
763 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); }
764 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); }
765 if (isset($p[2])) {
766 if (preg_match('/^\s*[\.\-0-9]/',$p[2])) {
767 $new['blur'] = $this->mpdf->ConvertSize(trim($p[2]),$this->mpdf->blk[$this->mpdf->blklvl-1]['inner_width'],$this->mpdf->FontSize,false);
768 }
769 else { $new['col'] = $this->mpdf->ConvertColor(preg_replace('/\*/',',',$p[2])); }
770 if (isset($p[3])) {
771 $new['col'] = $this->mpdf->ConvertColor(preg_replace('/\*/',',',$p[3]));
772 }
773 }
774 if (!$new['col']) { $new['col'] = $this->mpdf->ConvertColor('#888888'); }
775 if (isset($new['y'])) { array_unshift($sh, $new); }
776 }
777 return $sh;
778}
779
780function parseCSSbackground($s) {
781 $bg = array('c'=>false, 'i'=>false, 'r'=>false, 'p'=>false, );
782/*-- BACKGROUNDS --*/
783 if (preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient\(.*\)/i',$s,$m)) {
784 $bg['i'] = $m[0];
785 }
786 else
787/*-- END BACKGROUNDS --*/
788 if (preg_match('/url\(/i',$s)) {
789 // If color, set and strip it off
790 // mPDF 5.6.05
791 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)) {
792 $bg['c'] = strtolower($m[1]);
793 $s = $m[3];
794 }
795/*-- BACKGROUNDS --*/
796 if (preg_match('/url\([\'\"]{0,1}(.*?)[\'\"]{0,1}\)\s*(.*)/i',$s,$m)) {
797 $bg['i'] = $m[1];
798 $s = strtolower($m[2]);
799 if (preg_match('/(repeat-x|repeat-y|no-repeat|repeat)/',$s,$m)) {
800 $bg['r'] = $m[1];
801 }
802 // Remove repeat, attachment (discarded) and also any inherit
803 $s = preg_replace('/(repeat-x|repeat-y|no-repeat|repeat|scroll|fixed|inherit)/','',$s);
804 $bits = preg_split('/\s+/',trim($s));
805 // These should be Position x1 or x2
806 if (count($bits)==1) {
807 if (preg_match('/bottom/',$bits[0])) { $bg['p'] = '50% 100%'; }
808 else if (preg_match('/top/',$bits[0])) { $bg['p'] = '50% 0%'; }
809 else { $bg['p'] = $bits[0] . ' 50%'; }
810 }
811 else if (count($bits)==2) {
812 // Can be either right center or center right
813 if (preg_match('/(top|bottom)/',$bits[0]) || preg_match('/(left|right)/',$bits[1])) {
814 $bg['p'] = $bits[1] . ' '.$bits[0];
815 }
816 else {
817 $bg['p'] = $bits[0] . ' '.$bits[1];
818 }
819 }
820 if ($bg['p']) {
821 $bg['p'] = preg_replace('/(left|top)/','0%',$bg['p']);
822 $bg['p'] = preg_replace('/(right|bottom)/','100%',$bg['p']);
823 $bg['p'] = preg_replace('/(center)/','50%',$bg['p']);
824 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'])) {
825 $bg['p'] = false;
826 }
827 }
828 }
829/*-- END BACKGROUNDS --*/
830 }
831 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
832 return ($bg);
833}
834
835
836function expand24($mp) {
837 $prop = preg_split('/\s+/',trim($mp));
838 if (count($prop) == 1 ) {
839 return array('T' => $prop[0], 'R' => $prop[0], 'B' => $prop[0], 'L'=> $prop[0]);
840 }
841 if (count($prop) == 2 ) {
842 return array('T' => $prop[0], 'R' => $prop[1], 'B' => $prop[0], 'L'=> $prop[1]);
843 }
844
845 if (count($prop) == 3 ) {
846 return array('T' => $prop[0], 'R' => $prop[1], 'B' => $prop[2], 'L'=> $prop[1]);
847 }
848 if (count($prop) == 4 ) {
849 return array('T' => $prop[0], 'R' => $prop[1], 'B' => $prop[2], 'L'=> $prop[3]);
850 }
851 return array();
852}
853
854/*-- BORDER-RADIUS --*/
855function border_radius_expand($val,$k) {
856 $b = array();
857 if ($k == 'BORDER-RADIUS') {
858 $hv = explode('/',trim($val));
859 $prop = preg_split('/\s+/',trim($hv[0]));
860 if (count($prop)==1) {
861 $b['TL-H'] = $b['TR-H'] = $b['BR-H'] = $b['BL-H'] = $prop[0];
862 }
863 else if (count($prop)==2) {
864 $b['TL-H'] = $b['BR-H'] = $prop[0];
865 $b['TR-H'] = $b['BL-H'] = $prop[1];
866 }
867 else if (count($prop)==3) {
868 $b['TL-H'] = $prop[0];
869 $b['TR-H'] = $b['BL-H'] = $prop[1];
870 $b['BR-H'] = $prop[2];
871 }
872 else if (count($prop)==4) {
873 $b['TL-H'] = $prop[0];
874 $b['TR-H'] = $prop[1];
875 $b['BR-H'] = $prop[2];
876 $b['BL-H'] = $prop[3];
877 }
878 if (count($hv)==2) {
879 $prop = preg_split('/\s+/',trim($hv[1]));
880 if (count($prop)==1) {
881 $b['TL-V'] = $b['TR-V'] = $b['BR-V'] = $b['BL-V'] = $prop[0];
882 }
883 else if (count($prop)==2) {
884 $b['TL-V'] = $b['BR-V'] = $prop[0];
885 $b['TR-V'] = $b['BL-V'] = $prop[1];
886 }
887 else if (count($prop)==3) {
888 $b['TL-V'] = $prop[0];
889 $b['TR-V'] = $b['BL-V'] = $prop[1];
890 $b['BR-V'] = $prop[2];
891 }
892 else if (count($prop)==4) {
893 $b['TL-V'] = $prop[0];
894 $b['TR-V'] = $prop[1];
895 $b['BR-V'] = $prop[2];
896 $b['BL-V'] = $prop[3];
897 }
898 }
899 else {
900 $b['TL-V'] = $b['TL-H'];
901 $b['TR-V'] = $b['TR-H'];
902 $b['BL-V'] = $b['BL-H'];
903 $b['BR-V'] = $b['BR-H'];
904 }
905 return $b;
906 }
907
908 // Parse 2
909 $h = 0;
910 $v = 0;
911 $prop = preg_split('/\s+/',trim($val));
912 if (count($prop)==1) { $h = $v = $val; }
913 else { $h = $prop[0]; $v = $prop[1]; }
914 if ($h==0 || $v==0) { $h = $v = 0; }
915 if ($k == 'BORDER-TOP-LEFT-RADIUS') {
916 $b['TL-H'] = $h;
917 $b['TL-V'] = $v;
918 }
919 else if ($k == 'BORDER-TOP-RIGHT-RADIUS') {
920 $b['TR-H'] = $h;
921 $b['TR-V'] = $v;
922 }
923 else if ($k == 'BORDER-BOTTOM-LEFT-RADIUS') {
924 $b['BL-H'] = $h;
925 $b['BL-V'] = $v;
926 }
927 else if ($k == 'BORDER-BOTTOM-RIGHT-RADIUS') {
928 $b['BR-H'] = $h;
929 $b['BR-V'] = $v;
930 }
931 return $b;
932
933}
934/*-- END BORDER-RADIUS --*/
935
936function _mergeCSS($p, &$t) {
937 // Save Cascading CSS e.g. "div.topic p" at this block level
938 if (isset($p) && $p) {
939 if ($t) {
940 $t = $this->array_merge_recursive_unique($t, $p);
941 }
942 else { $t = $p; }
943 }
944}
945
946// for CSS handling
947function array_merge_recursive_unique($array1, $array2) {
948 $arrays = func_get_args();
949 $narrays = count($arrays);
950 $ret = $arrays[0];
951 for ($i = 1; $i < $narrays; $i ++) {
952 foreach ($arrays[$i] as $key => $value) {
953 if (((string) $key) === ((string) intval($key))) { // integer or string as integer key - append
954 $ret[] = $value;
955 }
956 else { // string key - merge
957 if (is_array($value) && isset($ret[$key])) {
958 $ret[$key] = $this->array_merge_recursive_unique($ret[$key], $value);
959 }
960 else {
961 $ret[$key] = $value;
962 }
963 }
964 }
965 }
966 return $ret;
967}
968
969
970
971function _mergeFullCSS($p, &$t, $tag, $classes, $id) {
972 $this->_mergeCSS($p[$tag], $t);
973 // STYLESHEET CLASS e.g. .smallone{} .redletter{}
974 foreach($classes AS $class) {
975 $this->_mergeCSS($p['CLASS>>'.$class], $t);
976 }
977 // STYLESHEET nth-child SELECTOR e.g. tr:nth-child(odd) td:nth-child(2n+1)
978 if ($tag=='TR' && isset($p) && $p) {
979 foreach($p AS $k=>$val) {
980 if (preg_match('/'.$tag.'>>SELECTORNTHCHILD>>(.*)/',$k, $m)) {
981 $select = false;
982 if ($tag=='TR') {
983 $row = $this->mpdf->row;
984 $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);
985 $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);
986 if ($this->mpdf->tabletfoot) { $row -= $thnr; }
987 else if (!$this->mpdf->tablethead) { $row -= ($thnr + $tfnr); }
988 if ($m[1]=='ODD' && ($row % 2) == 0) { $select = true; }
989 else if ($m[1]=='EVEN' && ($row % 2) == 1) { $select = true; }
990 else if (preg_match('/(\d+)N\+(\d+)/',$m[1],$a)) {
991 if ((($row + 1) % $a[1]) == $a[2]) { $select = true; }
992 }
993 }
994 else if ($tag=='TD' || $tag=='TH') {
995 if ($m[1]=='ODD' && ($this->mpdf->col % 2) == 0) { $select = true; }
996 else if ($m[1]=='EVEN' && ($this->mpdf->col % 2) == 1) { $select = true; }
997 else if (preg_match('/(\d+)N\+(\d+)/',$m[1],$a)) {
998 if ((($this->mpdf->col + 1) % $a[1]) == $a[2]) { $select = true; }
999 }
1000 }
1001 if ($select) {
1002 $this->_mergeCSS($p[$tag.'>>SELECTORNTHCHILD>>'.$m[1]], $t);
1003 }
1004 }
1005 }
1006 }
1007 // STYLESHEET CLASS e.g. #smallone{} #redletter{}
1008 if (isset($id) && $id) {
1009 $this->_mergeCSS($p['ID>>'.$id], $t);
1010 }
1011 // STYLESHEET CLASS e.g. .smallone{} .redletter{}
1012 foreach($classes AS $class) {
1013 $this->_mergeCSS($p[$tag.'>>CLASS>>'.$class], $t);
1014 }
1015 // STYLESHEET CLASS e.g. #smallone{} #redletter{}
1016 if (isset($id)) {
1017 $this->_mergeCSS($p[$tag.'>>ID>>'.$id], $t);
1018 }
1019}
1020
1021function setBorderDominance($prop, $val) {
1022 if (isset($prop['BORDER-LEFT']) && $prop['BORDER-LEFT']) { $this->cell_border_dominance_L = $val; }
1023 if (isset($prop['BORDER-RIGHT']) && $prop['BORDER-RIGHT']) { $this->cell_border_dominance_R = $val; }
1024 if (isset($prop['BORDER-TOP']) && $prop['BORDER-TOP']) { $this->cell_border_dominance_T = $val; }
1025 if (isset($prop['BORDER-BOTTOM']) && $prop['BORDER-BOTTOM']) { $this->cell_border_dominance_B = $val; }
1026}
1027
1028function _set_mergedCSS(&$m, &$p, $d=true, $bd=false) {
1029 if (isset($m)) {
1030 if ((isset($m['depth']) && $m['depth']>1) || $d==false) { // include check for 'depth'
1031 if ($bd) { $this->setBorderDominance($m, $bd); } // *TABLES*
1032 if (is_array($m)) {
1033 $p = array_merge($p,$m);
1034 $this->_mergeBorders($p,$m);
1035 }
1036 }
1037 }
1038}
1039
1040
1041function _mergeBorders(&$b, &$a) { // Merges $a['BORDER-TOP-STYLE'] to $b['BORDER-TOP'] etc.
1042 foreach(array('TOP','RIGHT','BOTTOM','LEFT') AS $side) {
1043 foreach(array('STYLE','WIDTH','COLOR') AS $el) {
1044 if (isset($a['BORDER-'.$side.'-'.$el])) { // e.g. $b['BORDER-TOP-STYLE']
1045 $s = trim($a['BORDER-'.$side.'-'.$el]);
1046 if (isset($b['BORDER-'.$side])) { // e.g. $b['BORDER-TOP']
1047 $p = trim($b['BORDER-'.$side]);
1048 }
1049 else { $p = ''; }
1050 if ($el=='STYLE') {
1051 if ($p) { $b['BORDER-'.$side] = preg_replace('/(\S+)\s+(\S+)\s+(\S+)/', '\\1 '.$s.' \\3', $p); }
1052 else { $b['BORDER-'.$side] = '0px '.$s.' #000000'; }
1053 }
1054 else if ($el=='WIDTH') {
1055 if ($p) { $b['BORDER-'.$side] = preg_replace('/(\S+)\s+(\S+)\s+(\S+)/', $s.' \\2 \\3', $p); }
1056 else { $b['BORDER-'.$side] = $s.' none #000000'; }
1057 }
1058 else if ($el=='COLOR') {
1059 if ($p) { $b['BORDER-'.$side] = preg_replace('/(\S+)\s+(\S+)\s+(\S+)/', '\\1 \\2 '.$s, $p); }
1060 else { $b['BORDER-'.$side] = '0px none '.$s; }
1061 }
1062 }
1063 }
1064 }
1065}
1066
1067
1068function MergeCSS($inherit,$tag,$attr) {
1069 $p = array();
1070 $zp = array();
1071
1072 $classes = array();
1073 if (isset($attr['CLASS'])) {
1074 $classes = preg_split('/\s+/',$attr['CLASS']);
1075 }
1076 if (!isset($attr['ID'])) { $attr['ID']=''; }
1077 //===============================================
1078/*-- TABLES --*/
1079 // Set Inherited properties
1080 if ($inherit == 'TOPTABLE') { // $tag = TABLE
1081 //===============================================
1082 // Save Cascading CSS e.g. "div.topic p" at this block level
1083
1084 if (isset($this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'])) {
1085 $this->tablecascadeCSS[0] = $this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'];
1086 }
1087 else {
1088 $this->tablecascadeCSS[0] = $this->cascadeCSS;
1089 }
1090 }
1091 //===============================================
1092 // Set Inherited properties
1093 if ($inherit == 'TOPTABLE' || $inherit == 'TABLE') {
1094 //Cascade everything from last level that is not an actual property, or defined by current tag/attributes
1095 if (isset($this->tablecascadeCSS[$this->tbCSSlvl-1]) && is_array($this->tablecascadeCSS[$this->tbCSSlvl-1])) {
1096 foreach($this->tablecascadeCSS[$this->tbCSSlvl-1] AS $k=>$v) {
1097 $this->tablecascadeCSS[$this->tbCSSlvl][$k] = $v;
1098 }
1099 }
1100 $this->_mergeFullCSS($this->cascadeCSS, $this->tablecascadeCSS[$this->tbCSSlvl], $tag, $classes, $attr['ID']);
1101 //===============================================
1102 // Cascading forward CSS e.g. "table.topic td" for this table in $this->tablecascadeCSS
1103 //===============================================
1104 // STYLESHEET TAG e.g. table
1105 $this->_mergeFullCSS($this->tablecascadeCSS[$this->tbCSSlvl-1], $this->tablecascadeCSS[$this->tbCSSlvl], $tag, $classes, $attr['ID']);
1106 //===============================================
1107 }
1108/*-- END TABLES --*/
1109 //===============================================
1110/*-- LISTS --*/
1111 // Set Inherited properties
1112 if ($inherit == 'TOPLIST') { // $tag = UL,OL
1113 //===============================================
1114 // Save Cascading CSS e.g. "div.topic p" at this block level
1115 if (isset($this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'])) {
1116 $this->listcascadeCSS[0] = $this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'];
1117 }
1118 else {
1119 $this->listcascadeCSS[0] = $this->cascadeCSS;
1120 }
1121 }
1122 //===============================================
1123 // Set Inherited properties
1124 if ($inherit == 'TOPLIST' || $inherit == 'LIST') {
1125 //Cascade everything from last level that is not an actual property, or defined by current tag/attributes
1126 if (isset($this->listcascadeCSS[$this->listCSSlvl-1]) && is_array($this->listcascadeCSS[$this->listCSSlvl-1])) {
1127 foreach($this->listcascadeCSS[$this->listCSSlvl-1] AS $k=>$v) {
1128 $this->listcascadeCSS[$this->listCSSlvl][$k] = $v;
1129 }
1130 }
1131 $this->_mergeFullCSS($this->cascadeCSS, $this->listcascadeCSS[$this->listCSSlvl], $tag, $classes, $attr['ID']);
1132 //===============================================
1133 // Cascading forward CSS e.g. "table.topic td" for this list in $this->listcascadeCSS
1134 //===============================================
1135 // STYLESHEET TAG e.g. table
1136 $this->_mergeFullCSS($this->listcascadeCSS[$this->listCSSlvl-1], $this->listcascadeCSS[$this->listCSSlvl], $tag, $classes, $attr['ID']);
1137 //===============================================
1138 }
1139/*-- END LISTS --*/
1140 //===============================================
1141 // Set Inherited properties
1142 if ($inherit == 'BLOCK') {
1143 if (isset($this->mpdf->blk[$this->mpdf->blklvl-1]['cascadeCSS']) && is_array($this->mpdf->blk[$this->mpdf->blklvl-1]['cascadeCSS'])) {
1144 foreach($this->mpdf->blk[$this->mpdf->blklvl-1]['cascadeCSS'] AS $k=>$v) {
1145 $this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'][$k] = $v;
1146
1147 }
1148 }
1149
1150 //===============================================
1151 // Save Cascading CSS e.g. "div.topic p" at this block level
1152 $this->_mergeFullCSS($this->cascadeCSS, $this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'], $tag, $classes, $attr['ID']);
1153 //===============================================
1154 // Cascading forward CSS
1155 //===============================================
1156 $this->_mergeFullCSS($this->mpdf->blk[$this->mpdf->blklvl-1]['cascadeCSS'], $this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'], $tag, $classes, $attr['ID']);
1157 //===============================================
1158 // Block properties
1159 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
1160 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']; }
1161
1162 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']; }
1163
1164 if (isset($this->mpdf->blk[$this->mpdf->blklvl-1]['align']) && $this->mpdf->blk[$this->mpdf->blklvl-1]['align']) {
1165 if ($this->mpdf->blk[$this->mpdf->blklvl-1]['align'] == 'L') { $p['TEXT-ALIGN'] = 'left'; }
1166 else if ($this->mpdf->blk[$this->mpdf->blklvl-1]['align'] == 'J') { $p['TEXT-ALIGN'] = 'justify'; }
1167 else if ($this->mpdf->blk[$this->mpdf->blklvl-1]['align'] == 'R') { $p['TEXT-ALIGN'] = 'right'; }
1168 else if ($this->mpdf->blk[$this->mpdf->blklvl-1]['align'] == 'C') { $p['TEXT-ALIGN'] = 'center'; }
1169 }
1170 if ($this->mpdf->ColActive || $this->mpdf->keep_block_together) {
1171 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)
1172 $cor = $this->mpdf->blk[$this->mpdf->blklvl-1]['bgcolorarray' ];
1173 $p['BACKGROUND-COLOR'] = $this->mpdf->_colAtoString($cor);
1174 }
1175 }
1176
1177 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']; }
1178 if (isset($this->mpdf->blk[$this->mpdf->blklvl-1]['InlineProperties'])) {
1179 $biilp = $this->mpdf->blk[$this->mpdf->blklvl-1]['InlineProperties'];
1180 }
1181 else { $biilp = null; }
1182 if (isset($biilp[ 'family' ]) && $biilp[ 'family' ]) { $p['FONT-FAMILY'] = $biilp[ 'family' ]; }
1183 if (isset($biilp[ 'I' ]) && $biilp[ 'I' ]) { $p['FONT-STYLE'] = 'italic'; }
1184 if (isset($biilp[ 'sizePt' ]) && $biilp[ 'sizePt' ]) { $p['FONT-SIZE'] = $biilp[ 'sizePt' ] . 'pt'; }
1185 if (isset($biilp[ 'B' ]) && $biilp[ 'B' ]) { $p['FONT-WEIGHT'] = 'bold'; }
1186 if (isset($biilp[ 'colorarray' ]) && $biilp[ 'colorarray' ]) {
1187 $cor = $biilp[ 'colorarray' ];
1188 $p['COLOR'] = $this->mpdf->_colAtoString($cor);
1189 }
1190 if (isset($biilp[ 'fontkerning' ])) {
1191 if ($biilp[ 'fontkerning' ]) { $p['FONT-KERNING'] = 'normal'; }
1192 else { $p['FONT-KERNING'] = 'none'; }
1193 }
1194 if (isset($biilp[ 'lSpacingCSS' ]) && $biilp[ 'lSpacingCSS' ]) { $p['LETTER-SPACING'] = $biilp[ 'lSpacingCSS' ]; }
1195 if (isset($biilp[ 'wSpacingCSS' ]) && $biilp[ 'wSpacingCSS' ]) { $p['WORD-SPACING'] = $biilp[ 'wSpacingCSS' ]; }
1196 if (isset($biilp[ 'toupper' ]) && $biilp[ 'toupper' ]) { $p['TEXT-TRANSFORM'] = 'uppercase'; }
1197 else if (isset($biilp[ 'tolower' ]) && $biilp[ 'tolower' ]) { $p['TEXT-TRANSFORM'] = 'lowercase'; }
1198 else if (isset($biilp[ 'capitalize' ]) && $biilp[ 'capitalize' ]) { $p['TEXT-TRANSFORM'] = 'capitalize'; }
1199 // CSS says text-decoration is not inherited, but IE7 does??
1200 if (isset($biilp[ 'underline' ]) && $biilp[ 'underline' ]) { $p['TEXT-DECORATION'] = 'underline'; }
1201 if (isset($biilp[ 'smCaps' ]) && $biilp[ 'smCaps' ]) { $p['FONT-VARIANT'] = 'small-caps'; }
1202
1203 }
1204 //===============================================
1205 //===============================================
1206/*-- LISTS --*/
1207 // Set Inherited properties
1208 if ($inherit == 'TOPLIST') {
1209 if ($this->listCSSlvl == 1) {
1210 $bilp = $this->mpdf->blk[$this->mpdf->blklvl]['InlineProperties'];
1211 if (isset($bilp[ 'family' ]) && $bilp[ 'family' ]) { $p['FONT-FAMILY'] = $bilp[ 'family' ]; }
1212 if (isset($bilp[ 'I' ]) && $bilp[ 'I' ]) { $p['FONT-STYLE'] = 'italic'; }
1213 if (isset($bilp[ 'sizePt' ]) && $bilp[ 'sizePt' ]) { $p['FONT-SIZE'] = $bilp[ 'sizePt' ] . 'pt'; }
1214 if (isset($bilp[ 'B' ]) && $bilp[ 'B' ]) { $p['FONT-WEIGHT'] = 'bold'; }
1215 if (isset($bilp[ 'colorarray' ]) && $bilp[ 'colorarray' ]) {
1216 $cor = $bilp[ 'colorarray' ];
1217 $p['COLOR'] = $this->mpdf->_colAtoString($cor);
1218 }
1219 if (isset($bilp[ 'toupper' ]) && $bilp[ 'toupper' ]) { $p['TEXT-TRANSFORM'] = 'uppercase'; }
1220 else if (isset($bilp[ 'tolower' ]) && $bilp[ 'tolower' ]) { $p['TEXT-TRANSFORM'] = 'lowercase'; }
1221 else if (isset($bilp[ 'capitalize' ]) && $bilp[ 'capitalize' ]) { $p['TEXT-TRANSFORM'] = 'capitalize'; }
1222 if (isset($bilp[ 'fontkerning' ])) {
1223 if ($bilp[ 'fontkerning' ]) { $p['FONT-KERNING'] = 'normal'; }
1224 else { $p['FONT-KERNING'] = 'none'; }
1225 }
1226 if (isset($bilp[ 'lSpacingCSS' ]) && $bilp[ 'lSpacingCSS' ]) { $p['LETTER-SPACING'] = $bilp[ 'lSpacingCSS' ]; }
1227 if (isset($bilp[ 'wSpacingCSS' ]) && $bilp[ 'wSpacingCSS' ]) { $p['WORD-SPACING'] = $bilp[ 'wSpacingCSS' ]; }
1228 // CSS says text-decoration is not inherited, but IE7 does??
1229 if (isset($bilp[ 'underline' ]) && $bilp[ 'underline' ]) { $p['TEXT-DECORATION'] = 'underline'; }
1230 if (isset($bilp[ 'smCaps' ]) && $bilp[ 'smCaps' ]) { $p['FONT-VARIANT'] = 'small-caps'; }
1231 if ($tag=='LI') {
1232 // Note to self - this should never work, as TOPLIST is not called when LI (see code removed in v5.3)
1233 $this->mpdf->Error("If you see this message, please report this as a bug to the mPDF Forum.");
1234 }
1235 }
1236 }
1237/*-- END LISTS --*/
1238 //===============================================
1239 //===============================================
1240 // DEFAULT for this TAG set in DefaultCSS
1241 if (isset($this->mpdf->defaultCSS[$tag])) {
1242 $zp = $this->fixCSS($this->mpdf->defaultCSS[$tag]);
1243 if (is_array($zp)) { // Default overwrites Inherited
1244 $p = array_merge($p,$zp); // !! Note other way round !!
1245 $this->_mergeBorders($p,$zp);
1246 }
1247 }
1248 //===============================================
1249/*-- TABLES --*/
1250 // cellPadding overwrites TD/TH default but not specific CSS set on cell
1251 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)) {
1252 $p['PADDING-LEFT'] = $this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['cell_padding'];
1253 $p['PADDING-RIGHT'] = $this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['cell_padding'];
1254 $p['PADDING-TOP'] = $this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['cell_padding'];
1255 $p['PADDING-BOTTOM'] = $this->mpdf->table[$this->mpdf->tableLevel][$this->mpdf->tbctr[$this->mpdf->tableLevel]]['cell_padding'];
1256 }
1257/*-- END TABLES --*/
1258 //===============================================
1259 // STYLESHEET TAG e.g. h1 p div table
1260 if (isset($this->CSS[$tag]) && $this->CSS[$tag]) {
1261 $zp = $this->CSS[$tag];
1262 if ($tag=='TD' || $tag=='TH') { $this->setBorderDominance($zp, 9); } // *TABLES* // *TABLES-ADVANCED-BORDERS*
1263 if (is_array($zp)) {
1264 $p = array_merge($p,$zp);
1265 $this->_mergeBorders($p,$zp);
1266 }
1267 }
1268 //===============================================
1269 // STYLESHEET CLASS e.g. .smallone{} .redletter{}
1270 foreach($classes AS $class) {
1271 $zp = array();
1272 if (isset($this->CSS['CLASS>>'.$class]) && $this->CSS['CLASS>>'.$class]) { $zp = $this->CSS['CLASS>>'.$class]; }
1273 if ($tag=='TD' || $tag=='TH') { $this->setBorderDominance($zp, 9); } // *TABLES* // *TABLES-ADVANCED-BORDERS*
1274 if (is_array($zp)) {
1275 $p = array_merge($p,$zp);
1276 $this->_mergeBorders($p,$zp);
1277 }
1278 }
1279 //===============================================
1280/*-- TABLES --*/
1281 // STYLESHEET nth-child SELECTOR e.g. tr:nth-child(odd) td:nth-child(2n+1)
1282 if ($tag=='TR' || $tag=='TD' || $tag=='TH') {
1283 foreach($this->CSS AS $k=>$val) {
1284 if (preg_match('/'.$tag.'>>SELECTORNTHCHILD>>(.*)/',$k, $m)) {
1285 $select = false;
1286 if ($tag=='TR') {
1287 $row = $this->mpdf->row;
1288 $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);
1289 $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);
1290 if ($this->mpdf->tabletfoot) { $row -= $thnr; }
1291 else if (!$this->mpdf->tablethead) { $row -= ($thnr + $tfnr); }
1292 if ($m[1]=='ODD' && ($row % 2) == 0) { $select = true; }
1293 else if ($m[1]=='EVEN' && ($row % 2) == 1) { $select = true; }
1294 else if (preg_match('/(\d+)N\+(\d+)/',$m[1],$a)) {
1295 if ((($row + 1) % $a[1]) == $a[2]) { $select = true; }
1296 }
1297 }
1298 else if ($tag=='TD' || $tag=='TH') {
1299 if ($m[1]=='ODD' && ($this->mpdf->col % 2) == 0) { $select = true; }
1300 else if ($m[1]=='EVEN' && ($this->mpdf->col % 2) == 1) { $select = true; }
1301 else if (preg_match('/(\d+)N\+(\d+)/',$m[1],$a)) {
1302 if ((($this->mpdf->col+1) % $a[1]) == $a[2]) { $select = true; }
1303 }
1304 }
1305 if ($select) {
1306 $zp = $this->CSS[$tag.'>>SELECTORNTHCHILD>>'.$m[1]];
1307 if ($tag=='TD' || $tag=='TH') { $this->setBorderDominance($zp, 9); }
1308 if (is_array($zp)) {
1309 $p = array_merge($p,$zp);
1310 $this->_mergeBorders($p,$zp);
1311 }
1312 }
1313 }
1314 }
1315 }
1316/*-- END TABLES --*/
1317 //===============================================
1318 // STYLESHEET ID e.g. #smallone{} #redletter{}
1319 if (isset($attr['ID']) && isset($this->CSS['ID>>'.$attr['ID']]) && $this->CSS['ID>>'.$attr['ID']]) {
1320 $zp = $this->CSS['ID>>'.$attr['ID']];
1321 if ($tag=='TD' || $tag=='TH') { $this->setBorderDominance($zp, 9); } // *TABLES* // *TABLES-ADVANCED-BORDERS*
1322 if (is_array($zp)) {
1323 $p = array_merge($p,$zp);
1324 $this->_mergeBorders($p,$zp);
1325 }
1326 }
1327 //===============================================
1328 // STYLESHEET CLASS e.g. p.smallone{} div.redletter{}
1329 foreach($classes AS $class) {
1330 $zp = array();
1331 if (isset($this->CSS[$tag.'>>CLASS>>'.$class]) && $this->CSS[$tag.'>>CLASS>>'.$class]) { $zp = $this->CSS[$tag.'>>CLASS>>'.$class]; }
1332 if ($tag=='TD' || $tag=='TH') { $this->setBorderDominance($zp, 9); } // *TABLES* // *TABLES-ADVANCED-BORDERS*
1333 if (is_array($zp)) {
1334 $p = array_merge($p,$zp);
1335 $this->_mergeBorders($p,$zp);
1336 }
1337 }
1338 //===============================================
1339 // STYLESHEET CLASS e.g. p#smallone{} div#redletter{}
1340 if (isset($attr['ID']) && isset($this->CSS[$tag.'>>ID>>'.$attr['ID']]) && $this->CSS[$tag.'>>ID>>'.$attr['ID']]) {
1341 $zp = $this->CSS[$tag.'>>ID>>'.$attr['ID']];
1342 if ($tag=='TD' || $tag=='TH') { $this->setBorderDominance($zp, 9); } // *TABLES* // *TABLES-ADVANCED-BORDERS*
1343 if (is_array($zp)) {
1344 $p = array_merge($p,$zp);
1345 $this->_mergeBorders($p,$zp);
1346 }
1347 }
1348 //===============================================
1349 // Cascaded e.g. div.class p only works for block level
1350 if ($inherit == 'BLOCK') {
1351 $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl-1]['cascadeCSS'][$tag], $p);
1352 foreach($classes AS $class) {
1353 $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl-1]['cascadeCSS']['CLASS>>'.$class], $p);
1354 }
1355 $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl-1]['cascadeCSS']['ID>>'.$attr['ID']], $p);
1356 foreach($classes AS $class) {
1357 $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl-1]['cascadeCSS'][$tag.'>>CLASS>>'.$class], $p);
1358 }
1359 $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl-1]['cascadeCSS'][$tag.'>>ID>>'.$attr['ID']], $p);
1360 }
1361 else if ($inherit == 'INLINE') {
1362 $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'][$tag], $p);
1363 foreach($classes AS $class) {
1364 $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS']['CLASS>>'.$class], $p);
1365 }
1366 $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS']['ID>>'.$attr['ID']], $p);
1367 foreach($classes AS $class) {
1368 $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'][$tag.'>>CLASS>>'.$class], $p);
1369 }
1370 $this->_set_mergedCSS($this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'][$tag.'>>ID>>'.$attr['ID']], $p);
1371 }
1372/*-- TABLES --*/
1373 else if ($inherit == 'TOPTABLE' || $inherit == 'TABLE') { // NB looks at $this->tablecascadeCSS-1 for cascading CSS
1374 // false, 9 = don't check for 'depth' and do set border dominance
1375 $this->_set_mergedCSS($this->tablecascadeCSS[$this->tbCSSlvl-1][$tag], $p, false, 9);
1376 foreach($classes AS $class) {
1377 $this->_set_mergedCSS($this->tablecascadeCSS[$this->tbCSSlvl-1]['CLASS>>'.$class], $p, false, 9);
1378 }
1379 // STYLESHEET nth-child SELECTOR e.g. tr:nth-child(odd) td:nth-child(2n+1)
1380 if ($tag=='TR' || $tag=='TD' || $tag=='TH') {
1381 foreach($this->tablecascadeCSS[$this->tbCSSlvl-1] AS $k=>$val) {
1382 if (preg_match('/'.$tag.'>>SELECTORNTHCHILD>>(.*)/',$k, $m)) {
1383 $select = false;
1384 if ($tag=='TR') {
1385 $row = $this->mpdf->row;
1386 $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);
1387 $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);
1388 if ($this->mpdf->tabletfoot) { $row -= $thnr; }
1389 else if (!$this->mpdf->tablethead) { $row -= ($thnr + $tfnr); }
1390 if ($m[1]=='ODD' && ($row % 2) == 0) { $select = true; }
1391 else if ($m[1]=='EVEN' && ($row % 2) == 1) { $select = true; }
1392 else if (preg_match('/(\d+)N\+(\d+)/',$m[1],$a)) {
1393 if ((($row + 1) % $a[1]) == $a[2]) { $select = true; }
1394 }
1395 }
1396 else if ($tag=='TD' || $tag=='TH') {
1397 if ($m[1]=='ODD' && ($this->mpdf->col % 2) == 0) { $select = true; }
1398 else if ($m[1]=='EVEN' && ($this->mpdf->col % 2) == 1) { $select = true; }
1399 else if (preg_match('/(\d+)N\+(\d+)/',$m[1],$a)) {
1400 if ((($this->mpdf->col + 1) % $a[1]) == $a[2]) { $select = true; }
1401 }
1402 }
1403 if ($select) {
1404 $this->_set_mergedCSS($this->tablecascadeCSS[$this->tbCSSlvl-1][$tag.'>>SELECTORNTHCHILD>>'.$m[1]], $p, false, 9);
1405 }
1406 }
1407 }
1408 }
1409 $this->_set_mergedCSS($this->tablecascadeCSS[$this->tbCSSlvl-1]['ID>>'.$attr['ID']], $p, false, 9);
1410 foreach($classes AS $class) {
1411 $this->_set_mergedCSS($this->tablecascadeCSS[$this->tbCSSlvl-1][$tag.'>>CLASS>>'.$class], $p, false, 9);
1412 }
1413 $this->_set_mergedCSS($this->tablecascadeCSS[$this->tbCSSlvl-1][$tag.'>>ID>>'.$attr['ID']], $p, false, 9);
1414 }
1415/*-- END TABLES --*/
1416 //===============================================
1417/*-- LISTS --*/
1418 else if ($inherit == 'TOPLIST' || $inherit == 'LIST') { // NB looks at $this->listcascadeCSS-1 for cascading CSS
1419 // false = don't check for 'depth'
1420 $this->_set_mergedCSS($this->listcascadeCSS[$this->listCSSlvl-1][$tag], $p, false);
1421 foreach($classes AS $class) {
1422 $this->_set_mergedCSS($this->listcascadeCSS[$this->listCSSlvl-1]['CLASS>>'.$class], $p, false);
1423 }
1424 $this->_set_mergedCSS($this->listcascadeCSS[$this->listCSSlvl-1]['ID>>'.$attr['ID']], $p, false);
1425 foreach($classes AS $class) {
1426 $this->_set_mergedCSS($this->listcascadeCSS[$this->listCSSlvl-1][$tag.'>>CLASS>>'.$class], $p, false);
1427 }
1428 $this->_set_mergedCSS($this->listcascadeCSS[$this->listCSSlvl-1][$tag.'>>ID>>'.$attr['ID']], $p, false);
1429 }
1430/*-- END LISTS --*/
1431 //===============================================
1432 //===============================================
1433 // INLINE STYLE e.g. style="CSS:property"
1434 if (isset($attr['STYLE'])) {
1435 $zp = $this->readInlineCSS($attr['STYLE']);
1436 if ($tag=='TD' || $tag=='TH') { $this->setBorderDominance($zp, 9); } // *TABLES* // *TABLES-ADVANCED-BORDERS*
1437 if (is_array($zp)) {
1438 $p = array_merge($p,$zp);
1439 $this->_mergeBorders($p,$zp);
1440 }
1441 }
1442 //===============================================
1443 //===============================================
1444 // INLINE ATTRIBUTES e.g. .. ALIGN="CENTER">
1445 if (isset($attr['LANG']) and $attr['LANG']!='') {
1446 $p['LANG'] = $attr['LANG'];
1447 }
1448 if (isset($attr['COLOR']) and $attr['COLOR']!='') {
1449 $p['COLOR'] = $attr['COLOR'];
1450 }
1451 if ($tag != 'INPUT') {
1452 if (isset($attr['WIDTH']) and $attr['WIDTH']!='') {
1453 $p['WIDTH'] = $attr['WIDTH'];
1454 }
1455 if (isset($attr['HEIGHT']) and $attr['HEIGHT']!='') {
1456 $p['HEIGHT'] = $attr['HEIGHT'];
1457 }
1458 }
1459 if ($tag == 'FONT') {
1460 if (isset($attr['FACE'])) {
1461 $p['FONT-FAMILY'] = $attr['FACE'];
1462 }
1463 if (isset($attr['SIZE']) and $attr['SIZE']!='') {
1464 $s = '';
1465 if ($attr['SIZE'] === '+1') { $s = '120%'; }
1466 else if ($attr['SIZE'] === '-1') { $s = '86%'; }
1467 else if ($attr['SIZE'] === '1') { $s = 'XX-SMALL'; }
1468 else if ($attr['SIZE'] == '2') { $s = 'X-SMALL'; }
1469 else if ($attr['SIZE'] == '3') { $s = 'SMALL'; }
1470 else if ($attr['SIZE'] == '4') { $s = 'MEDIUM'; }
1471 else if ($attr['SIZE'] == '5') { $s = 'LARGE'; }
1472 else if ($attr['SIZE'] == '6') { $s = 'X-LARGE'; }
1473 else if ($attr['SIZE'] == '7') { $s = 'XX-LARGE'; }
1474 if ($s) $p['FONT-SIZE'] = $s;
1475 }
1476 }
1477 if (isset($attr['VALIGN']) and $attr['VALIGN']!='') {
1478 $p['VERTICAL-ALIGN'] = $attr['VALIGN'];
1479 }
1480 if (isset($attr['VSPACE']) and $attr['VSPACE']!='') {
1481 $p['MARGIN-TOP'] = $attr['VSPACE'];
1482 $p['MARGIN-BOTTOM'] = $attr['VSPACE'];
1483 }
1484 if (isset($attr['HSPACE']) and $attr['HSPACE']!='') {
1485 $p['MARGIN-LEFT'] = $attr['HSPACE'];
1486 $p['MARGIN-RIGHT'] = $attr['HSPACE'];
1487 }
1488 //===============================================
1489 return $p;
1490}
1491
1492function PreviewBlockCSS($tag,$attr) {
1493 // Looks ahead from current block level to a new level
1494 $p = array();
1495 $zp = array();
1496 $oldcascadeCSS = $this->mpdf->blk[$this->mpdf->blklvl]['cascadeCSS'];
1497 $classes = array();
1498 if (isset($attr['CLASS'])) { $classes = preg_split('/\s+/',$attr['CLASS']); }
1499 //===============================================
1500 // DEFAULT for this TAG set in DefaultCSS
1501 if (isset($this->mpdf->defaultCSS[$tag])) {
1502 $zp = $this->fixCSS($this->mpdf->defaultCSS[$tag]);
1503 if (is_array($zp)) { $p = array_merge($zp,$p); } // Inherited overwrites default
1504 }
1505 // STYLESHEET TAG e.g. h1 p div table
1506 if (isset($this->CSS[$tag])) {
1507 $zp = $this->CSS[$tag];
1508 if (is_array($zp)) { $p = array_merge($p,$zp); }
1509 }
1510 // STYLESHEET CLASS e.g. .smallone{} .redletter{}
1511 foreach($classes AS $class) {
1512 $zp = array();
1513 if (isset($this->CSS['CLASS>>'.$class])) { $zp = $this->CSS['CLASS>>'.$class]; }
1514 if (is_array($zp)) { $p = array_merge($p,$zp); }
1515 }
1516 // STYLESHEET ID e.g. #smallone{} #redletter{}
1517 if (isset($attr['ID']) && isset($this->CSS['ID>>'.$attr['ID']])) {
1518 $zp = $this->CSS['ID>>'.$attr['ID']];
1519 if (is_array($zp)) { $p = array_merge($p,$zp); }
1520 }
1521 // STYLESHEET CLASS e.g. p.smallone{} div.redletter{}
1522 foreach($classes AS $class) {
1523 $zp = array();
1524 if (isset($this->CSS[$tag.'>>CLASS>>'.$class])) { $zp = $this->CSS[$tag.'>>CLASS>>'.$class]; }
1525 if (is_array($zp)) { $p = array_merge($p,$zp); }
1526 }
1527 // STYLESHEET CLASS e.g. p#smallone{} div#redletter{}
1528 if (isset($attr['ID']) && isset($this->CSS[$tag.'>>ID>>'.$attr['ID']])) {
1529 $zp = $this->CSS[$tag.'>>ID>>'.$attr['ID']];
1530 if (is_array($zp)) { $p = array_merge($p,$zp); }
1531 }
1532 //===============================================
1533 // STYLESHEET TAG e.g. div h1 div p
1534
1535 $this->_set_mergedCSS($oldcascadeCSS[$tag], $p);
1536 // STYLESHEET CLASS e.g. .smallone{} .redletter{}
1537 foreach($classes AS $class) {
1538
1539 $this->_set_mergedCSS($oldcascadeCSS['CLASS>>'.$class], $p);
1540 }
1541 // STYLESHEET CLASS e.g. #smallone{} #redletter{}
1542 if (isset($attr['ID'])) {
1543
1544 $this->_set_mergedCSS($oldcascadeCSS['ID>>'.$attr['ID']], $p);
1545 }
1546 // STYLESHEET CLASS e.g. div.smallone{} p.redletter{}
1547 foreach($classes AS $class) {
1548
1549 $this->_set_mergedCSS($oldcascadeCSS[$tag.'>>CLASS>>'.$class], $p);
1550 }
1551 // STYLESHEET CLASS e.g. div#smallone{} p#redletter{}
1552 if (isset($attr['ID'])) {
1553
1554 $this->_set_mergedCSS($oldcascadeCSS[$tag.'>>ID>>'.$attr['ID']], $p);
1555 }
1556 //===============================================
1557 // INLINE STYLE e.g. style="CSS:property"
1558 if (isset($attr['STYLE'])) {
1559 $zp = $this->readInlineCSS($attr['STYLE']);
1560 if (is_array($zp)) { $p = array_merge($p,$zp); }
1561 }
1562 //===============================================
1563 return $p;
1564}
1565
1566
1567
1568
1569
1570} // end of class
1571
1572?> \ No newline at end of file
diff --git a/inc/3rdparty/libraries/mpdf/classes/directw.php b/inc/3rdparty/libraries/mpdf/classes/directw.php
deleted file mode 100644
index dc317d26..00000000
--- a/inc/3rdparty/libraries/mpdf/classes/directw.php
+++ /dev/null
@@ -1,408 +0,0 @@
1<?php
2
3class directw {
4
5var $mpdf = null;
6
7function directw(&$mpdf) {
8 $this->mpdf = $mpdf;
9}
10
11
12function 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
227function 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
355function 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
deleted file mode 100644
index 9367e717..00000000
--- a/inc/3rdparty/libraries/mpdf/classes/form.php
+++ /dev/null
@@ -1,1498 +0,0 @@
1<?php
2
3class form {
4
5var $mpdf = null;
6
7var $forms;
8var $formn;
9
10//Active Forms
11var $formSubmitNoValueFields;
12var $formExportType;
13var $formSelectDefaultOption;
14var $formUseZapD;
15/* Form Styles */
16var $form_border_color;
17var $form_background_color;
18var $form_border_width;
19var $form_border_style;
20var $form_button_border_color;
21var $form_button_background_color;
22var $form_button_border_width;
23var $form_button_border_style;
24var $form_radio_color;
25var $form_radio_background_color;
26
27var $form_element_spacing;
28
29// Active forms
30var $formMethod;
31var $formAction;
32var $form_fonts;
33var $form_radio_groups;
34var $form_checkboxes;
35var $pdf_acro_array;
36
37var $pdf_array_co;
38var $array_form_button_js;
39var $array_form_choice_js;
40var $array_form_text_js;
41
42/* Button Text */
43var $form_button_text;
44var $form_button_text_over;
45var $form_button_text_click;
46var $form_button_icon;
47
48
49// FORMS
50var $textarea_lineheight;
51
52function 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
110function 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
167function 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
230function 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
301function 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
319function 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
368function 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
418function 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
463function 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
493function 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
524function _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
535function _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
572function _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
594function 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
603function 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
612function 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
623function 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
637function 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
953function 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
969function 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
986function 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
993function 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
1000function SetFormD ( $W, $S, $BC, $BG ) {
1001 $this->SetFormBorderWidth ( $W );
1002 $this->SetFormBorderStyle ( $S );
1003 $this->SetFormBorderColor ( $BC );
1004 $this->SetFormBackgroundColor ( $BG );
1005}
1006
1007function _setflag( $array ) {
1008 $flag = 0;
1009 foreach($array as $val) { $flag += 1 << ($val-1); }
1010 return $flag;
1011}
1012
1013function _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
1023function _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
1072function _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
12665.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
1267f 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
12966.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
1320function _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
1398function _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
deleted file mode 100644
index 263513e2..00000000
--- a/inc/3rdparty/libraries/mpdf/classes/gif.php
+++ /dev/null
@@ -1,700 +0,0 @@
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
20class 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
235class 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
314class 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
391class 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
462class 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
640class 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
deleted file mode 100644
index 2691bf5d..00000000
--- a/inc/3rdparty/libraries/mpdf/classes/grad.php
+++ /dev/null
@@ -1,723 +0,0 @@
1<?php
2
3class grad {
4
5var $mpdf = null;
6
7function grad(&$mpdf) {
8 $this->mpdf = $mpdf;
9}
10
11// mPDF 5.3.A1
12function 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])
102function 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
447function 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
680function 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
deleted file mode 100644
index 0573053b..00000000
--- a/inc/3rdparty/libraries/mpdf/classes/indic.php
+++ /dev/null
@@ -1,433 +0,0 @@
1<?php
2
3class indic {
4
5function indic() {
6
7}
8
9
10function 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
deleted file mode 100644
index 46fa9d5a..00000000
--- a/inc/3rdparty/libraries/mpdf/classes/meter.php
+++ /dev/null
@@ -1,224 +0,0 @@
1<?php
2
3class meter {
4
5
6function __construct() {
7
8}
9
10function 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
deleted file mode 100644
index 571f4edd..00000000
--- a/inc/3rdparty/libraries/mpdf/classes/svg.php
+++ /dev/null
@@ -1,2703 +0,0 @@
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
14class 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));
748if ($vv[0] < 0) { $sx *= -1; } // change sign
749$sy=sqrt(pow($vv[1],2)+pow($vv[3],2));
750if ($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+)\)/i',$critere_style['style'], $m)) { // mPDF 5.7.2
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 // mPDF 5.7.2
819 if (preg_match("/[^-]opacity:\s*([a-z0-9.]*|none)/i",$critere_style['style'], $m) ||
820 preg_match("/^opacity:\s*([a-z0-9.]*|none)/i",$critere_style['style'], $m)) {
821 $current_style['fill-opacity'] = $m[1];
822 $current_style['stroke-opacity'] = $m[1];
823 }
824
825 $tmp = preg_replace("/(.*)fill-opacity:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']);
826 if ($tmp != $critere_style['style']){ $current_style['fill-opacity'] = $tmp;}
827
828 $tmp = preg_replace("/(.*)fill-rule:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']);
829 if ($tmp != $critere_style['style']){ $current_style['fill-rule'] = $tmp;}
830
831 if (preg_match('/stroke:\s*rgb\((\d+),\s*(\d+),\s*(\d+)\)/',$critere_style['style'], $m)) {
832 $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);
833 }
834 else { $tmp = preg_replace("/(.*)stroke:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']);
835 if ($tmp != $critere_style['style']){ $current_style['stroke'] = $tmp; }
836 }
837
838 $tmp = preg_replace("/(.*)stroke-linecap:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']);
839 if ($tmp != $critere_style['style']){ $current_style['stroke-linecap'] = $tmp;}
840
841 $tmp = preg_replace("/(.*)stroke-linejoin:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']);
842 if ($tmp != $critere_style['style']){ $current_style['stroke-linejoin'] = $tmp;}
843
844 $tmp = preg_replace("/(.*)stroke-miterlimit:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']);
845 if ($tmp != $critere_style['style']){ $current_style['stroke-miterlimit'] = $tmp;}
846
847 $tmp = preg_replace("/(.*)stroke-opacity:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']);
848 if ($tmp != $critere_style['style']){ $current_style['stroke-opacity'] = $tmp; }
849
850 $tmp = preg_replace("/(.*)stroke-width:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']);
851 if ($tmp != $critere_style['style']){ $current_style['stroke-width'] = $tmp;}
852
853 // mPDF 4.4.003
854 $tmp = preg_replace("/(.*)stroke-dasharray:\s*([a-z0-9., ]*|none)(.*)/i","$2",$critere_style['style']);
855 if ($tmp != $critere_style['style']){ $current_style['stroke-dasharray'] = $tmp;}
856
857 // mPDF 4.4.003
858 $tmp = preg_replace("/(.*)stroke-dashoffset:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']);
859 if ($tmp != $critere_style['style']){ $current_style['stroke-dashoffset'] = $tmp;}
860
861 }
862 // mPDF 5.7.2
863 if(isset($critere_style['opacity'])){
864 $current_style['fill-opacity'] = $critere_style['opacity'];
865 $current_style['stroke-opacity'] = $critere_style['opacity'];
866 }
867
868 if(isset($critere_style['fill'])){
869 $current_style['fill'] = $critere_style['fill'];
870 }
871
872 if(isset($critere_style['fill-opacity'])){
873 $current_style['fill-opacity'] = $critere_style['fill-opacity'];
874 }
875
876 if(isset($critere_style['fill-rule'])){
877 $current_style['fill-rule'] = $critere_style['fill-rule'];
878 }
879
880 if(isset($critere_style['stroke'])){
881 $current_style['stroke'] = $critere_style['stroke'];
882 }
883
884 if(isset($critere_style['stroke-linecap'])){
885 $current_style['stroke-linecap'] = $critere_style['stroke-linecap'];
886 }
887
888 if(isset($critere_style['stroke-linejoin'])){
889 $current_style['stroke-linejoin'] = $critere_style['stroke-linejoin'];
890 }
891
892 if(isset($critere_style['stroke-miterlimit'])){
893 $current_style['stroke-miterlimit'] = $critere_style['stroke-miterlimit'];
894 }
895
896 if(isset($critere_style['stroke-opacity'])){
897 $current_style['stroke-opacity'] = $critere_style['stroke-opacity'];
898 }
899
900 if(isset($critere_style['stroke-width'])){
901 $current_style['stroke-width'] = $critere_style['stroke-width'];
902 }
903
904 // mPDF 4.4.003
905 if(isset($critere_style['stroke-dasharray'])){
906 $current_style['stroke-dasharray'] = $critere_style['stroke-dasharray'];
907 }
908 if(isset($critere_style['stroke-dashoffset'])){
909 $current_style['stroke-dashoffset'] = $critere_style['stroke-dashoffset'];
910 }
911
912 // mPDF 4.4.005 Used as indirect setting for currentColor
913 if(isset($critere_style['color']) && $critere_style['color'] != 'inherit'){
914 $current_style['color'] = $critere_style['color'];
915 }
916
917 return $current_style;
918
919 }
920
921 //
922 // Cette fonction ecrit le style dans le stream svg.
923 function svgStyle($critere_style, $attribs, $element){
924 $path_style = '';
925 if (substr_count($critere_style['fill'],'url')>0 && $element != 'line'){
926 //
927 // couleur degradé
928 $id_gradient = preg_replace("/url\(#([\w_]*)\)/i","$1",$critere_style['fill']);
929 if ($id_gradient != $critere_style['fill']) {
930 if (isset($this->svg_gradient[$id_gradient])) {
931 $fill_gradient = $this->svgGradient($this->svg_gradient[$id_gradient], $attribs, $element);
932 if ($fill_gradient) { // mPDF 4.4.003
933 $path_style = "q ";
934 $w = "W";
935 $style .= 'N';
936 }
937 }
938 }
939
940 }
941 // mPDF 4.4.005 Used as indirect setting for currentColor
942 else if (strtolower($critere_style['fill']) == 'currentcolor' && $element != 'line'){
943 $col = $this->mpdf_ref->ConvertColor($critere_style['color']);
944 if ($col) {
945 // mPDF 5.0.051
946 // mPDF 5.3.74
947 if ($col{0}==5) { $critere_style['fill-opacity'] = ord($col{4}/100); } // RGBa
948 if ($col{0}==6) { $critere_style['fill-opacity'] = ord($col{5}/100); } // CMYKa
949 $path_style .= $this->mpdf_ref->SetFColor($col, true).' '; // mPDF 5.0.051
950 $style .= 'F';
951 }
952 }
953 else if ($critere_style['fill'] != 'none' && $element != 'line'){
954 $col = $this->mpdf_ref->ConvertColor($critere_style['fill']);
955 if ($col) {
956 // mPDF 5.0.051
957 // mPDF 5.3.74
958 if ($col{0}==5) { $critere_style['fill-opacity'] = ord($col{4}/100); } // RGBa
959 if ($col{0}==6) { $critere_style['fill-opacity'] = ord($col{5}/100); } // CMYKa
960 $path_style .= $this->mpdf_ref->SetFColor($col, true).' '; // mPDF 5.0.051
961 $style .= 'F';
962 }
963 }
964
965 // mPDF 5.0.040
966 if (substr_count($critere_style['stroke'],'url')>0){
967/*
968 // Cannot put a gradient on a "stroke" in PDF?
969 $id_gradient = preg_replace("/url\(#([\w_]*)\)/i","$1",$critere_style['stroke']);
970 if ($id_gradient != $critere_style['stroke']) {
971 if (isset($this->svg_gradient[$id_gradient])) {
972 $fill_gradient = $this->svgGradient($this->svg_gradient[$id_gradient], $attribs, $element);
973 if ($fill_gradient) {
974 $path_style = "q ";
975 $w = "W";
976 $style .= 'D';
977 }
978 }
979 }
980*/
981 }
982 // mPDF 4.4.005 Used as indirect setting for currentColor
983 else if (strtolower($critere_style['stroke']) == 'currentcolor'){
984 $col = $this->mpdf_ref->ConvertColor($critere_style['color']);
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']);
993 $path_style .= sprintf('%.3F w ',$lw*$this->kp);
994 }
995 }
996 else if ($critere_style['stroke'] != 'none'){
997 $col = $this->mpdf_ref->ConvertColor($critere_style['stroke']);
998 if ($col) {
999 // mPDF 5.0.051
1000 // mPDF 5.3.74
1001 if ($col{0}==5) { $critere_style['stroke-opacity'] = ord($col{4}/100); } // RGBa
1002 if ($col{0}==6) { $critere_style['stroke-opacity'] = ord($col{5}/100); } // CMYKa
1003 $path_style .= $this->mpdf_ref->SetDColor($col, true).' '; // mPDF 5.0.051
1004 $style .= 'D';
1005 $lw = $this->ConvertSVGSizePixels($critere_style['stroke-width']); // mPDF 4.4.003
1006 $path_style .= sprintf('%.3F w ',$lw*$this->kp);
1007 }
1008 }
1009
1010
1011 if ($critere_style['stroke'] != 'none'){
1012 if ($critere_style['stroke-linejoin'] == 'miter'){
1013 $path_style .= ' 0 j ';
1014 }
1015 else if ($critere_style['stroke-linejoin'] == 'round'){
1016 $path_style .= ' 1 j ';
1017 }
1018 else if ($critere_style['stroke-linejoin'] == 'bevel'){
1019 $path_style .= ' 2 j ';
1020 }
1021
1022 if ($critere_style['stroke-linecap'] == 'butt'){
1023 $path_style .= ' 0 J ';
1024 }
1025 else if ($critere_style['stroke-linecap'] == 'round'){
1026 $path_style .= ' 1 J ';
1027 }
1028 else if ($critere_style['stroke-linecap'] == 'square'){
1029 $path_style .= ' 2 J ';
1030 }
1031
1032 if (isset($critere_style['stroke-miterlimit'])){
1033 if ($critere_style['stroke-miterlimit'] == 'none'){
1034 }
1035 else if (preg_match('/^[\d.]+$/',$critere_style['stroke-miterlimit'])) {
1036 $path_style .= sprintf('%.2F M ',$critere_style['stroke-miterlimit']);
1037 }
1038 }
1039 // mPDF 4.4.003
1040 if (isset($critere_style['stroke-dasharray'])){
1041 $off = 0;
1042 $d = preg_split('/[ ,]/',$critere_style['stroke-dasharray']);
1043 if (count($d) == 1 && $d[0]==0) {
1044 $path_style .= '[] 0 d ';
1045 }
1046 else {
1047 if (count($d) % 2 == 1) { $d = array_merge($d, $d); } // 5, 3, 1 => 5,3,1,5,3,1 OR 3 => 3,3
1048 $arr = '';
1049 for($i=0; $i<count($d); $i+=2) {
1050 $arr .= sprintf('%.3F %.3F ', $d[$i]*$this->kp, $d[$i+1]*$this->kp);
1051 }
1052 if (isset($critere_style['stroke-dashoffset'])){ $off = $critere_style['stroke-dashoffset'] + 0; }
1053 $path_style .= sprintf('[%s] %.3F d ', $arr, $off*$this->kp);
1054 }
1055 }
1056 }
1057
1058 // mPDF 4.4.003
1059 if ($critere_style['fill-rule']=='evenodd') { $fr = '*'; }
1060 else { $fr = ''; }
1061
1062 // mPDF 4.4.003
1063 if (isset($critere_style['fill-opacity'])) {
1064 $opacity = 1;
1065 if ($critere_style['fill-opacity'] == 0) { $opacity = 0; }
1066 else if ($critere_style['fill-opacity'] > 1) { $opacity = 1; }
1067 else if ($critere_style['fill-opacity'] > 0) { $opacity = $critere_style['fill-opacity']; }
1068 else if ($critere_style['fill-opacity'] < 0) { $opacity = 0; }
1069 $gs = $this->mpdf_ref->AddExtGState(array('ca'=>$opacity, 'BM'=>'/Normal'));
1070 $this->mpdf_ref->extgstates[$gs]['fo'] = true; // mPDF 5.0.039
1071 $path_style .= sprintf(' /GS%d gs ', $gs);
1072 }
1073
1074 // mPDF 4.4.003
1075 if (isset($critere_style['stroke-opacity'])) {
1076 $opacity = 1;
1077 if ($critere_style['stroke-opacity'] == 0) { $opacity = 0; }
1078 else if ($critere_style['stroke-opacity'] > 1) { $opacity = 1; }
1079 else if ($critere_style['stroke-opacity'] > 0) { $opacity = $critere_style['stroke-opacity']; }
1080 else if ($critere_style['stroke-opacity'] < 0) { $opacity = 0; }
1081 $gs = $this->mpdf_ref->AddExtGState(array('CA'=>$opacity, 'BM'=>'/Normal'));
1082 $this->mpdf_ref->extgstates[$gs]['fo'] = true; // mPDF 5.0.039
1083 $path_style .= sprintf(' /GS%d gs ', $gs);
1084 }
1085
1086 switch ($style){
1087 case 'F':
1088 $op = 'f';
1089 break;
1090 case 'FD':
1091 $op = 'B';
1092 break;
1093 case 'ND':
1094 $op = 'S';
1095 break;
1096 case 'D':
1097 $op = 'S';
1098 break;
1099 default:
1100 $op = 'n';
1101 }
1102
1103 // mPDF 5.0
1104 $prestyle = $path_style.' ';
1105 $poststyle = $w.' '. $op.$fr.' '.$fill_gradient."\n";
1106 return array($prestyle,$poststyle);
1107
1108 }
1109
1110 //
1111 // fonction retracant les <path />
1112 function svgPath($command, $arguments){
1113 $path_cmd = '';
1114 $newsubpath = false; // mPDF 4.4.003
1115 // mPDF 5.0.039
1116 $minl = $this->pathBBox[0];
1117 $mint = $this->pathBBox[1];
1118 $maxr = $this->pathBBox[2]+$this->pathBBox[0];
1119 $maxb = $this->pathBBox[3]+$this->pathBBox[1];
1120 // mPDF 5.0.040
1121 $start = array($this->xbase, -$this->ybase);
1122
1123 // mPDF 4.4.003
1124 preg_match_all('/[\-^]?[\d.]+(e[\-]?[\d]+){0,1}/i', $arguments, $a, PREG_SET_ORDER);
1125
1126 // if the command is a capital letter, the coords go absolute, otherwise relative
1127 if(strtolower($command) == $command) $relative = true;
1128 else $relative = false;
1129
1130
1131 $ile_argumentow = count($a);
1132
1133 // each command may have different needs for arguments [1 to 8]
1134
1135 switch(strtolower($command)){
1136 case 'm': // move
1137 for($i = 0; $i<$ile_argumentow; $i+=2){
1138 $x = $a[$i][0];
1139 $y = $a[$i+1][0];
1140 if($relative){
1141 $pdfx = ($this->xbase + $x);
1142 $pdfy = ($this->ybase - $y);
1143 $this->xbase += $x;
1144 $this->ybase += -$y;
1145 }
1146 else{
1147 $pdfx = $x;
1148 $pdfy = -$y ;
1149 $this->xbase = $x;
1150 $this->ybase = -$y;
1151 }
1152 $pdf_pt = $this->svg_overflow($pdfx,$pdfy);
1153 // mPDF 5.0.039
1154 $minl = min($minl,$pdf_pt['x']);
1155 $maxr = max($maxr,$pdf_pt['x']);
1156 $mint = min($mint,-$pdf_pt['y']);
1157 $maxb = max($maxb,-$pdf_pt['y']);
1158 if($i == 0) $path_cmd .= sprintf('%.3F %.3F m ', $pdf_pt['x']*$this->kp, $pdf_pt['y']*$this->kp);
1159 else $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x']*$this->kp, $pdf_pt['y']*$this->kp);
1160 // mPDF 4.4.003 Save start points of subpath
1161 if ($this->subPathInit) {
1162 $this->spxstart = $this->xbase;
1163 $this->spystart = $this->ybase;
1164 $this->subPathInit = false;
1165 }
1166 }
1167 break;
1168 case 'l': // a simple line
1169 for($i = 0; $i<$ile_argumentow; $i+=2){
1170 $x = ($a[$i][0]);
1171 $y = ($a[$i+1][0]);
1172 if($relative){
1173 $pdfx = ($this->xbase + $x);
1174 $pdfy = ($this->ybase - $y);
1175 $this->xbase += $x;
1176 $this->ybase += -$y;
1177 }
1178 else{
1179 $pdfx = $x ;
1180 $pdfy = -$y ;
1181 $this->xbase = $x;
1182 $this->ybase = -$y;
1183 }
1184 $pdf_pt = $this->svg_overflow($pdfx,$pdfy);
1185 // mPDF 5.0.039
1186 $minl = min($minl,$pdf_pt['x']);
1187 $maxr = max($maxr,$pdf_pt['x']);
1188 $mint = min($mint,-$pdf_pt['y']);
1189 $maxb = max($maxb,-$pdf_pt['y']);
1190 $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x']*$this->kp, $pdf_pt['y']*$this->kp);
1191 }
1192 break;
1193 case 'h': // a very simple horizontal line
1194 for($i = 0; $i<$ile_argumentow; $i++){
1195 $x = ($a[$i][0]);
1196 if($relative){
1197 $y = 0;
1198 $pdfx = ($this->xbase + $x) ;
1199 $pdfy = ($this->ybase - $y) ;
1200 $this->xbase += $x;
1201 $this->ybase += -$y;
1202 }
1203 else{
1204 $y = -$this->ybase;
1205 $pdfx = $x;
1206 $pdfy = -$y;
1207 $this->xbase = $x;
1208 $this->ybase = -$y;
1209 }
1210 $pdf_pt = $this->svg_overflow($pdfx,$pdfy);
1211 // mPDF 5.0.039
1212 $minl = min($minl,$pdf_pt['x']);
1213 $maxr = max($maxr,$pdf_pt['x']);
1214 $mint = min($mint,-$pdf_pt['y']);
1215 $maxb = max($maxb,-$pdf_pt['y']);
1216 $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x']*$this->kp, $pdf_pt['y']*$this->kp);
1217 }
1218 break;
1219 case 'v': // the simplest line, vertical
1220 for($i = 0; $i<$ile_argumentow; $i++){
1221 $y = ($a[$i][0]);
1222 if($relative){
1223 $x = 0;
1224 $pdfx = ($this->xbase + $x);
1225 $pdfy = ($this->ybase - $y);
1226 $this->xbase += $x;
1227 $this->ybase += -$y;
1228 }
1229 else{
1230 $x = $this->xbase;
1231 $pdfx = $x;
1232 $pdfy = -$y;
1233 $this->xbase = $x;
1234 $this->ybase = -$y;
1235 }
1236 $pdf_pt = $this->svg_overflow($pdfx,$pdfy);
1237 // mPDF 5.0.039
1238 $minl = min($minl,$pdf_pt['x']);
1239 $maxr = max($maxr,$pdf_pt['x']);
1240 $mint = min($mint,-$pdf_pt['y']);
1241 $maxb = max($maxb,-$pdf_pt['y']);
1242 $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x']*$this->kp, $pdf_pt['y']*$this->kp);
1243 }
1244 break;
1245 case 's': // bezier with first vertex equal first control
1246 // mPDF 4.4.003
1247 if (!($this->lastcommand == 'C' || $this->lastcommand == 'c' || $this->lastcommand == 'S' || $this->lastcommand == 's')) {
1248 $this->lastcontrolpoints = array(0,0);
1249 }
1250 for($i = 0; $i<$ile_argumentow; $i += 4){
1251 $x1 = $this->lastcontrolpoints[0];
1252 $y1 = $this->lastcontrolpoints[1];
1253 $x2 = ($a[$i][0]);
1254 $y2 = ($a[$i+1][0]);
1255 $x = ($a[$i+2][0]);
1256 $y = ($a[$i+3][0]);
1257 if($relative){
1258 $pdfx1 = ($this->xbase + $x1);
1259 $pdfy1 = ($this->ybase - $y1);
1260 $pdfx2 = ($this->xbase + $x2);
1261 $pdfy2 = ($this->ybase - $y2);
1262 $pdfx = ($this->xbase + $x);
1263 $pdfy = ($this->ybase - $y);
1264 $this->xbase += $x;
1265 $this->ybase += -$y;
1266 }
1267 else{
1268 $pdfx1 = $this->xbase + $x1;
1269 $pdfy1 = $this->ybase -$y1;
1270 $pdfx2 = $x2;
1271 $pdfy2 = -$y2;
1272 $pdfx = $x;
1273 $pdfy = -$y;
1274 $this->xbase = $x;
1275 $this->ybase = -$y;
1276 }
1277 $this->lastcontrolpoints = array(($pdfx-$pdfx2),-($pdfy-$pdfy2)); // mPDF 4.4.003 always relative
1278
1279 $pdf_pt = $this->svg_overflow($pdfx,$pdfy);
1280
1281 // mPDF 5.0.040
1282 $curves = array($pdfx1,-$pdfy1,$pdfx2,-$pdfy2,$pdfx,-$pdfy);
1283 $bx = calc_bezier_bbox($start, $curves);
1284 $minl = min($minl,$bx[0]);
1285 $maxr = max($maxr,$bx[2]);
1286 $mint = min($mint,$bx[1]);
1287 $maxb = max($maxb,$bx[3]);
1288
1289 if( ($pdf_pt['x'] != $pdfx) || ($pdf_pt['y'] != $pdfy) )
1290 {
1291 $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x']*$this->kp, $pdf_pt['y']*$this->kp);
1292 }
1293 else
1294 {
1295 $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);
1296 }
1297
1298 }
1299 break;
1300 case 'c': // bezier with second vertex equal second control
1301 for($i = 0; $i<$ile_argumentow; $i += 6){
1302 $x1 = ($a[$i][0]);
1303 $y1 = ($a[$i+1][0]);
1304 $x2 = ($a[$i+2][0]);
1305 $y2 = ($a[$i+3][0]);
1306 $x = ($a[$i+4][0]);
1307 $y = ($a[$i+5][0]);
1308
1309
1310 if($relative){
1311 $pdfx1 = ($this->xbase + $x1);
1312 $pdfy1 = ($this->ybase - $y1);
1313 $pdfx2 = ($this->xbase + $x2);
1314 $pdfy2 = ($this->ybase - $y2);
1315 $pdfx = ($this->xbase + $x);
1316 $pdfy = ($this->ybase - $y);
1317 $this->xbase += $x;
1318 $this->ybase += -$y;
1319 }
1320 else{
1321 $pdfx1 = $x1;
1322 $pdfy1 = -$y1;
1323 $pdfx2 = $x2;
1324 $pdfy2 = -$y2;
1325 $pdfx = $x;
1326 $pdfy = -$y;
1327 $this->xbase = $x;
1328 $this->ybase = -$y;
1329 }
1330 $this->lastcontrolpoints = array(($pdfx-$pdfx2),-($pdfy-$pdfy2)); // mPDF 4.4.003 always relative
1331 // $pdf_pt2 = $this->svg_overflow($pdfx2,$pdfy2);
1332 // $pdf_pt1 = $this->svg_overflow($pdfx1,$pdfy1);
1333 $pdf_pt = $this->svg_overflow($pdfx,$pdfy);
1334
1335 // mPDF 5.0.040
1336 $curves = array($pdfx1,-$pdfy1,$pdfx2,-$pdfy2,$pdfx,-$pdfy);
1337 $bx = calc_bezier_bbox($start, $curves);
1338 $minl = min($minl,$bx[0]);
1339 $maxr = max($maxr,$bx[2]);
1340 $mint = min($mint,$bx[1]);
1341 $maxb = max($maxb,$bx[3]);
1342
1343 if( ($pdf_pt['x'] != $pdfx) || ($pdf_pt['y'] != $pdfy) )
1344 {
1345 $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x']*$this->kp, $pdf_pt['y']*$this->kp);
1346 }
1347 else
1348 {
1349 $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);
1350 }
1351
1352 }
1353 break;
1354
1355 case 'q': // bezier quadratic avec point de control
1356 for($i = 0; $i<$ile_argumentow; $i += 4){
1357 $x1 = ($a[$i][0]);
1358 $y1 = ($a[$i+1][0]);
1359 $x = ($a[$i+2][0]);
1360 $y = ($a[$i+3][0]);
1361 if($relative){
1362 $pdfx = ($this->xbase + $x);
1363 $pdfy = ($this->ybase - $y);
1364
1365 $pdfx1 = ($this->xbase + ($x1*2/3));
1366 $pdfy1 = ($this->ybase - ($y1*2/3));
1367 // mPDF 4.4.003
1368 $pdfx2 = $pdfx1 + 1/3 *($x);
1369 $pdfy2 = $pdfy1 + 1/3 *(-$y) ;
1370
1371 $this->xbase += $x;
1372 $this->ybase += -$y;
1373 }
1374 else{
1375 $pdfx = $x;
1376 $pdfy = -$y;
1377
1378 $pdfx1 = ($this->xbase+(($x1-$this->xbase)*2/3));
1379 $pdfy1 = ($this->ybase-(($y1+$this->ybase)*2/3));
1380
1381 $pdfx2 = ($x+(($x1-$x)*2/3));
1382 $pdfy2 = (-$y-(($y1-$y)*2/3));
1383
1384 // mPDF 4.4.003
1385 $pdfx2 = $pdfx1 + 1/3 *($x - $this->xbase);
1386 $pdfy2 = $pdfy1 + 1/3 *(-$y - $this->ybase) ;
1387
1388 $this->xbase = $x;
1389 $this->ybase = -$y;
1390 }
1391 $this->lastcontrolpoints = array(($pdfx-$pdfx2),-($pdfy-$pdfy2)); // mPDF 4.4.003 always relative
1392
1393 $pdf_pt = $this->svg_overflow($pdfx,$pdfy);
1394
1395 // mPDF 5.0.040
1396 $curves = array($pdfx1,-$pdfy1,$pdfx2,-$pdfy2,$pdfx,-$pdfy);
1397 $bx = calc_bezier_bbox($start, $curves);
1398 $minl = min($minl,$bx[0]);
1399 $maxr = max($maxr,$bx[2]);
1400 $mint = min($mint,$bx[1]);
1401 $maxb = max($maxb,$bx[3]);
1402
1403 if( ($pdf_pt['x'] != $pdfx) || ($pdf_pt['y'] != $pdfy) )
1404 {
1405 $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x']*$this->kp, $pdf_pt['y']*$this->kp);
1406 }
1407 else
1408 {
1409 $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);
1410 }
1411 }
1412 break;
1413 case 't': // bezier quadratic avec point de control simetrique a lancien point de control
1414 // mPDF 4.4.003
1415 if (!($this->lastcommand == 'Q' || $this->lastcommand == 'q' || $this->lastcommand == 'T' || $this->lastcommand == 't')) {
1416 $this->lastcontrolpoints = array(0,0);
1417 }
1418 for($i = 0; $i<$ile_argumentow; $i += 2){
1419 $x = ($a[$i][0]);
1420 $y = ($a[$i+1][0]);
1421
1422 $x1 = $this->lastcontrolpoints[0];
1423 $y1 = $this->lastcontrolpoints[1];
1424
1425 if($relative){
1426 $pdfx = ($this->xbase + $x);
1427 $pdfy = ($this->ybase - $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);
1433 $pdfy2 = $pdfy1 + 1/3 *(-$y) ;
1434
1435 $this->xbase += $x;
1436 $this->ybase += -$y;
1437 }
1438 else{
1439 $pdfx = $x;
1440 $pdfy = -$y;
1441
1442 $pdfx1 = ($this->xbase + ($x1)); // mPDF 4.4.003
1443 $pdfy1 = ($this->ybase - ($y1)); // mPDF 4.4.003
1444 // mPDF 4.4.003
1445 $pdfx2 = $pdfx1 + 1/3 *($x - $this->xbase);
1446 $pdfy2 = $pdfy1 + 1/3 *(-$y - $this->ybase) ;
1447
1448 $this->xbase = $x;
1449 $this->ybase = -$y;
1450 }
1451
1452 $this->lastcontrolpoints = array(($pdfx-$pdfx2),-($pdfy-$pdfy2)); // mPDF 4.4.003 always relative
1453
1454 // mPDF 5.0.040
1455 $curves = array($pdfx1,-$pdfy1,$pdfx2,-$pdfy2,$pdfx,-$pdfy);
1456 $bx = calc_bezier_bbox($start, $curves);
1457 $minl = min($minl,$bx[0]);
1458 $maxr = max($maxr,$bx[2]);
1459 $mint = min($mint,$bx[1]);
1460 $maxb = max($maxb,$bx[3]);
1461
1462 $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);
1463 }
1464
1465 break;
1466 case 'a': // Elliptical arc
1467 for($i = 0; $i<$ile_argumentow; $i += 7){
1468 $rx = ($a[$i][0]);
1469 $ry = ($a[$i+1][0]);
1470 $angle = ($a[$i+2][0]); //x-axis-rotation
1471 $largeArcFlag = ($a[$i+3][0]);
1472 $sweepFlag = ($a[$i+4][0]);
1473 $x2 = ($a[$i+5][0]);
1474 $y2 = ($a[$i+6][0]);
1475 $x1 = $this->xbase;
1476 $y1 = -$this->ybase;
1477 if($relative){
1478 $x2 = $this->xbase + $x2;
1479 $y2 = -$this->ybase + $y2;
1480 $this->xbase += ($a[$i+5][0]);
1481 $this->ybase += -($a[$i+6][0]);
1482 }
1483 else{
1484 $this->xbase = $x2;
1485 $this->ybase = -$y2;
1486 }
1487 // mPDF 5.0.039 // mPDF 5.0.040
1488 list($pcmd, $bounds) = $this->Arcto($x1, $y1, $x2, $y2, $rx, $ry, $angle, $largeArcFlag, $sweepFlag);
1489 $minl = min($minl,$x2,min($bounds[0]));
1490 $maxr = max($maxr,$x2,max($bounds[0]));
1491 $mint = min($mint,$y2,min($bounds[1]));
1492 $maxb = max($maxb,$y2,max($bounds[1]));
1493 $path_cmd .= $pcmd;
1494
1495 }
1496 break;
1497 case'z':
1498 $path_cmd .= 'h ';
1499 // mPDF 4.4.003
1500 $this->subPathInit = true;
1501 $newsubpath = true;
1502 $this->xbase = $this->spxstart;
1503 $this->ybase = $this->spystart;
1504 break;
1505 default:
1506 break;
1507 }
1508
1509 if (!$newsubpath) { $this->subPathInit = false; } // mPDF 4.4.003
1510 $this->lastcommand = $command;
1511 // mPDF 5.0.039
1512 $this->pathBBox[0] = $minl;
1513 $this->pathBBox[1] = $mint;
1514 $this->pathBBox[2] = $maxr - $this->pathBBox[0];
1515 $this->pathBBox[3] = $maxb - $this->pathBBox[1];
1516 return $path_cmd;
1517
1518 }
1519
1520function Arcto($x1, $y1, $x2, $y2, $rx, $ry, $angle, $largeArcFlag, $sweepFlag) {
1521
1522 // mPDF 5.0.040
1523 $bounds = array(0=>array($x1,$x2),1=>array($y1,$y2));
1524 // 1. Treat out-of-range parameters as described in
1525 // http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
1526 // If the endpoints (x1, y1) and (x2, y2) are identical, then this
1527 // is equivalent to omitting the elliptical arc segment entirely
1528 if ($x1 == $x2 && $y1 == $y2) return array('', $bounds); // mPD 5.0.040
1529
1530 // If rX = 0 or rY = 0 then this arc is treated as a straight line
1531 // segment (a "lineto") joining the endpoints.
1532 if ($rx == 0.0 || $ry == 0.0) {
1533 // return array(Lineto(x2, y2), $bounds); // mPD 5.0.040
1534 }
1535
1536 // If rX or rY have negative signs, these are dropped; the absolute
1537 // value is used instead.
1538 if ($rx<0.0) $rx = -$rx;
1539 if ($ry<0.0) $ry = -$ry;
1540
1541 // 2. convert to center parameterization as shown in
1542 // http://www.w3.org/TR/SVG/implnote.html
1543 $sinPhi = sin(deg2rad($angle));
1544 $cosPhi = cos(deg2rad($angle));
1545
1546 $x1dash = $cosPhi * ($x1-$x2)/2.0 + $sinPhi * ($y1-$y2)/2.0;
1547 $y1dash = -$sinPhi * ($x1-$x2)/2.0 + $cosPhi * ($y1-$y2)/2.0;
1548
1549
1550 $numerator = $rx*$rx*$ry*$ry - $rx*$rx*$y1dash*$y1dash - $ry*$ry*$x1dash*$x1dash;
1551
1552 if ($numerator < 0.0) {
1553 // If rX , rY and are such that there is no solution (basically,
1554 // the ellipse is not big enough to reach from (x1, y1) to (x2,
1555 // y2)) then the ellipse is scaled up uniformly until there is
1556 // exactly one solution (until the ellipse is just big enough).
1557
1558 // -> find factor s, such that numerator' with rx'=s*rx and
1559 // ry'=s*ry becomes 0 :
1560 $s = sqrt(1.0 - $numerator/($rx*$rx*$ry*$ry));
1561
1562 $rx *= $s;
1563 $ry *= $s;
1564 $root = 0.0;
1565
1566 }
1567 else {
1568 $root = ($largeArcFlag == $sweepFlag ? -1.0 : 1.0) * sqrt( $numerator/($rx*$rx*$y1dash*$y1dash+$ry*$ry*$x1dash*$x1dash) );
1569 }
1570
1571 $cxdash = $root*$rx*$y1dash/$ry;
1572 $cydash = -$root*$ry*$x1dash/$rx;
1573
1574 $cx = $cosPhi * $cxdash - $sinPhi * $cydash + ($x1+$x2)/2.0;
1575 $cy = $sinPhi * $cxdash + $cosPhi * $cydash + ($y1+$y2)/2.0;
1576
1577
1578 $theta1 = $this->CalcVectorAngle(1.0, 0.0, ($x1dash-$cxdash)/$rx, ($y1dash-$cydash)/$ry);
1579 $dtheta = $this->CalcVectorAngle(($x1dash-$cxdash)/$rx, ($y1dash-$cydash)/$ry, (-$x1dash-$cxdash)/$rx, (-$y1dash-$cydash)/$ry);
1580 if (!$sweepFlag && $dtheta>0)
1581 $dtheta -= 2.0*M_PI;
1582 else if ($sweepFlag && $dtheta<0)
1583 $dtheta += 2.0*M_PI;
1584
1585 // 3. convert into cubic bezier segments <= 90deg
1586 $segments = ceil(abs($dtheta/(M_PI/2.0)));
1587 $delta = $dtheta/$segments;
1588 $t = 8.0/3.0 * sin($delta/4.0) * sin($delta/4.0) / sin($delta/2.0);
1589 $coords = array();
1590 for ($i = 0; $i < $segments; $i++) {
1591 $cosTheta1 = cos($theta1);
1592 $sinTheta1 = sin($theta1);
1593 $theta2 = $theta1 + $delta;
1594 $cosTheta2 = cos($theta2);
1595 $sinTheta2 = sin($theta2);
1596
1597 // a) calculate endpoint of the segment:
1598 $xe = $cosPhi * $rx*$cosTheta2 - $sinPhi * $ry*$sinTheta2 + $cx;
1599 $ye = $sinPhi * $rx*$cosTheta2 + $cosPhi * $ry*$sinTheta2 + $cy;
1600
1601 // b) calculate gradients at start/end points of segment:
1602 $dx1 = $t * ( - $cosPhi * $rx*$sinTheta1 - $sinPhi * $ry*$cosTheta1);
1603 $dy1 = $t * ( - $sinPhi * $rx*$sinTheta1 + $cosPhi * $ry*$cosTheta1);
1604
1605 $dxe = $t * ( $cosPhi * $rx*$sinTheta2 + $sinPhi * $ry*$cosTheta2);
1606 $dye = $t * ( $sinPhi * $rx*$sinTheta2 - $cosPhi * $ry*$cosTheta2);
1607
1608 // c) draw the cubic bezier:
1609 $coords[$i] = array(($x1+$dx1), ($y1+$dy1), ($xe+$dxe), ($ye+$dye), $xe, $ye);
1610
1611 // do next segment
1612 $theta1 = $theta2;
1613 $x1 = $xe;
1614 $y1 = $ye;
1615 }
1616 $path = ' ';
1617 foreach($coords AS $c) {
1618 $cpx1 = $c[0];
1619 $cpy1 = $c[1];
1620 $cpx2 = $c[2];
1621 $cpy2 = $c[3];
1622 $x2 = $c[4];
1623 $y2 = $c[5];
1624 $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";
1625
1626 // mPDF 5.0.040
1627 $bounds[0][] = $c[4];
1628 $bounds[1][] = $c[5];
1629 }
1630 return array($path, $bounds); // mPD 5.0.040
1631}
1632
1633
1634 function CalcVectorAngle($ux, $uy, $vx, $vy) {
1635 $ta = atan2($uy, $ux);
1636 $tb = atan2($vy, $vx);
1637 if ($tb >= $ta)
1638 return ($tb-$ta);
1639 return (6.28318530718 - ($ta-$tb));
1640 }
1641
1642
1643 // mPDF 4.4.003
1644 function ConvertSVGSizePixels($size=5,$maxsize='x'){
1645 // maxsize in pixels (user units) or 'y' or 'x'
1646 // e.g. $w = $this->ConvertSVGSizePixels($arguments['w'],$this->svg_info['w']*(25.4/$this->mpdf_ref->dpi));
1647 // usefontsize - setfalse for e.g. margins - will ignore fontsize for % values
1648 // Depends of maxsize value to make % work properly. Usually maxsize == pagewidth
1649 // For text $maxsize = Fontsize
1650 // Setting e.g. margin % will use maxsize (pagewidth) and em will use fontsize
1651
1652 if ($maxsize == 'y') { $maxsize = $this->svg_info['h']; }
1653 else if ($maxsize == 'x') { $maxsize = $this->svg_info['w']; }
1654 $maxsize *= (25.4/$this->mpdf_ref->dpi); // convert pixels to mm
1655 $fontsize=$this->mpdf_ref->FontSize;
1656 //Return as pixels
1657 $size = $this->mpdf_ref->ConvertSize($size,$maxsize,$fontsize,false) * 1/(25.4/$this->mpdf_ref->dpi);
1658 return $size;
1659 }
1660
1661 // mPDF 4.4.003
1662 function ConvertSVGSizePts($size=5){
1663 // usefontsize - setfalse for e.g. margins - will ignore fontsize for % values
1664 // Depends of maxsize value to make % work properly. Usually maxsize == pagewidth
1665 // For text $maxsize = Fontsize
1666 // Setting e.g. margin % will use maxsize (pagewidth) and em will use fontsize
1667 $maxsize=$this->mpdf_ref->FontSize;
1668 //Return as pts
1669 $size = $this->mpdf_ref->ConvertSize($size,$maxsize,false,true) * 72/25.4;
1670 return $size;
1671 }
1672
1673
1674 //
1675 // fonction retracant les <rect />
1676 function svgRect($arguments){
1677
1678 if ($arguments['h']==0 || $arguments['w']==0) { return ''; } // mPDF 4.4.003
1679
1680 $x = $this->ConvertSVGSizePixels($arguments['x'],'x'); // mPDF 4.4.003
1681 $y = $this->ConvertSVGSizePixels($arguments['y'],'y'); // mPDF 4.4.003
1682 $h = $this->ConvertSVGSizePixels($arguments['h'],'y'); // mPDF 4.4.003
1683 $w = $this->ConvertSVGSizePixels($arguments['w'],'x'); // mPDF 4.4.003
1684 $rx = $this->ConvertSVGSizePixels($arguments['rx'],'x'); // mPDF 4.4.003
1685 $ry = $this->ConvertSVGSizePixels($arguments['ry'],'y'); // mPDF 4.4.003
1686
1687 if ($rx > $w/2) { $rx = $w/2; } // mPDF 4.4.003
1688 if ($ry > $h/2) { $ry = $h/2; } // mPDF 4.4.003
1689
1690 if ($rx>0 and $ry == 0){$ry = $rx;}
1691 if ($ry>0 and $rx == 0){$rx = $ry;}
1692
1693 if ($rx == 0 and $ry == 0){
1694 // trace un rectangle sans angle arrondit
1695 $path_cmd = sprintf('%.3F %.3F m ', ($x*$this->kp), -($y*$this->kp));
1696 $path_cmd .= sprintf('%.3F %.3F l ', (($x+$w)*$this->kp), -($y*$this->kp));
1697 $path_cmd .= sprintf('%.3F %.3F l ', (($x+$w)*$this->kp), -(($y+$h)*$this->kp));
1698 $path_cmd .= sprintf('%.3F %.3F l ', ($x)*$this->kp, -(($y+$h)*$this->kp));
1699 $path_cmd .= sprintf('%.3F %.3F l h ', ($x*$this->kp), -($y*$this->kp));
1700
1701
1702 }
1703 else {
1704 // trace un rectangle avec les arrondit
1705 // les points de controle du bezier sont deduis grace a la constante kappa
1706 $kappa = 4*(sqrt(2)-1)/3;
1707
1708 $kx = $kappa*$rx;
1709 $ky = $kappa*$ry;
1710
1711 $path_cmd = sprintf('%.3F %.3F m ', ($x+$rx)*$this->kp, -$y*$this->kp);
1712 $path_cmd .= sprintf('%.3F %.3F l ', ($x+($w-$rx))*$this->kp, -$y*$this->kp);
1713 $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 );
1714 $path_cmd .= sprintf('%.3F %.3F l ', ($x+$w)*$this->kp, (-$y+(-$h+$ry))*$this->kp);
1715 $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 );
1716
1717 $path_cmd .= sprintf('%.3F %.3F l ', ($x+$rx)*$this->kp, (-$y+(-$h))*$this->kp);
1718 $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 );
1719 $path_cmd .= sprintf('%.3F %.3F l ', $x*$this->kp, (-$y+(-$ry))*$this->kp);
1720 $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 );
1721
1722
1723 }
1724 return $path_cmd;
1725 }
1726
1727 //
1728 // fonction retracant les <ellipse /> et <circle />
1729 // le cercle est tracé grave a 4 bezier cubic, les poitn de controles
1730 // sont deduis grace a la constante kappa * rayon
1731 function svgEllipse($arguments){
1732 if ($arguments['rx']==0 || $arguments['ry']==0) { return ''; } // mPDF 4.4.003
1733
1734 $kappa = 4*(sqrt(2)-1)/3;
1735
1736 $cx = $this->ConvertSVGSizePixels($arguments['cx'],'x'); // mPDF 4.4.003
1737 $cy = $this->ConvertSVGSizePixels($arguments['cy'],'y'); // mPDF 4.4.003
1738 $rx = $this->ConvertSVGSizePixels($arguments['rx'],'x'); // mPDF 4.4.003
1739 $ry = $this->ConvertSVGSizePixels($arguments['ry'],'y'); // mPDF 4.4.003
1740
1741 $x1 = $cx;
1742 $y1 = -$cy+$ry;
1743
1744 $x2 = $cx+$rx;
1745 $y2 = -$cy;
1746
1747 $x3 = $cx;
1748 $y3 = -$cy-$ry;
1749
1750 $x4 = $cx-$rx;
1751 $y4 = -$cy;
1752
1753 $path_cmd = sprintf('%.3F %.3F m ', $x1*$this->kp, $y1*$this->kp);
1754 $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);
1755 $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);
1756 $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);
1757 $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);
1758 $path_cmd .= 'h ';
1759
1760 return $path_cmd;
1761
1762 }
1763
1764 //
1765 // fonction retracant les <polyline /> et les <line />
1766 function svgPolyline($arguments,$ispolyline=true){
1767 if ($ispolyline) {
1768 $xbase = $arguments[0] ;
1769 $ybase = - $arguments[1] ;
1770 }
1771 else {
1772 if ($arguments[0]==$arguments[2] && $arguments[1]==$arguments[3]) { return ''; } // mPDF 4.4.003 Zero length line
1773 $xbase = $this->ConvertSVGSizePixels($arguments[0],'x'); // mPDF 4.4.003
1774 $ybase = - $this->ConvertSVGSizePixels($arguments[1],'y'); // mPDF 4.4.003
1775 }
1776 $path_cmd = sprintf('%.3F %.3F m ', $xbase*$this->kp, $ybase*$this->kp);
1777 for ($i = 2; $i<count($arguments);$i += 2) {
1778 if ($ispolyline) {
1779 $tmp_x = $arguments[$i] ;
1780 $tmp_y = - $arguments[($i+1)] ;
1781 }
1782 else {
1783 $tmp_x = $this->ConvertSVGSizePixels($arguments[$i],'x') ; // mPDF 4.4.003
1784 $tmp_y = - $this->ConvertSVGSizePixels($arguments[($i+1)],'y') ; // mPDF 4.4.003
1785 }
1786 $path_cmd .= sprintf('%.3F %.3F l ', $tmp_x*$this->kp, $tmp_y*$this->kp);
1787 }
1788
1789 // $path_cmd .= 'h '; // ?? In error - don't close subpath here
1790 return $path_cmd;
1791
1792 }
1793
1794 //
1795 // fonction retracant les <polygone />
1796 function svgPolygon($arguments){
1797 $xbase = $arguments[0] ;
1798 $ybase = - $arguments[1] ;
1799 $path_cmd = sprintf('%.3F %.3F m ', $xbase*$this->kp, $ybase*$this->kp);
1800 for ($i = 2; $i<count($arguments);$i += 2) {
1801 $tmp_x = $arguments[$i] ;
1802 $tmp_y = - $arguments[($i+1)] ;
1803
1804 $path_cmd .= sprintf('%.3F %.3F l ', $tmp_x*$this->kp, $tmp_y*$this->kp);
1805
1806 }
1807 $path_cmd .= sprintf('%.3F %.3F l ', $xbase*$this->kp, $ybase*$this->kp);
1808 $path_cmd .= 'h ';
1809 return $path_cmd;
1810
1811 }
1812
1813 //
1814 // write string to image
1815 function svgText() {
1816 // $tmp = count($this->txt_style)-1;
1817 $current_style = array_pop($this->txt_style);
1818 $style = '';
1819 $render = -1;
1820 if(isset($this->txt_data[2]))
1821 {
1822 // select font
1823 $style .= ($current_style['font-weight'] == 'bold')?'B':'';
1824 $style .= ($current_style['font-style'] == 'italic')?'I':'';
1825 $size = $current_style['font-size']*$this->kf; // mPDF 5.0.039
1826
1827 // mPDF 5.0
1828 $current_style['font-family'] = $this->mpdf_ref->SetFont($current_style['font-family'],$style,$size,false);
1829 $this->mpdf_ref->CurrentFont['fo'] = true; // mPDF 5.0.039
1830
1831
1832 // mPDF 5.0.041
1833 $opacitystr = '';
1834 $opacity = 1;
1835 if (isset($current_style['fill-opacity'])) {
1836 if ($current_style['fill-opacity'] == 0) { $opacity = 0; }
1837 else if ($current_style['fill-opacity'] > 1) { $opacity = 1; }
1838 else if ($current_style['fill-opacity'] > 0) { $opacity = $current_style['fill-opacity']; }
1839 else if ($current_style['fill-opacity'] < 0) { $opacity = 0; }
1840 }
1841 $gs = $this->mpdf_ref->AddExtGState(array('ca'=>$opacity, 'BM'=>'/Normal'));
1842 $this->mpdf_ref->extgstates[$gs]['fo'] = true; // mPDF 5.0.039
1843 $opacitystr = sprintf(' /GS%d gs ', $gs);
1844
1845 // mPDF 5.0.051
1846 $fillstr = '';
1847 if (isset($current_style['fill']) && $current_style['fill']!='none') {
1848 $col = $this->mpdf_ref->ConvertColor($current_style['fill']);
1849 // mPDF 5.0.051
1850 $fillstr = $this->mpdf_ref->SetFColor($col, true);
1851 $render = "0"; // Fill (only)
1852 }
1853 $strokestr = '';
1854 if (isset($current_style['stroke-width']) && $current_style['stroke-width']>0 && $current_style['stroke']!='none') {
1855 $scol = $this->mpdf_ref->ConvertColor($current_style['stroke']);
1856 if ($scol) {
1857 $strokestr .= $this->mpdf_ref->SetDColor($scol, true).' '; // mPDF 5.0.051
1858 }
1859 $linewidth = $this->ConvertSVGSizePixels($current_style['stroke-width']);
1860 if ($linewidth > 0) {
1861 $strokestr .= sprintf('%.3F w 1 J 1 j ',$linewidth*$this->kp);
1862 if ($render == -1) { $render = "1"; } // stroke only
1863 else { $render = "2"; } // fill and stroke
1864 }
1865 }
1866 if ($render == -1) { return ''; }
1867
1868 $x = $this->ConvertSVGSizePixels($this->txt_data[0],'x'); // mPDF 4.4.003
1869 $y = $this->ConvertSVGSizePixels($this->txt_data[1],'y'); // mPDF 4.4.003
1870 $txt = $this->txt_data[2];
1871
1872 // mPDF 4.4.003
1873 $txt = preg_replace('/\f/','',$txt);
1874 $txt = preg_replace('/\r/','',$txt);
1875 $txt = preg_replace('/\n/',' ',$txt);
1876 $txt = preg_replace('/\t/',' ',$txt);
1877 $txt = preg_replace("/[ ]+/u",' ',$txt);
1878
1879 $txt = trim($txt);
1880
1881 $txt = $this->mpdf_ref->purify_utf8_text($txt);
1882 if ($this->mpdf_ref->text_input_as_HTML) {
1883 $txt = $this->mpdf_ref->all_entities_to_utf8($txt);
1884 }
1885
1886 // mPDF 5.0
1887 if ($this->mpdf_ref->usingCoreFont) { $txt = mb_convert_encoding($txt,$this->mpdf_ref->mb_enc,'UTF-8'); }
1888 if (preg_match("/([".$this->mpdf_ref->pregRTLchars."])/u", $txt)) { $this->mpdf_ref->biDirectional = true; } // mPDF 4.4.003
1889
1890 $this->mpdf_ref->magic_reverse_dir($txt, true, 'ltr'); // mPDF 5.0.054
1891 $this->mpdf_ref->ConvertIndic($txt);
1892
1893
1894 if ($current_style['text-anchor']=='middle') {
1895 $tw = $this->mpdf_ref->GetStringWidth($txt)*_MPDFK/2; // mPDF 4.4.003 // mPDF 5.4.09
1896 }
1897 else if ($current_style['text-anchor']=='end') {
1898 $tw = $this->mpdf_ref->GetStringWidth($txt)*_MPDFK; // mPDF 4.4.003 // mPDF 5.4.09
1899 }
1900 else $tw = 0;
1901
1902 if (!$this->mpdf_ref->usingCoreFont) {
1903 $this->mpdf_ref->UTF8StringToArray($txt); // mPDF 5.0 adds chars to subset list
1904 $txt= $this->mpdf_ref->UTF8ToUTF16BE($txt, false);
1905 }
1906 $txt='('.$this->mpdf_ref->_escape($txt).')';
1907 $this->mpdf_ref->CurrentFont['used']= true;
1908
1909 $pdfx = $x - $tw/$this->kp; // mPDF 4.4.009
1910 $pdfy = -$y ;
1911 $xbase = $x;
1912 $ybase = -$y;
1913
1914 // mPDF 5.7.2
1915 $path_cmd = sprintf('q BT /F%d %.3F Tf %s %.3F %.3F Td %s Tr %s %s %s Tj ET Q ',$this->mpdf_ref->CurrentFont['i'], $this->mpdf_ref->FontSizePt, $opacitystr, $pdfx*$this->kp,$pdfy*$this->kp,$render,$fillstr,$strokestr,$txt)."\n";
1916 unset($this->txt_data[0], $this->txt_data[1],$this->txt_data[2]);
1917
1918 if (isset($current_style['font-size-parent'])) {
1919 $this->mpdf_ref->SetFontSize($current_style['font-size-parent']);
1920 }
1921 }
1922 else
1923 {
1924 return ' ';
1925 }
1926 return $path_cmd;
1927 }
1928
1929
1930function svgDefineTxtStyle($critere_style)
1931{
1932 // get copy of current/default txt style, and modify it with supplied attributes
1933 $tmp = count($this->txt_style)-1;
1934 $current_style = $this->txt_style[$tmp];
1935 if (isset($critere_style['style'])){
1936 if (preg_match('/fill:\s*rgb\((\d+),\s*(\d+),\s*(\d+)\)/',$critere_style['style'], $m)) {
1937 $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);
1938 }
1939 else { $tmp = preg_replace("/(.*)fill:\s*([a-z0-9#_()]*|none)(.*)/i","$2",$critere_style['style']);
1940 if ($tmp != $critere_style['style']){ $current_style['fill'] = $tmp; }
1941 }
1942
1943 $tmp = preg_replace("/(.*)fill-opacity:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']);
1944 if ($tmp != $critere_style['style']){ $current_style['fill-opacity'] = $tmp;}
1945
1946 $tmp = preg_replace("/(.*)fill-rule:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']);
1947 if ($tmp != $critere_style['style']){ $current_style['fill-rule'] = $tmp;}
1948
1949 if (preg_match('/stroke:\s*rgb\((\d+),\s*(\d+),\s*(\d+)\)/',$critere_style['style'], $m)) {
1950 $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);
1951 }
1952 else { $tmp = preg_replace("/(.*)stroke:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']);
1953 if ($tmp != $critere_style['style']){ $current_style['stroke'] = $tmp; }
1954 }
1955
1956 $tmp = preg_replace("/(.*)stroke-linecap:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']);
1957 if ($tmp != $critere_style['style']){ $current_style['stroke-linecap'] = $tmp;}
1958
1959 $tmp = preg_replace("/(.*)stroke-linejoin:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']);
1960 if ($tmp != $critere_style['style']){ $current_style['stroke-linejoin'] = $tmp;}
1961
1962 $tmp = preg_replace("/(.*)stroke-miterlimit:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']);
1963 if ($tmp != $critere_style['style']){ $current_style['stroke-miterlimit'] = $tmp;}
1964
1965 $tmp = preg_replace("/(.*)stroke-opacity:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']);
1966 if ($tmp != $critere_style['style']){ $current_style['stroke-opacity'] = $tmp; }
1967
1968 $tmp = preg_replace("/(.*)stroke-width:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']);
1969 if ($tmp != $critere_style['style']){ $current_style['stroke-width'] = $tmp;}
1970
1971 $tmp = preg_replace("/(.*)stroke-dasharray:\s*([a-z0-9., ]*|none)(.*)/i","$2",$critere_style['style']);
1972 if ($tmp != $critere_style['style']){ $current_style['stroke-dasharray'] = $tmp;}
1973
1974 $tmp = preg_replace("/(.*)stroke-dashoffset:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']);
1975 if ($tmp != $critere_style['style']){ $current_style['stroke-dashoffset'] = $tmp;}
1976
1977 // mPDF 5.7.2
1978 $tmp = preg_replace("/(.*)font-family:\s*([a-z0-9.\"' ,\-]*|none)(.*)/i","$2",$critere_style['style']);
1979 if ($tmp != $critere_style['style']){ $critere_style['font-family'] = $tmp;}
1980
1981 $tmp = preg_replace("/(.*)font-size:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']);
1982 if ($tmp != $critere_style['style']){ $critere_style['font-size'] = $tmp;}
1983
1984 $tmp = preg_replace("/(.*)font-weight:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']);
1985 if ($tmp != $critere_style['style']){ $critere_style['font-weight'] = $tmp;}
1986
1987 $tmp = preg_replace("/(.*)font-style:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']);
1988 if ($tmp != $critere_style['style']){ $critere_style['font-style'] = $tmp;}
1989
1990 }
1991
1992 if (isset($critere_style['font'])){
1993
1994 // [ [ <'font-style'> || <'font-variant'> || <'font-weight'> ]?<'font-size'> [ / <'line-height'> ]? <'font-family'> ]
1995
1996 $tmp = preg_replace("/(.*)(italic|oblique)(.*)/i","$2",$critere_style['font']);
1997 if ($tmp != $critere_style['font']){
1998 if($tmp == 'oblique'){
1999 $tmp = 'italic';
2000 }
2001 $current_style['font-style'] = $tmp;
2002 }
2003 $tmp = preg_replace("/(.*)(bold|bolder)(.*)/i","$2",$critere_style['font']);
2004 if ($tmp != $critere_style['font']){
2005 if($tmp == 'bolder'){
2006 $tmp = 'bold';
2007 }
2008 $current_style['font-weight'] = $tmp;
2009 }
2010
2011 // select digits not followed by percent sign nor preceeded by forward slash
2012 $tmp = preg_replace("/(.*)\b(\d+)[\b|\/](.*)/i","$2",$critere_style['font']);
2013 if ($tmp != $critere_style['font']){
2014 $current_style['font-size'] = $this->ConvertSVGSizePts($tmp);
2015 $this->mpdf_ref->SetFont('','',$current_style['font-size'],false);
2016 }
2017
2018 }
2019
2020 if(isset($critere_style['fill'])){
2021 $current_style['fill'] = $critere_style['fill'];
2022 }
2023 if(isset($critere_style['stroke'])){
2024 $current_style['stroke'] = $critere_style['stroke'];
2025 }
2026 if(isset($critere_style['stroke-width'])){
2027 $current_style['stroke-width'] = $critere_style['stroke-width'];
2028 }
2029
2030 if(isset($critere_style['font-style'])){
2031 if(strtolower($critere_style['font-style']) == 'oblique')
2032 {
2033 $critere_style['font-style'] = 'italic';
2034 }
2035 $current_style['font-style'] = $critere_style['font-style'];
2036 }
2037
2038 if(isset($critere_style['font-weight'])){
2039 if(strtolower($critere_style['font-weight']) == 'bolder')
2040 {
2041 $critere_style['font-weight'] = 'bold';
2042 }
2043 $current_style['font-weight'] = $critere_style['font-weight'];
2044 }
2045
2046 if(isset($critere_style['font-size'])){
2047 // mPDF 5.4.12
2048 if (strpos($critere_style['font-size'], '%')!==false) {
2049 $current_style['font-size-parent'] = $current_style['font-size'];
2050 }
2051 $current_style['font-size'] = $this->ConvertSVGSizePts($critere_style['font-size']);
2052 $this->mpdf_ref->SetFont('','',$current_style['font-size'],false);
2053 }
2054
2055 if(isset($critere_style['font-family'])){
2056 $v = $critere_style['font-family'];
2057 $aux_fontlist = explode(",",$v);
2058 $found = 0;
2059 foreach($aux_fontlist AS $f) {
2060 $fonttype = trim($f);
2061 $fonttype = preg_replace('/["\']*(.*?)["\']*/','\\1',$fonttype);
2062 $fonttype = preg_replace('/ /','',$fonttype);
2063 $v = strtolower(trim($fonttype));
2064 if (isset($this->mpdf_ref->fonttrans[$v]) && $this->mpdf_ref->fonttrans[$v]) { $v = $this->mpdf_ref->fonttrans[$v]; }
2065 if ((!$this->mpdf_ref->usingCoreFont && in_array($v,$this->mpdf_ref->available_unifonts)) ||
2066 ($this->mpdf_ref->usingCoreFont && in_array($v,array('courier','times','helvetica','arial'))) ||
2067 in_array($v, array('sjis','uhc','big5','gb'))) {
2068 $current_style['font-family'] = $v;
2069 $found = 1;
2070 break;
2071 }
2072 }
2073 if (!$found) {
2074 foreach($aux_fontlist AS $f) {
2075 $fonttype = trim($f);
2076 $fonttype = preg_replace('/["\']*(.*?)["\']*/','\\1',$fonttype);
2077 $fonttype = preg_replace('/ /','',$fonttype);
2078 $v = strtolower(trim($fonttype));
2079 if (isset($this->mpdf_ref->fonttrans[$v]) && $this->mpdf_ref->fonttrans[$v]) { $v = $this->mpdf_ref->fonttrans[$v]; }
2080 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) ) {
2081 $current_style['font-family'] = $v;
2082 break;
2083 }
2084 }
2085 }
2086 }
2087
2088 if(isset($critere_style['text-anchor'])){
2089 $current_style['text-anchor'] = $critere_style['text-anchor'];
2090 }
2091
2092 // add current style to text style array (will remove it later after writing text to svg_string)
2093 array_push($this->txt_style,$current_style);
2094}
2095
2096
2097
2098 //
2099 // fonction ajoutant un gradient
2100 function svgAddGradient($id,$array_gradient){
2101
2102 $this->svg_gradient[$id] = $array_gradient;
2103
2104 }
2105 //
2106 // Ajoute une couleur dans le gradient correspondant
2107
2108 //
2109 // function ecrivant dans le svgstring
2110 function svgWriteString($content){
2111
2112 $this->svg_string .= $content;
2113
2114 }
2115
2116
2117
2118 // analise le svg et renvoie aux fonctions precedente our le traitement
2119 function ImageSVG($data){
2120 $this->svg_info = array();
2121
2122 // mPDF 4.4.006
2123 if (preg_match('/<!ENTITY/si',$data)) {
2124 // Get User-defined entities
2125 preg_match_all('/<!ENTITY\s+([a-z]+)\s+\"(.*?)\">/si',$data, $ent);
2126 // Replace entities
2127 for ($i=0; $i<count($ent[0]); $i++) {
2128 $data = preg_replace('/&'.preg_quote($ent[1][$i],'/').';/is', $ent[2][$i], $data);
2129 }
2130 }
2131
2132
2133 if (preg_match('/xlink:href=/si',$data)) {
2134 // GRADIENTS
2135 // Get links
2136 preg_match_all('/(<(linearGradient|radialgradient)[^>]*)xlink:href=["\']#(.*?)["\'](.*?)\/>/si',$data, $links);
2137 if (count($links[0])) { $links[5] = array(); }
2138 // Delete links from data - keeping in $links
2139 for ($i=0; $i<count($links[0]); $i++) {
2140 $links[5][$i] = 'tmpLink'.RAND(100000,9999999);
2141 $data = preg_replace('/'.preg_quote($links[0][$i],'/').'/is', '<MYLINKS'.$links[5][$i].'>' , $data);
2142 }
2143 // Get targets
2144 preg_match_all('/<(linearGradient|radialgradient)([^>]*)id=["\'](.*?)["\'](.*?)>(.*?)<\/(linearGradient|radialgradient)>/si',$data, $m);
2145 $targets = array();
2146 $stops = array();
2147 // keeping in $targets
2148 for ($i=0; $i<count($m[0]); $i++) {
2149 $stops[$m[3][$i]] = $m[5][$i];
2150 }
2151 // Add back links this time as targets (gradients)
2152 for ($i=0; $i<count($links[0]); $i++) {
2153 $def = $links[1][$i] .' '.$links[4][$i].'>'. $stops[$links[3][$i]].'</'.$links[2][$i] .'>' ;
2154 $data = preg_replace('/<MYLINKS'.$links[5][$i].'>/is', $def , $data);
2155 }
2156
2157 // mPDF 5.7.2
2158 // <USE>
2159 preg_match_all('/<use ([^>]*)xlink:href=["\']#([^>]*?)["\']([^>]*)\/>/si',$data, $links);
2160 for ($i=0; $i<count($links[0]); $i++) {
2161
2162 // Get the item to use from defs
2163 $insert = '';
2164 if (preg_match('/<([a-zA-Z]*) [^>]*id=["\']'.$links[2][$i].'["\'][^>]*\/>/si',$data, $m)) {
2165 $insert = $m[0];
2166 }
2167 if (!$insert && preg_match('/<([a-zA-Z]*) [^>]*id=["\']'.$links[2][$i].'["\']/si',$data, $m)) {
2168
2169 if (preg_match('/<'.$m[1].'[^>]*id=["\']'.$links[2][$i].'["\'][^>]*>.*?<\/'.$m[1].'>/si',$data, $m)) {
2170 $insert = $m[0];
2171 }
2172 }
2173
2174 if ($insert) {
2175
2176 $inners = $links[1][$i] . ' ' . $links[3][$i];
2177 // Change x,y coords to translate()
2178 if (preg_match('/y=["\']([^>]*?)["\']/', $inners, $m)) { $y = $m[1]; }
2179 else { $y = 0; }
2180 if (preg_match('/x=["\']([^>]*?)["\']/', $inners, $m)) { $x = $m[1]; }
2181 else { $x = 0; }
2182 if ($x || $y) {
2183 $inners = preg_replace('/(y|x)=["\']([^>]*?)["\']/', '', $inners);
2184 if (preg_match('/transform=["\']([^>]*?)["\']/', $inners, $m)) {
2185 if (preg_match('/translate\(\s*([0-9\.]+)\s*,\s*([0-9\.]+)\s*\)/', $m[1], $mm)) {
2186 $transform = $m[1]; // transform="...."
2187 $x += $mm[1];
2188 $y += $mm[2];
2189 $transform = preg_replace('/'.preg_quote($mm[0],'/').'/', '', $transform);
2190 $transform = 'transform="'.$transform.' translate('.$x.', '.$y.')"';
2191 $inners = preg_replace('/'.preg_quote($m[0],'/').'/is', $transform, $inners);
2192 }
2193 else {
2194 $inners = preg_replace('/'.preg_quote($m[0],'/').'/is', 'transform="'.$m[1].' translate('.$x.', '.$y.')"', $inners);
2195 }
2196 }
2197 else {
2198 $inners .= ' transform="translate('.$x.', '.$y.')"';
2199 }
2200 }
2201 }
2202 $replacement = '<g '.$inners.'>'.$insert.'</g>';
2203 $data = preg_replace('/'.preg_quote($links[0][$i],'/').'/is', $replacement, $data);
2204 }
2205 preg_match_all('/<use ([^>]*)xlink:href=["\']#([^>]*?)["\']([^>]*)>\s*<\/use>/si',$data, $links);
2206 for ($i=0; $i<count($links[0]); $i++) {
2207
2208 // Get the item to use from defs
2209 $insert = '';
2210 if (preg_match('/<([a-zA-Z]*) [^>]*id=["\']'.$links[2][$i].'["\'][^>]*\/>/si',$data, $m)) {
2211 $insert = $m[0];
2212 }
2213 if (!$insert && preg_match('/<([a-zA-Z]*) [^>]*id=["\']'.$links[2][$i].'["\']/si',$data, $m)) {
2214
2215 if (preg_match('/<'.$m[1].'[^>]*id=["\']'.$links[2][$i].'["\'][^>]*>.*?<\/'.$m[1].'>/si',$data, $m)) {
2216 $insert = $m[0];
2217 }
2218 }
2219
2220 if ($insert) {
2221
2222 $inners = $links[1][$i] . ' ' . $links[3][$i];
2223 // Change x,y coords to translate()
2224 if (preg_match('/y=["\']([^>]*?)["\']/', $inners, $m)) { $y = $m[1]; }
2225 else { $y = 0; }
2226 if (preg_match('/x=["\']([^>]*?)["\']/', $inners, $m)) { $x = $m[1]; }
2227 else { $x = 0; }
2228 if ($x || $y) {
2229 $inners = preg_replace('/(y|x)=["\']([^>]*?)["\']/', '', $inners);
2230 if (preg_match('/transform=["\']([^>]*?)["\']/', $inners, $m)) {
2231 if (preg_match('/translate\(\s*([0-9\.]+)\s*,\s*([0-9\.]+)\s*\)/', $m[1], $mm)) {
2232 $transform = $m[1]; // transform="...."
2233 $x += $mm[1];
2234 $y += $mm[2];
2235 $transform = preg_replace('/'.preg_quote($mm[0],'/').'/', '', $transform);
2236 $transform = 'transform="'.$transform.' translate('.$x.', '.$y.')"';
2237 $inners = preg_replace('/'.preg_quote($m[0],'/').'/is', $transform, $inners);
2238 }
2239 else {
2240 $inners = preg_replace('/'.preg_quote($m[0],'/').'/is', 'transform="'.$m[1].' translate('.$x.', '.$y.')"', $inners);
2241 }
2242 }
2243 else {
2244 $inners .= ' transform="translate('.$x.', '.$y.')"';
2245 }
2246 }
2247 $replacement = '<g '.$inners.'>'.$insert.'</g>';
2248 $data = preg_replace('/'.preg_quote($links[0][$i],'/').'/is', $replacement, $data);
2249
2250
2251 }
2252 }
2253 }
2254 // Removes <pattern>
2255 $data = preg_replace('/<pattern.*?<\/pattern>/is', '', $data);
2256 // Removes <marker>
2257 $data = preg_replace('/<marker.*?<\/marker>/is', '', $data);
2258
2259 $this->svg_info['data'] = $data;
2260
2261 $this->svg_string = '';
2262
2263 //
2264 // chargement unique des fonctions
2265 if(!function_exists("xml_svg2pdf_start")){
2266
2267 function xml_svg2pdf_start($parser, $name, $attribs){
2268 //
2269 // definition
2270 global $svg_class, $last_gradid;
2271
2272 // mPDF 5.7.2
2273 if (strtolower($name) == 'lineargradient'){
2274 $tmp_gradient = array(
2275 'type' => 'linear',
2276 'info' => array(
2277 'x1' => $attribs['x1'],
2278 'y1' => $attribs['y1'],
2279 'x2' => $attribs['x2'],
2280 'y2' => $attribs['y2']
2281 ),
2282 'transform' => $attribs['gradientTransform'],
2283 'units' => $attribs['gradientUnits'],
2284 'spread' => $attribs['spreadMethod'],
2285 'color' => array()
2286 );
2287 $last_gradid = $attribs['id'];
2288 $svg_class->svgAddGradient($attribs['id'],$tmp_gradient);
2289 return;
2290 }
2291 else if (strtolower($name) == 'radialgradient'){
2292 $tmp_gradient = array(
2293 'type' => 'radial',
2294 'info' => array(
2295 'x0' => $attribs['cx'],
2296 'y0' => $attribs['cy'],
2297 'x1' => $attribs['fx'],
2298 'y1' => $attribs['fy'],
2299 'r' => $attribs['r']
2300 ),
2301 'transform' => $attribs['gradientTransform'],
2302 'units' => $attribs['gradientUnits'],
2303 'spread' => $attribs['spreadMethod'],
2304 'color' => array()
2305 );
2306 $last_gradid = $attribs['id'];
2307 $svg_class->svgAddGradient($attribs['id'],$tmp_gradient);
2308 return;
2309 }
2310 else if (strtolower($name) == 'stop'){
2311 if (!$last_gradid) break;
2312 if (isset($attribs['style']) AND preg_match('/stop-color:\s*([^;]*)/i',$attribs['style'],$m)) {
2313 $color = trim($m[1]);
2314 } else if (isset($attribs['stop-color'])) {
2315 $color = $attribs['stop-color'];
2316 }
2317 $col = $svg_class->mpdf_ref->ConvertColor($color);
2318
2319 if ($col{0}==3 || $col{0}==5) { // RGB
2320 $color_final = sprintf('%.3F %.3F %.3F',ord($col{1})/255,ord($col{2})/255,ord($col{3})/255);
2321 $svg_class->svg_gradient[$last_gradid]['colorspace']='RGB';
2322 }
2323 else if ($col{0}==4 || $col{0}==6) { // CMYK
2324 $color_final = sprintf('%.3F %.3F %.3F %.3F',ord($col{1})/100,ord($col{2})/100,ord($col{3})/100,ord($col{4})/100);
2325 $svg_class->svg_gradient[$last_gradid]['colorspace']='CMYK';
2326 }
2327 else if ($col{0}==1) { // Grayscale
2328 $color_final = sprintf('%.3F',ord($col{1})/255);
2329 $svg_class->svg_gradient[$last_gradid]['colorspace']='Gray';
2330 }
2331
2332 $stop_opacity = 1;
2333 if (isset($attribs['style']) AND preg_match('/stop-opacity:\s*([0-9.]*)/i',$attribs['style'],$m)) {
2334 $stop_opacity = $m[1];
2335 } else if (isset($attribs['stop-opacity'])) {
2336 $stop_opacity = $attribs['stop-opacity'];
2337 }
2338 else if ($col{0}==5) { // RGBa
2339 $stop_opacity = ord($col{4}/100);
2340 }
2341 else if ($col{0}==6) { // CMYKa
2342 $stop_opacity = ord($col{5}/100);
2343 }
2344
2345 $tmp_color = array(
2346 'color' => $color_final,
2347 'offset' => $attribs['offset'],
2348 'opacity' => $stop_opacity
2349 );
2350 array_push($svg_class->svg_gradient[$last_gradid]['color'],$tmp_color);
2351 return;
2352 }
2353 if ($svg_class->inDefs) { return; }
2354
2355 $svg_class->xbase = 0;
2356 $svg_class->ybase = 0;
2357 switch (strtolower($name)){
2358
2359 // mPDF 5.0.039 - Don't output stuff inside <defs>
2360 case 'defs':
2361 $svg_class->inDefs = true;
2362 return;
2363
2364 case 'svg':
2365 $svg_class->svgOffset($attribs);
2366 break;
2367
2368 case 'path':
2369 $path = $attribs['d'];
2370 // mPDF 5.6.65
2371 preg_match_all('/([MZLHVCSQTAmzlhvcsqta])([eE ,\-.\d]+)*/', $path, $commands, PREG_SET_ORDER);
2372 $path_cmd = '';
2373 $svg_class->subPathInit = true;
2374 // mPDF 5.0.039
2375 $svg_class->pathBBox = array(999999,999999,-999999,-999999);
2376 foreach($commands as $c){
2377 if(count($c)==3 || $c[2]==''){
2378 list($tmp, $command, $arguments) = $c;
2379 }
2380 else{
2381 list($tmp, $command) = $c;
2382 $arguments = '';
2383 }
2384
2385 $path_cmd .= $svg_class->svgPath($command, $arguments);
2386 }
2387 // mPDF 5.0.039
2388 if ($svg_class->pathBBox[2]==-1999998) { $svg_class->pathBBox[2] = 100; }
2389 if ($svg_class->pathBBox[3]==-1999998) { $svg_class->pathBBox[3] = 100; }
2390 if ($svg_class->pathBBox[0]==999999) { $svg_class->pathBBox[0] = 0; }
2391 if ($svg_class->pathBBox[1]==999999) { $svg_class->pathBBox[1] = 0; }
2392 $critere_style = $attribs;
2393 unset($critere_style['d']);
2394 $path_style = $svg_class->svgDefineStyle($critere_style);
2395 break;
2396
2397 case 'rect':
2398 if (!isset($attribs['x'])) {$attribs['x'] = 0;}
2399 if (!isset($attribs['y'])) {$attribs['y'] = 0;}
2400 if (!isset($attribs['rx'])) {$attribs['rx'] = 0;}
2401 if (!isset($attribs['ry'])) {$attribs['ry'] = 0;}
2402 $arguments = array(
2403 'x' => $attribs['x'],
2404 'y' => $attribs['y'],
2405 'w' => $attribs['width'],
2406 'h' => $attribs['height'],
2407 'rx' => $attribs['rx'],
2408 'ry' => $attribs['ry']
2409 );
2410 $path_cmd = $svg_class->svgRect($arguments);
2411 $critere_style = $attribs;
2412 unset($critere_style['x'],$critere_style['y'],$critere_style['rx'],$critere_style['ry'],$critere_style['height'],$critere_style['width']);
2413 $path_style = $svg_class->svgDefineStyle($critere_style);
2414 break;
2415
2416 case 'circle':
2417 if (!isset($attribs['cx'])) {$attribs['cx'] = 0;}
2418 if (!isset($attribs['cy'])) {$attribs['cy'] = 0;}
2419 $arguments = array(
2420 'cx' => $attribs['cx'],
2421 'cy' => $attribs['cy'],
2422 'rx' => $attribs['r'],
2423 'ry' => $attribs['r']
2424 );
2425 $path_cmd = $svg_class->svgEllipse($arguments);
2426 $critere_style = $attribs;
2427 unset($critere_style['cx'],$critere_style['cy'],$critere_style['r']);
2428 $path_style = $svg_class->svgDefineStyle($critere_style);
2429 break;
2430
2431 case 'ellipse':
2432 if (!isset($attribs['cx'])) {$attribs['cx'] = 0;}
2433 if (!isset($attribs['cy'])) {$attribs['cy'] = 0;}
2434 $arguments = array(
2435 'cx' => $attribs['cx'],
2436 'cy' => $attribs['cy'],
2437 'rx' => $attribs['rx'],
2438 'ry' => $attribs['ry']
2439 );
2440 $path_cmd = $svg_class->svgEllipse($arguments);
2441 $critere_style = $attribs;
2442 unset($critere_style['cx'],$critere_style['cy'],$critere_style['rx'],$critere_style['ry']);
2443 $path_style = $svg_class->svgDefineStyle($critere_style);
2444 break;
2445
2446 case 'line':
2447 $arguments = array($attribs['x1'],$attribs['y1'],$attribs['x2'],$attribs['y2']);
2448 $path_cmd = $svg_class->svgPolyline($arguments,false); // mPDF 4.4.003
2449 $critere_style = $attribs;
2450 unset($critere_style['x1'],$critere_style['y1'],$critere_style['x2'],$critere_style['y2']);
2451 $path_style = $svg_class->svgDefineStyle($critere_style);
2452 break;
2453
2454 case 'polyline':
2455 $path = $attribs['points'];
2456 preg_match_all('/[0-9\-\.]*/',$path, $tmp, PREG_SET_ORDER);
2457 $arguments = array();
2458 for ($i=0;$i<count($tmp);$i++){
2459 if ($tmp[$i][0] !=''){
2460 array_push($arguments, $tmp[$i][0]);
2461 }
2462 }
2463 $path_cmd = $svg_class->svgPolyline($arguments);
2464 $critere_style = $attribs;
2465 unset($critere_style['points']);
2466 $path_style = $svg_class->svgDefineStyle($critere_style);
2467 break;
2468
2469 case 'polygon':
2470 $path = $attribs['points'];
2471 preg_match_all('/([\-]*[0-9\.]+)/',$path, $tmp);
2472 $arguments = array();
2473 for ($i=0;$i<count($tmp[0]);$i++){
2474 if ($tmp[0][$i] !=''){
2475 array_push($arguments, $tmp[0][$i]);
2476 }
2477 }
2478 $path_cmd = $svg_class->svgPolygon($arguments);
2479 // definition du style de la forme:
2480 $critere_style = $attribs;
2481 unset($critere_style['points']);
2482 $path_style = $svg_class->svgDefineStyle($critere_style);
2483 break;
2484
2485 case 'a':
2486 if (isset($attribs['xlink:href'])) {
2487 unset($attribs['xlink:href']); // this should be a hyperlink
2488 // not handled like a xlink:href in other elements
2489 } // then continue like a <g>
2490 case 'g':
2491 $array_style = $svg_class->svgDefineStyle($attribs);
2492 if ($array_style['transformations']) {
2493 $svg_class->svgWriteString(' q '.$array_style['transformations']);
2494 }
2495 array_push($svg_class->svg_style,$array_style);
2496
2497 $svg_class->svgDefineTxtStyle($attribs); // mPDF 4.4.003
2498
2499 break;
2500
2501 case 'text':
2502 $array_style = $svg_class->svgDefineStyle($attribs);
2503 if ($array_style['transformations']) {
2504 $svg_class->svgWriteString(' q '.$array_style['transformations']);
2505 }
2506 array_push($svg_class->svg_style,$array_style);
2507
2508 $svg_class->txt_data = array();
2509 $svg_class->txt_data[0] = $attribs['x'];
2510 $svg_class->txt_data[1] = $attribs['y'];
2511 $critere_style = $attribs;
2512 unset($critere_style['x'], $critere_style['y']);
2513 $svg_class->svgDefineTxtStyle($critere_style);
2514 break;
2515 }
2516
2517 //
2518 //insertion des path et du style dans le flux de donné general.
2519 if (isset($path_cmd) && $path_cmd) { // mPDF 4.4.003
2520 // mPDF 5.0
2521 list($prestyle,$poststyle) = $svg_class->svgStyle($path_style, $attribs, strtolower($name));
2522 if ($path_style['transformations']) { // transformation on an element
2523 $svg_class->svgWriteString(" q ".$path_style['transformations']. " $prestyle $path_cmd $poststyle" . " Q\n");
2524 }
2525 else {
2526 $svg_class->svgWriteString("$prestyle $path_cmd $poststyle\n");
2527 }
2528 }
2529 }
2530
2531 function characterData($parser, $data)
2532 {
2533 global $svg_class;
2534 if ($svg_class->inDefs) { return; } // mPDF 5.7.2
2535 if(isset($svg_class->txt_data[2])) {
2536 $svg_class->txt_data[2] .= $data;
2537 }
2538 else {
2539 $svg_class->txt_data[2] = $data;
2540 }
2541 }
2542
2543
2544 function xml_svg2pdf_end($parser, $name){
2545 global $svg_class;
2546 // Don't output stuff inside <defs>
2547 // mPDF 5.7.2
2548 if ($name == 'defs') {
2549 $svg_class->inDefs = false;
2550 return;
2551 }
2552 if ($svg_class->inDefs) { return; }
2553 switch($name){
2554
2555 case "g":
2556 case "a":
2557 $tmp = count($svg_class->svg_style)-1;
2558 $current_style = $svg_class->svg_style[$tmp];
2559 if ($current_style['transformations']) {
2560 $svg_class->svgWriteString(" Q\n");
2561 }
2562 array_pop($svg_class->svg_style);
2563
2564 array_pop($svg_class->txt_style); // mPDF 4.4.003
2565
2566 break;
2567 case 'radialgradient':
2568 case 'lineargradient':
2569 $last_gradid = '';
2570 break;
2571 case "text":
2572 $path_cmd = $svg_class->svgText();
2573 // echo 'path >> '.$path_cmd."<br><br>";
2574 // echo "style >> ".$get_style[1]."<br><br>";
2575 $svg_class->svgWriteString($path_cmd);
2576 // mPDF 4.4.003
2577 $tmp = count($svg_class->svg_style)-1;
2578 $current_style = $svg_class->svg_style[$tmp];
2579 if ($current_style['transformations']) {
2580 $svg_class->svgWriteString(" Q\n");
2581 }
2582 array_pop($svg_class->svg_style);
2583
2584 break;
2585 }
2586 // mPDF 5.0.039 - Don't output stuff inside <defs>
2587 if ($name == 'defs') {
2588 $svg_class->inDefs = false;
2589 }
2590
2591 }
2592
2593 }
2594
2595 $svg2pdf_xml='';
2596 global $svg_class;
2597 $svg_class = $this;
2598 // mPDF 5.0.039 - Don't output stuff inside <defs>
2599 $svg_class->inDefs = false;
2600 $svg2pdf_xml_parser = xml_parser_create("utf-8");
2601 xml_parser_set_option($svg2pdf_xml_parser, XML_OPTION_CASE_FOLDING, false);
2602 xml_set_element_handler($svg2pdf_xml_parser, "xml_svg2pdf_start", "xml_svg2pdf_end");
2603 xml_set_character_data_handler($svg2pdf_xml_parser, "characterData");
2604 xml_parse($svg2pdf_xml_parser, $data);
2605 // mPDF 4.4.003
2606 if ($this->svg_error) { return false; }
2607 else {
2608 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);
2609 }
2610
2611 }
2612
2613}
2614
2615// END OF CLASS
2616
2617
2618// mPDF 5.0.040
2619function calc_bezier_bbox($start, $c) {
2620 $P0 = array($start[0],$start[1]);
2621 $P1 = array($c[0],$c[1]);
2622 $P2 = array($c[2],$c[3]);
2623 $P3 = array($c[4],$c[5]);
2624 $bounds = array();
2625 $bounds[0][] = $P0[0];
2626 $bounds[1][] = $P0[1];
2627 $bounds[0][] = $P3[0];
2628 $bounds[1][] = $P3[1];
2629 for ($i=0;$i<=1;$i++) {
2630 $b = 6 * $P0[$i] - 12 * $P1[$i] + 6 * $P2[$i];
2631 $a = -3 * $P0[$i] + 9 * $P1[$i] - 9 * $P2[$i] + 3 * $P3[$i];
2632 $c = 3 * $P1[$i] - 3 * $P0[$i];
2633 if ($a == 0) {
2634 if ($b == 0) { continue; }
2635 $t = -$c / $b;
2636 if ($t>0 && $t<1) {
2637 $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]);
2638 }
2639 continue;
2640 }
2641 $b2ac = pow($b, 2) - 4 * $c * $a;
2642 if ($b2ac < 0) { continue; }
2643 $t1 = (-$b + sqrt($b2ac))/(2 * $a);
2644 if ($t1>0 && $t1<1) {
2645 $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]);
2646 }
2647 $t2 = (-$b - sqrt($b2ac))/(2 * $a);
2648 if ($t2>0 && $t2<1) {
2649 $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]);
2650 }
2651 }
2652 $x = min($bounds[0]);
2653 $x2 = max($bounds[0]);
2654 $y = min($bounds[1]);
2655 $y2 = max($bounds[1]);
2656 return array($x, $y, $x2, $y2);
2657}
2658
2659// mPDF 5.0.040
2660function _testIntersectCircle($cx, $cy, $cr) {
2661 // Tests whether a circle fully encloses a rectangle 0,0,1,1
2662 // to see if any further radial gradients need adding (SVG)
2663 // If centre of circle is inside 0,0,1,1 square
2664 if ($cx >= 0 && $cx <= 1 && $cy >= 0 && $cy <= 1) {
2665 $maxd = 1.5;
2666 }
2667 // distance to four corners
2668 else {
2669 $d1 = sqrt(pow(($cy-0),2) + pow(($cx-0),2));
2670 $d2 = sqrt(pow(($cy-1),2) + pow(($cx-0),2));
2671 $d3 = sqrt(pow(($cy-0),2) + pow(($cx-1),2));
2672 $d4 = sqrt(pow(($cy-1),2) + pow(($cx-1),2));
2673 $maxd = max($d1,$d2,$d3,$d4);
2674 }
2675 if ($cr < $maxd) { return true; }
2676 else { return false; }
2677}
2678
2679// mPDF 5.0.040
2680function _testIntersect($x1, $y1, $x2, $y2, $x3, $y3, $x4, $y4) {
2681 // Tests whether line (x1, y1) and (x2, y2) [a gradient axis (perpendicular)]
2682 // intersects with a specific line segment (x3, y3) and (x4, y4)
2683 $a1 = $y2-$y1;
2684 $b1 = $x1-$x2;
2685 $c1 = $a1*$x1+$b1*$y1;
2686 $a2 = $y4-$y3;
2687 $b2 = $x3-$x4;
2688 $c2 = $a2*$x3+$b2*$y3;
2689 $det = $a1*$b2 - $a2*$b1;
2690 if($det == 0){ //Lines are parallel
2691 return false;
2692 }
2693 else{
2694 $x = ($b2*$c1 - $b1*$c2)/$det;
2695 $y = ($a1*$c2 - $a2*$c1)/$det;
2696 if ($x >= $x3 && $x <= $x4 && $y >= $y3 && $y <= $y4) { return true; }
2697 }
2698 return false;
2699}
2700
2701
2702
2703?> \ No newline at end of file
diff --git a/inc/3rdparty/libraries/mpdf/classes/tocontents.php b/inc/3rdparty/libraries/mpdf/classes/tocontents.php
deleted file mode 100644
index b1b61446..00000000
--- a/inc/3rdparty/libraries/mpdf/classes/tocontents.php
+++ /dev/null
@@ -1,467 +0,0 @@
1<?php
2
3class tocontents {
4
5var $mpdf = null;
6var $_toc;
7var $TOCmark;
8var $TOCoutdent; // mPDF 5.6.31
9var $TOCpreHTML;
10var $TOCpostHTML;
11var $TOCbookmarkText;
12var $TOCusePaging;
13var $TOCuseLinking;
14var $TOCorientation;
15var $TOC_margin_left;
16var $TOC_margin_right;
17var $TOC_margin_top;
18var $TOC_margin_bottom;
19var $TOC_margin_header;
20var $TOC_margin_footer;
21var $TOC_odd_header_name;
22var $TOC_even_header_name;
23var $TOC_odd_footer_name;
24var $TOC_even_footer_name;
25var $TOC_odd_header_value;
26var $TOC_even_header_value;
27var $TOC_odd_footer_value;
28var $TOC_even_footer_value;
29var $TOC_page_selector;
30var $m_TOC;
31
32function tocontents(&$mpdf) {
33 $this->mpdf = $mpdf;
34 $this->_toc=array();
35 $this->TOCmark = 0;
36 $this->m_TOC=array();
37}
38
39function 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
106function 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
138function 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 // mPDF 5.6.19
228 $html ='<div class="mpdf_toc" id="mpdf_toc_'.$toc_id.'">';
229 foreach($this->_toc as $t) {
230 if ($t['toc_id']==='_mpdf_all' || $t['toc_id']===$toc_id ) {
231 $html .= '<div class="mpdf_toc_level_'.$t['l'].'">';
232 if ($TOCuseLinking) { $html .= '<a class="mpdf_toc_a" href="#__mpdfinternallink_'.$t['link'].'">'; }
233 $html .= '<span class="mpdf_toc_t_level_'.$t['l'].'">'.$t['t'].'</span>';
234 if ($TOCuseLinking) { $html .= '</a>'; }
235 if (!$tocoutdent) { $tocoutdent = '0'; }
236 if ($TOCusePaging) { $html .= ' <dottab outdent="'.$tocoutdent.'" /> ';
237 if ($TOCuseLinking) { $html .= '<a class="mpdf_toc_a" href="#__mpdfinternallink_'.$t['link'].'">'; }
238 $html .= '<span class="mpdf_toc_p_level_'.$t['l'].'">'.$this->mpdf->docPageNum($t['p']).'</span>';
239 if ($TOCuseLinking) { $html .= '</a>'; }
240 }
241 $html .= '</div>';
242 }
243 }
244 $html .= '</div>';
245 $this->mpdf->WriteHTML($html);
246
247 if ($toc_postHTML) { $this->mpdf->WriteHTML($toc_postHTML); }
248 $this->mpdf->writingToC = false; // mPDF 5.6.38
249 $this->mpdf->AddPage($toc_orientation,'E');
250
251 $n_toc = $this->mpdf->page - $tocstart + 1;
252
253 if ($toci==0 && $this->TOCmark) {
254 $TOC_start = $tocstart ;
255 $TOC_end = $this->mpdf->page;
256 $TOC_npages = $n_toc;
257 }
258 else {
259 $this->m_TOC[$toc_id]['start'] = $tocstart ;
260 $this->m_TOC[$toc_id]['end'] = $this->mpdf->page;
261 $this->m_TOC[$toc_id]['npages'] = $n_toc;
262 }
263 }
264
265 $s = '';
266
267 $s .= $this->mpdf->PrintBodyBackgrounds();
268
269 $s .= $this->mpdf->PrintPageBackgrounds();
270 $this->mpdf->pages[$this->mpdf->page] = preg_replace('/(___BACKGROUND___PATTERNS'.$this->mpdf->uniqstr.')/', "\n".$s."\n".'\\1', $this->mpdf->pages[$this->mpdf->page]);
271 $this->mpdf->pageBackgrounds = array();
272
273 //Page footer
274 $this->mpdf->InFooter=true;
275 $this->mpdf->Footer();
276 $this->mpdf->InFooter=false;
277
278 // 2nd time through to move pages etc.
279 $added_toc_pages = 0;
280 if (count($this->m_TOC)) { reset($this->m_TOC); }
281
282 for ($toci = 0; $toci<$notocs; $toci++) {
283 if ($toci==0 && $this->TOCmark) {
284 $toc_id = 0;
285 $toc_page = $this->TOCmark + $added_toc_pages;
286 $toc_orientation = $this->TOCorientation;
287 $TOCuseLinking = $this->TOCuseLinking;
288 $TOCusePaging = $this->TOCusePaging;
289 $toc_bookmarkText = $this->TOCbookmarkText; // *BOOKMARKS*
290
291 $tocstart = $TOC_start ;
292 $tocend = $n = $TOC_end;
293 $n_toc = $TOC_npages;
294 }
295 else {
296 $arr = current($this->m_TOC);
297
298 $toc_id = key($this->m_TOC);
299 $toc_page = $this->m_TOC[$toc_id]['TOCmark'] + $added_toc_pages;
300 $toc_orientation = $this->m_TOC[$toc_id]['TOCorientation'];
301 $TOCuseLinking = $this->m_TOC[$toc_id]['TOCuseLinking'];
302 $TOCusePaging = $this->m_TOC[$toc_id]['TOCusePaging'];
303 $toc_bookmarkText = $this->m_TOC[$toc_id]['TOCbookmarkText']; // *BOOKMARKS*
304
305 $tocstart = $this->m_TOC[$toc_id]['start'] ;
306 $tocend = $n = $this->m_TOC[$toc_id]['end'] ;
307 $n_toc = $this->m_TOC[$toc_id]['npages'] ;
308
309 next($this->m_TOC);
310 }
311
312 // Now pages moved
313 $added_toc_pages += $n_toc;
314
315 $this->mpdf->MovePages($toc_page, $tocstart, $tocend) ;
316 $this->mpdf->pgsIns[$toc_page] = $tocend - $tocstart + 1;
317
318/*-- BOOKMARKS --*/
319 // Insert new Bookmark for Bookmark
320 if ($toc_bookmarkText) {
321 $insert = -1;
322 foreach($this->mpdf->BMoutlines as $i=>$o) {
323 if($o['p']<$toc_page) { // i.e. before point of insertion
324 $insert = $i;
325 }
326 }
327 $txt = $this->mpdf->purify_utf8_text($toc_bookmarkText);
328 if ($this->mpdf->text_input_as_HTML) {
329 $txt = $this->mpdf->all_entities_to_utf8($txt);
330 }
331 $newBookmark[0] = array('t'=>$txt,'l'=>0,'y'=>0,'p'=>$toc_page );
332 array_splice($this->mpdf->BMoutlines,($insert+1),0,$newBookmark);
333 }
334/*-- END BOOKMARKS --*/
335
336 }
337
338 // Delete empty page that was inserted earlier
339 if ($extrapage) {
340 unset($this->mpdf->pages[count($this->mpdf->pages)]);
341 $this->mpdf->page--; // Reset page pointer
342 }
343
344
345}
346
347
348function openTagTOC($attr) {
349 if (isset($attr['OUTDENT']) && $attr['OUTDENT']) { $tocoutdent = $attr['OUTDENT']; } else { $tocoutdent = ''; } // mPDF 5.6.19
350 if (isset($attr['RESETPAGENUM']) && $attr['RESETPAGENUM']) { $resetpagenum = $attr['RESETPAGENUM']; } else { $resetpagenum = ''; }
351 if (isset($attr['PAGENUMSTYLE']) && $attr['PAGENUMSTYLE']) { $pagenumstyle = $attr['PAGENUMSTYLE']; } else { $pagenumstyle= ''; }
352 if (isset($attr['SUPPRESS']) && $attr['SUPPRESS']) { $suppress = $attr['SUPPRESS']; } else { $suppress = ''; }
353 if (isset($attr['TOC-ORIENTATION']) && $attr['TOC-ORIENTATION']) { $toc_orientation = $attr['TOC-ORIENTATION']; } else { $toc_orientation = ''; }
354 if (isset($attr['PAGING']) && (strtoupper($attr['PAGING'])=='OFF' || $attr['PAGING']==='0')) { $paging = false; }
355 else { $paging = true; }
356 if (isset($attr['LINKS']) && (strtoupper($attr['LINKS'])=='ON' || $attr['LINKS']==1)) { $links = true; }
357 else { $links = false; }
358 if (isset($attr['NAME']) && $attr['NAME']) { $toc_id = strtolower($attr['NAME']); } else { $toc_id = 0; }
359 $this->TOC('',0,0,$resetpagenum, $pagenumstyle, $suppress, $toc_orientation, $paging, $links, $toc_id, $tocoutdent); // mPDF 5.6.19 5.6.31
360}
361
362
363function openTagTOCPAGEBREAK($attr) {
364 if (isset($attr['NAME']) && $attr['NAME']) { $toc_id = strtolower($attr['NAME']); } else { $toc_id = 0; }
365 if ($toc_id) {
366 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
367 if (isset($attr['TOC-ORIENTATION']) && $attr['TOC-ORIENTATION']) { $this->m_TOC[$toc_id]['TOCorientation'] = $attr['TOC-ORIENTATION']; } else { $this->m_TOC[$toc_id]['TOCorientation'] = ''; }
368 if (isset($attr['PAGING']) && (strtoupper($attr['PAGING'])=='OFF' || $attr['PAGING']==='0')) { $this->m_TOC[$toc_id]['TOCusePaging'] = false; }
369 else { $this->m_TOC[$toc_id]['TOCusePaging'] = true; }
370 if (isset($attr['LINKS']) && (strtoupper($attr['LINKS'])=='ON' || $attr['LINKS']==1)) { $this->m_TOC[$toc_id]['TOCuseLinking'] = true; }
371 else { $this->m_TOC[$toc_id]['TOCuseLinking'] = false; }
372
373 $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'] = '';
374 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); }
375 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); }
376 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); }
377 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); }
378 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); }
379 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); }
380 $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'] = '';
381 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']; }
382 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']; }
383 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']; }
384 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']; }
385 $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;
386 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; }
387 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; }
388 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; }
389 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; }
390 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; }
391 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; }
392 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; }
393 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; }
394 if (isset($attr['TOC-PAGE-SELECTOR']) && $attr['TOC-PAGE-SELECTOR']) { $this->m_TOC[$toc_id]['TOC_page_selector'] = $attr['TOC-PAGE-SELECTOR']; }
395 else { $this->m_TOC[$toc_id]['TOC_page_selector'] = ''; }
396 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'] = ''; }
397
398
399 if (isset($attr['TOC-PREHTML']) && $attr['TOC-PREHTML']) { $this->m_TOC[$toc_id]['TOCpreHTML'] = htmlspecialchars_decode($attr['TOC-PREHTML'],ENT_QUOTES); }
400 if (isset($attr['TOC-POSTHTML']) && $attr['TOC-POSTHTML']) { $this->m_TOC[$toc_id]['TOCpostHTML'] = htmlspecialchars_decode($attr['TOC-POSTHTML'],ENT_QUOTES); }
401
402 if (isset($attr['TOC-BOOKMARKTEXT']) && $attr['TOC-BOOKMARKTEXT']) { $this->m_TOC[$toc_id]['TOCbookmarkText'] = htmlspecialchars_decode($attr['TOC-BOOKMARKTEXT'],ENT_QUOTES); } // *BOOKMARKS*
403 }
404 else {
405 if (isset($attr['OUTDENT']) && $attr['OUTDENT']) { $this->TOCoutdent = $attr['OUTDENT']; } else { $this->TOCoutdent = ''; } // mPDF 5.6.19
406 if (isset($attr['TOC-ORIENTATION']) && $attr['TOC-ORIENTATION']) { $this->TOCorientation = $attr['TOC-ORIENTATION']; } else { $this->TOCorientation = ''; }
407 if (isset($attr['PAGING']) && (strtoupper($attr['PAGING'])=='OFF' || $attr['PAGING']==='0')) { $this->TOCusePaging = false; }
408 else { $this->TOCusePaging = true; }
409 if (isset($attr['LINKS']) && (strtoupper($attr['LINKS'])=='ON' || $attr['LINKS']==1)) { $this->TOCuseLinking = true; }
410 else { $this->TOCuseLinking = false; }
411
412 $this->TOC_margin_left = $this->TOC_margin_right = $this->TOC_margin_top = $this->TOC_margin_bottom = $this->TOC_margin_header = $this->TOC_margin_footer = '';
413 if (isset($attr['TOC-MARGIN-RIGHT'])) { $this->TOC_margin_right = $this->mpdf->ConvertSize($attr['TOC-MARGIN-RIGHT'],$this->mpdf->w,$this->mpdf->FontSize,false); }
414 if (isset($attr['TOC-MARGIN-LEFT'])) { $this->TOC_margin_left = $this->mpdf->ConvertSize($attr['TOC-MARGIN-LEFT'],$this->mpdf->w,$this->mpdf->FontSize,false); }
415 if (isset($attr['TOC-MARGIN-TOP'])) { $this->TOC_margin_top = $this->mpdf->ConvertSize($attr['TOC-MARGIN-TOP'],$this->mpdf->w,$this->mpdf->FontSize,false); }
416 if (isset($attr['TOC-MARGIN-BOTTOM'])) { $this->TOC_margin_bottom = $this->mpdf->ConvertSize($attr['TOC-MARGIN-BOTTOM'],$this->mpdf->w,$this->mpdf->FontSize,false); }
417 if (isset($attr['TOC-MARGIN-HEADER'])) { $this->TOC_margin_header = $this->mpdf->ConvertSize($attr['TOC-MARGIN-HEADER'],$this->mpdf->w,$this->mpdf->FontSize,false); }
418 if (isset($attr['TOC-MARGIN-FOOTER'])) { $this->TOC_margin_footer = $this->mpdf->ConvertSize($attr['TOC-MARGIN-FOOTER'],$this->mpdf->w,$this->mpdf->FontSize,false); }
419 $this->TOC_odd_header_name = $this->TOC_even_header_name = $this->TOC_odd_footer_name = $this->TOC_even_footer_name = '';
420 if (isset($attr['TOC-ODD-HEADER-NAME']) && $attr['TOC-ODD-HEADER-NAME']) { $this->TOC_odd_header_name = $attr['TOC-ODD-HEADER-NAME']; }
421 if (isset($attr['TOC-EVEN-HEADER-NAME']) && $attr['TOC-EVEN-HEADER-NAME']) { $this->TOC_even_header_name = $attr['TOC-EVEN-HEADER-NAME']; }
422 if (isset($attr['TOC-ODD-FOOTER-NAME']) && $attr['TOC-ODD-FOOTER-NAME']) { $this->TOC_odd_footer_name = $attr['TOC-ODD-FOOTER-NAME']; }
423 if (isset($attr['TOC-EVEN-FOOTER-NAME']) && $attr['TOC-EVEN-FOOTER-NAME']) { $this->TOC_even_footer_name = $attr['TOC-EVEN-FOOTER-NAME']; }
424 $this->TOC_odd_header_value = $this->TOC_even_header_value = $this->TOC_odd_footer_value = $this->TOC_even_footer_value = 0;
425 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; }
426 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; }
427 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; }
428 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; }
429
430 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; }
431 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; }
432 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; }
433 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; }
434 if (isset($attr['TOC-PAGE-SELECTOR']) && $attr['TOC-PAGE-SELECTOR']) { $this->TOC_page_selector = $attr['TOC-PAGE-SELECTOR']; }
435 else { $this->TOC_page_selector = ''; }
436 if (isset($attr['TOC-SHEET-SIZE']) && $attr['TOC-SHEET-SIZE']) { $this->TOCsheetsize = $attr['TOC-SHEET-SIZE']; } else { $this->TOCsheetsize = ''; }
437
438 if (isset($attr['TOC-PREHTML']) && $attr['TOC-PREHTML']) { $this->TOCpreHTML = htmlspecialchars_decode($attr['TOC-PREHTML'],ENT_QUOTES); }
439 if (isset($attr['TOC-POSTHTML']) && $attr['TOC-POSTHTML']) { $this->TOCpostHTML = htmlspecialchars_decode($attr['TOC-POSTHTML'],ENT_QUOTES); }
440 if (isset($attr['TOC-BOOKMARKTEXT']) && $attr['TOC-BOOKMARKTEXT']) { $this->TOCbookmarkText = htmlspecialchars_decode($attr['TOC-BOOKMARKTEXT'],ENT_QUOTES); }
441 }
442
443 if ($this->mpdf->y == $this->mpdf->tMargin && (!$this->mpdf->mirrorMargins ||($this->mpdf->mirrorMargins && $this->mpdf->page % 2==1))) {
444 if ($toc_id) { $this->m_TOC[$toc_id]['TOCmark'] = $this->mpdf->page; }
445 else { $this->TOCmark = $this->mpdf->page; }
446 // Don't add a page
447 if ($this->mpdf->page==1 && count($this->mpdf->PageNumSubstitutions)==0) {
448 $resetpagenum = '';
449 $pagenumstyle = '';
450 $suppress = '';
451 if (isset($attr['RESETPAGENUM'])) { $resetpagenum = $attr['RESETPAGENUM']; }
452 if (isset($attr['PAGENUMSTYLE'])) { $pagenumstyle = $attr['PAGENUMSTYLE']; }
453 if (isset($attr['SUPPRESS'])) { $suppress = $attr['SUPPRESS']; }
454 if (!$suppress) { $suppress = 'off'; }
455 if (!$resetpagenum) { $resetpagenum= 1; }
456 $this->mpdf->PageNumSubstitutions[] = array('from'=>1, 'reset'=> $resetpagenum, 'type'=>$pagenumstyle, 'suppress'=> $suppress);
457 }
458 return array(true, $toc_id);
459 }
460 // No break - continues as PAGEBREAK...
461 return array(false, $toc_id);
462}
463
464
465}
466
467?> \ No newline at end of file
diff --git a/inc/3rdparty/libraries/mpdf/classes/ttfontsuni.php b/inc/3rdparty/libraries/mpdf/classes/ttfontsuni.php
deleted file mode 100644
index 1c93b600..00000000
--- a/inc/3rdparty/libraries/mpdf/classes/ttfontsuni.php
+++ /dev/null
@@ -1,2065 +0,0 @@
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(!)
24if (!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
28if (!defined('_RECALC_PROFILE')) define("_RECALC_PROFILE", false);
29
30// TrueType Font Glyph operators
31define("GF_WORDS",(1 << 0));
32define("GF_SCALE",(1 << 3));
33define("GF_MORE",(1 << 5));
34define("GF_XYSCALE",(1 << 6));
35define("GF_TWOBYTWO",(1 << 7));
36
37
38
39class TTFontFile {
40
41var $unAGlyphs; // mPDF 5.4.05
42var $panose;
43var $maxUni;
44var $sFamilyClass;
45var $sFamilySubClass;
46var $sipset;
47var $smpset;
48var $_pos;
49var $numTables;
50var $searchRange;
51var $entrySelector;
52var $rangeShift;
53var $tables;
54var $otables;
55var $filename;
56var $fh;
57var $glyphPos;
58var $charToGlyph;
59var $ascent;
60var $descent;
61var $name;
62var $familyName;
63var $styleName;
64var $fullName;
65var $uniqueFontID;
66var $unitsPerEm;
67var $bbox;
68var $capHeight;
69var $stemV;
70var $italicAngle;
71var $flags;
72var $underlinePosition;
73var $underlineThickness;
74var $charWidths;
75var $defaultWidth;
76var $maxStrLenRead;
77var $numTTCFonts;
78var $TTCFonts;
79var $maxUniChar;
80var $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/*
2035Tables which require glyphIndex
2036hdmx
2037kern
2038LTSH
2039
2040Tables which do NOT require glyphIndex
2041VDMX
2042
2043GDEF
2044GPOS
2045GSUB
2046JSTF
2047
2048DSIG
2049PCLT - 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
deleted file mode 100644
index 3f2cccef..00000000
--- a/inc/3rdparty/libraries/mpdf/classes/ttfontsuni_analysis.php
+++ /dev/null
@@ -1,463 +0,0 @@
1<?php
2
3require_once(_MPDF_PATH.'classes/ttfontsuni.php');
4
5class 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
deleted file mode 100644
index 2efef00b..00000000
--- a/inc/3rdparty/libraries/mpdf/classes/wmf.php
+++ /dev/null
@@ -1,236 +0,0 @@
1<?php
2
3class wmf {
4
5var $mpdf = null;
6var $gdiObjectArray;
7
8function wmf(&$mpdf) {
9 $this->mpdf = $mpdf;
10}
11
12
13function _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
201function _MoveTo($x, $y) {
202 return "$x $y m\n";
203}
204
205// a line must have been started using _MoveTo() first
206function _LineTo($x, $y) {
207 return "$x $y l\n";
208}
209
210function _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
225function _GetGDIObject($idx) {
226 return $this->gdiObjectArray[$idx];
227}
228
229function _DeleteGDIObject($idx) {
230 unset($this->gdiObjectArray[$idx]);
231}
232
233
234}
235
236?> \ No newline at end of file