PluginProbe
PDF & Print by BestWebSoft – WordPress Posts and Pages PDF Generator Plugin / 2.4.2
PDF & Print by BestWebSoft – WordPress Posts and Pages PDF Generator Plugin v2.4.2
trunk 1.5 1.6 1.7 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.1 All 71 releases
pdf-print / mpdf / classes / svg.php

svg.php in PDF & Print by BestWebSoft – WordPress Posts and Pages PDF Generator Plugin 2.4.2, at mpdf/classes/svg.php

3,796 lines 131.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 // svg class modified for mPDF version 6.0 by Ian Back: based on -
4 // svg2pdf fpdf class
5 // sylvain briand (syb@godisaduck.com), modified by rick trevino (rtrevino1@yahoo.com)
6 // http://www.godisaduck.com/svg2pdf_with_fpdf
7 // http://rhodopsin.blogspot.com
8 //
9 // cette class etendue est open source, toute modification devra cependant etre repertoriée~
10 // If you wish to use Automatic Font selection within SVG's. change this definition to true.
11 // This selects different fonts for different scripts used in text.
12 // This can be enabled/disabled independently of the use of Automatic Font selection within mPDF generally.
13 // Choice of font is determined by the config_script2lang.php and config_lang2fonts.php files, the same as for mPDF generally.
14 if (!defined("_SVG_AUTOFONT")) {
15 define("_SVG_AUTOFONT", false);
16 }
17
18 // Enable a limited use of classes within SVG <text> elements by setting this to true.
19 // This allows recognition of a "class" attribute on a <text> element.
20 // The CSS style for that class should be outside the SVG, and cannot use any other selectors (i.e. only .class {} can be defined)
21 // <style> definitions within the SVG code will be recognised if the SVG is included as an inline item within the HTML code passed to mPDF.
22 // The style property should be pertinent to SVG e.g. use fill:red rather than color:red
23 // Only the properties currently supported for SVG text can be specified:
24 // fill, fill-opacity, stroke, stroke-opacity, stroke-linecap, stroke-linejoin, stroke-width, stroke-dasharray, stroke-dashoffset
25 // font-family, font-size, font-weight, font-variant, font-style, opacity, text-anchor
26 if (!defined("_SVG_CLASSES")) {
27 define("_SVG_CLASSES", false);
28 }
29
30 // NB UNITS - Works in pixels as main units - converting to PDF units when outputing to PDF string
31 // and on returning size
32
33 class SVG
34 {
35
36 var $svg_font; // array - holds content of SVG fonts defined in image // mPDF 6
37
38 var $svg_gradient; // array - contient les infos sur les gradient fill du svg classé par id du svg
39
40 var $svg_shadinglist; // array - contient les ids des objet shading
41
42 var $svg_info; // array contenant les infos du svg voulue par l'utilisateur
43
44 var $svg_attribs; // array - holds all attributes of root <svg> tag
45
46 var $svg_style; // array contenant les style de groupes du svg
47
48 var $svg_string; // String contenant le tracage du svg en lui même.
49
50 var $txt_data; // array - holds string info to write txt to image
51
52 var $txt_style; // array - current text style
53
54 var $mpdf_ref;
55
56 var $xbase;
57
58 var $ybase;
59
60 var $svg_error;
61
62 var $subPathInit;
63
64 var $spxstart;
65
66 var $spystart;
67
68 var $kp; // convert pixels to PDF units
69
70 var $pathBBox;
71
72 var $script2lang;
73
74 var $viet;
75
76 var $pashto;
77
78 var $urdu;
79
80 var $persian;
81
82 var $sindhi;
83
84 var $textlength; // mPDF 5.7.4
85
86 var $texttotallength; // mPDF 5.7.4
87
88 var $textoutput; // mPDF 5.7.4
89
90 var $textanchor; // mPDF 5.7.4
91
92 var $textXorigin; // mPDF 5.7.4
93
94 var $textYorigin; // mPDF 5.7.4
95
96 var $textjuststarted; // mPDF 5.7.4
97
98 var $intext; // mPDF 5.7.4
99
100 public function __construct(mPDF $mpdf)
101 {
102 $this->svg_font = array(); // mPDF 6
103 $this->svg_gradient = array();
104 $this->svg_shadinglist = array();
105 $this->txt_data = array();
106 $this->svg_string = '';
107 $this->svg_info = array();
108 $this->svg_attribs = array();
109 $this->xbase = 0;
110 $this->ybase = 0;
111 $this->svg_error = false;
112 $this->subPathInit = false;
113 $this->dashesUsed = false;
114 $this->mpdf_ref = & $mpdf;
115
116 $this->textlength = 0; // mPDF 5.7.4
117 $this->texttotallength = 0; // mPDF 5.7.4
118 $this->textoutput = ''; // mPDF 5.7.4
119 $this->textanchor = 'start'; // mPDF 5.7.4
120 $this->textXorigin = 0; // mPDF 5.7.4
121 $this->textYorigin = 0; // mPDF 5.7.4
122 $this->textjuststarted = false; // mPDF 5.7.4
123 $this->intext = false; // mPDF 5.7.4
124
125 $this->kp = 72 / $mpdf->img_dpi; // constant To convert pixels to pts/PDF units
126 $this->kf = 1; // constant To convert font size if re-mapped
127 $this->pathBBox = array();
128
129 $this->svg_style = array(
130 array(
131 'fill' => 'black',
132 'fill-opacity' => 1, // remplissage opaque par defaut
133 'fill-rule' => 'nonzero', // mode de remplissage par defaut
134 'stroke' => 'none', // pas de trait par defaut
135 'stroke-linecap' => 'butt', // style de langle par defaut
136 'stroke-linejoin' => 'miter',
137 'stroke-miterlimit' => 4, // limite de langle par defaut
138 'stroke-opacity' => 1, // trait opaque par defaut
139 'stroke-width' => 1,
140 'stroke-dasharray' => 0,
141 'stroke-dashoffset' => 0,
142 'color' => ''
143 )
144 );
145
146 $this->txt_style = array(
147 array(
148 'fill' => 'black', // pas de remplissage par defaut
149 'font-family' => $mpdf->default_font,
150 'font-size' => $mpdf->default_font_size, // ****** this is pts
151 'font-weight' => 'normal', // normal | bold
152 'font-style' => 'normal', // italic | normal
153 'text-anchor' => 'start', // alignment: start, middle, end
154 'fill-opacity' => 1, // remplissage opaque par defaut
155 'fill-rule' => 'nonzero', // mode de remplissage par defaut
156 'stroke' => 'none', // pas de trait par defaut
157 'stroke-opacity' => 1, // trait opaque par defaut
158 'stroke-width' => 1,
159 'color' => ''
160 )
161 );
162 }
163
164 // mPDF 5.7.4 Embedded image
165 function svgImage($attribs)
166 {
167 // x and y are coordinates
168 $x = (isset($attribs['x']) ? $attribs['x'] : 0);
169 $y = (isset($attribs['y']) ? $attribs['y'] : 0);
170 // preserveAspectRatio
171 $par = (isset($attribs['preserveAspectRatio']) ? $attribs['preserveAspectRatio'] : 'xMidYMid meet');
172 // width and height are <lengths> - Required attributes
173 $wset = (isset($attribs['width']) ? $attribs['width'] : 0);
174 $hset = (isset($attribs['height']) ? $attribs['height'] : 0);
175 $w = $this->mpdf_ref->ConvertSize($wset, $this->svg_info['w'] * (25.4 / $this->mpdf_ref->dpi), $this->mpdf_ref->FontSize, false);
176 $h = $this->mpdf_ref->ConvertSize($hset, $this->svg_info['h'] * (25.4 / $this->mpdf_ref->dpi), $this->mpdf_ref->FontSize, false);
177 if ($w == 0 || $h == 0) {
178 return;
179 }
180 // Convert to pixels = SVG units
181 $w *= 1 / (25.4 / $this->mpdf_ref->dpi);
182 $h *= 1 / (25.4 / $this->mpdf_ref->dpi);
183
184 $srcpath = $attribs['xlink:href'];
185 $orig_srcpath = '';
186 if (trim($srcpath) != '' && substr($srcpath, 0, 4) == 'var:') {
187 $orig_srcpath = $srcpath;
188 $this->mpdf_ref->GetFullPath($srcpath);
189 }
190
191 // Image file (does not allow vector images i.e. WMF/SVG)
192 // mPDF 6 Added $this->mpdf_ref->interpolateImages
193 $info = $this->mpdf_ref->_getImage($srcpath, true, false, $orig_srcpath, $this->mpdf_ref->interpolateImages);
194 if (!$info)
195 return;
196
197 // x,y,w,h define the reference rectangle
198 $img_h = $h;
199 $img_w = $w;
200 $img_x = $x;
201 $img_y = $y;
202 $meetOrSlice = 'meet';
203
204 // preserveAspectRatio
205 $ar = preg_split('/\s+/', strtolower($par));
206 if ($ar[0] != 'none') { // If "none" need to do nothing
207 // Force uniform scaling
208 if (isset($ar[1]) && $ar[1] == 'slice') {
209 $meetOrSlice = 'slice';
210 } else {
211 $meetOrSlice = 'meet';
212 }
213 if ($info['h'] / $info['w'] > $h / $w) {
214 if ($meetOrSlice == 'meet') { // the entire viewBox is visible within the viewport
215 $img_w = $img_h * $info['w'] / $info['h'];
216 } else { // the entire viewport is covered by the viewBox
217 $img_h = $img_w * $info['h'] / $info['w'];
218 }
219 } else if ($info['h'] / $info['w'] < $h / $w) {
220 if ($meetOrSlice == 'meet') { // the entire viewBox is visible within the viewport
221 $img_h = $img_w * $info['h'] / $info['w'];
222 } else { // the entire viewport is covered by the viewBox
223 $img_w = $img_h * $info['w'] / $info['h'];
224 }
225 }
226 if ($ar[0] == 'xminymin') {
227 // do nothing to x
228 // do nothing to y
229 } else if ($ar[0] == 'xmidymin') {
230 $img_x += $w / 2 - $img_w / 2; // xMid
231 // do nothing to y
232 } else if ($ar[0] == 'xmaxymin') {
233 $img_x += $w - $img_w; // xMax
234 // do nothing to y
235 } else if ($ar[0] == 'xminymid') {
236 // do nothing to x
237 $img_y += $h / 2 - $img_h / 2; // yMid
238 } else if ($ar[0] == 'xmaxymid') {
239 $img_x += $w - $img_w; // xMax
240 $img_y += $h / 2 - $img_h / 2; // yMid
241 } else if ($ar[0] == 'xminymax') {
242 // do nothing to x
243 $img_y += $h - $img_h; // yMax
244 } else if ($ar[0] == 'xmidymax') {
245 $img_x += $w / 2 - $img_w / 2; // xMid
246 $img_y += $h - $img_h; // yMax
247 } else if ($ar[0] == 'xmaxymax') {
248 $img_x += $w - $img_w; // xMax
249 $img_y += $h - $img_h; // yMax
250 } else { // xMidYMid (the default)
251 $img_x += $w / 2 - $img_w / 2; // xMid
252 $img_y += $h / 2 - $img_h / 2; // yMid
253 }
254 }
255
256 // Output
257 if ($meetOrSlice == 'slice') { // need to add a clipping path to reference rectangle
258 $s = ' q 0 w '; // Line width=0
259 $s .= sprintf('%.3F %.3F m ', ($x) * $this->kp, (-($y + $h)) * $this->kp); // start point TL before the arc
260 $s .= sprintf('%.3F %.3F l ', ($x) * $this->kp, (-($y)) * $this->kp); // line to BL
261 $s .= sprintf('%.3F %.3F l ', ($x + $w) * $this->kp, (-($y)) * $this->kp); // line to BR
262 $s .= sprintf('%.3F %.3F l ', ($x + $w) * $this->kp, (-($y + $h)) * $this->kp); // line to TR
263 $s .= sprintf('%.3F %.3F l ', ($x) * $this->kp, (-($y + $h)) * $this->kp); // line to TL
264 $s .= ' W n '; // Ends path no-op & Sets the clipping path
265 $this->svgWriteString($s);
266 }
267
268 $outstring = sprintf(" q %.3F 0 0 %.3F %.3F %.3F cm /I%d Do Q ", $img_w * $this->kp, $img_h * $this->kp, $img_x * $this->kp, -($img_y + $img_h) * $this->kp, $info['i']);
269 $this->svgWriteString($outstring);
270
271 if ($meetOrSlice == 'slice') { // need to end clipping path
272 $this->svgWriteString(' Q ');
273 }
274 }
275
276 function svgGradient($gradient_info, $attribs, $element)
277 {
278 $n = count($this->mpdf_ref->gradients) + 1;
279
280 // Get bounding dimensions of element
281 $w = 100;
282 $h = 100;
283 $x_offset = 0;
284 $y_offset = 0;
285 if ($element == 'rect') {
286 $w = $attribs['width'];
287 $h = $attribs['height'];
288 $x_offset = $attribs['x'];
289 $y_offset = $attribs['y'];
290 } else if ($element == 'ellipse') {
291 $w = $attribs['rx'] * 2;
292 $h = $attribs['ry'] * 2;
293 $x_offset = $attribs['cx'] - $attribs['rx'];
294 $y_offset = $attribs['cy'] - $attribs['ry'];
295 } else if ($element == 'circle') {
296 $w = $attribs['r'] * 2;
297 $h = $attribs['r'] * 2;
298 $x_offset = $attribs['cx'] - $attribs['r'];
299 $y_offset = $attribs['cy'] - $attribs['r'];
300 } else if ($element == 'polygon') {
301 $pts = preg_split('/[ ,]+/', trim($attribs['points']));
302 $maxr = $maxb = 0;
303 $minl = $mint = 999999;
304 for ($i = 0; $i < count($pts); $i++) {
305 if ($i % 2 == 0) { // x values
306 $minl = min($minl, $pts[$i]);
307 $maxr = max($maxr, $pts[$i]);
308 } else { // y values
309 $mint = min($mint, $pts[$i]);
310 $maxb = max($maxb, $pts[$i]);
311 }
312 }
313 $w = $maxr - $minl;
314 $h = $maxb - $mint;
315 $x_offset = $minl;
316 $y_offset = $mint;
317 } else if ($element == 'path') {
318 if (is_array($this->pathBBox) && $this->pathBBox[2] > 0) {
319 $w = $this->pathBBox[2];
320 $h = $this->pathBBox[3];
321 $x_offset = $this->pathBBox[0];
322 $y_offset = $this->pathBBox[1];
323 } else {
324 preg_match_all('/([a-z]|[A-Z])([ ,\-.\d]+)*/', $attribs['d'], $commands, PREG_SET_ORDER);
325 $maxr = $maxb = 0;
326 $minl = $mint = 999999;
327 foreach ($commands as $c) {
328 if (count($c) == 3) {
329 list($tmp, $cmd, $arg) = $c;
330 if ($cmd == 'M' || $cmd == 'L' || $cmd == 'C' || $cmd == 'S' || $cmd == 'Q' || $cmd == 'T') {
331 $pts = preg_split('/[ ,]+/', trim($arg));
332 for ($i = 0; $i < count($pts); $i++) {
333 if ($i % 2 == 0) { // x values
334 $minl = min($minl, $pts[$i]);
335 $maxr = max($maxr, $pts[$i]);
336 } else { // y values
337 $mint = min($mint, $pts[$i]);
338 $maxb = max($maxb, $pts[$i]);
339 }
340 }
341 }
342 if ($cmd == 'H') { // sets new x
343 $minl = min($minl, $arg);
344 $maxr = max($maxr, $arg);
345 }
346 if ($cmd == 'V') { // sets new y
347 $mint = min($mint, $arg);
348 $maxb = max($maxb, $arg);
349 }
350 }
351 }
352 $w = $maxr - $minl;
353 $h = $maxb - $mint;
354 $x_offset = $minl;
355 $y_offset = $mint;
356 }
357 }
358 if (!$w || $w == -999999) {
359 $w = 100;
360 }
361 if (!$h || $h == -999999) {
362 $h = 100;
363 }
364 if ($x_offset == 999999) {
365 $x_offset = 0;
366 }
367 if ($y_offset == 999999) {
368 $y_offset = 0;
369 }
370
371 // TRANSFORMATIONS
372 $transformations = '';
373 if (isset($gradient_info['transform'])) {
374 preg_match_all('/(matrix|translate|scale|rotate|skewX|skewY)\((.*?)\)/is', $gradient_info['transform'], $m);
375 if (count($m[0])) {
376 for ($i = 0; $i < count($m[0]); $i++) {
377 $c = strtolower($m[1][$i]);
378 $v = trim($m[2][$i]);
379 $vv = preg_split('/[ ,]+/', $v);
380 if ($c == 'matrix' && count($vv) == 6) {
381 // Note angle of rotation is reversed (from SVG to PDF), so vv[1] and vv[2] are negated
382 // cf svgDefineStyle()
383 $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);
384 } else if ($c == 'translate' && count($vv)) {
385 $tm[4] = $vv[0];
386 if (count($vv) == 2) {
387 $t_y = -$vv[1];
388 } else {
389 $t_y = 0;
390 }
391 $tm[5] = $t_y;
392 $transformations .= sprintf(' 1 0 0 1 %.3F %.3F cm ', $tm[4] * $this->kp, $tm[5] * $this->kp);
393 } else if ($c == 'scale' && count($vv)) {
394 if (count($vv) == 2) {
395 $s_y = $vv[1];
396 } else {
397 $s_y = $vv[0];
398 }
399 $tm[0] = $vv[0];
400 $tm[3] = $s_y;
401 $transformations .= sprintf(' %.3F 0 0 %.3F 0 0 cm ', $tm[0], $tm[3]);
402 } else if ($c == 'rotate' && count($vv)) {
403 $tm[0] = cos(deg2rad(-$vv[0]));
404 $tm[1] = sin(deg2rad(-$vv[0]));
405 $tm[2] = -$tm[1];
406 $tm[3] = $tm[0];
407 if (count($vv) == 3) {
408 $transformations .= sprintf(' 1 0 0 1 %.3F %.3F cm ', $vv[1] * $this->kp, -$vv[2] * $this->kp);
409 }
410 $transformations .= sprintf(' %.3F %.3F %.3F %.3F 0 0 cm ', $tm[0], $tm[1], $tm[2], $tm[3]);
411 if (count($vv) == 3) {
412 $transformations .= sprintf(' 1 0 0 1 %.3F %.3F cm ', -$vv[1] * $this->kp, $vv[2] * $this->kp);
413 }
414 } else if ($c == 'skewx' && count($vv)) {
415 $tm[2] = tan(deg2rad(-$vv[0]));
416 $transformations .= sprintf(' 1 0 %.3F 1 0 0 cm ', $tm[2]);
417 } else if ($c == 'skewy' && count($vv)) {
418 $tm[1] = tan(deg2rad(-$vv[0]));
419 $transformations .= sprintf(' 1 %.3F 0 1 0 0 cm ', $tm[1]);
420 }
421 }
422 }
423 }
424
425
426 $return = "";
427
428 if (isset($gradient_info['units']) && strtolower($gradient_info['units']) == 'userspaceonuse') {
429 if ($transformations) {
430 $return .= $transformations;
431 }
432 }
433 $spread = 'P'; // pad
434 if (isset($gradient_info['spread'])) {
435 if (strtolower($gradient_info['spread']) == 'reflect') {
436 $spread = 'F';
437 } // reflect
438 else if (strtolower($gradient_info['spread']) == 'repeat') {
439 $spread = 'R';
440 } // repeat
441 }
442
443
444 for ($i = 0; $i < (count($gradient_info['color'])); $i++) {
445 if (stristr($gradient_info['color'][$i]['offset'], '%') !== false) {
446 $gradient_info['color'][$i]['offset'] = ($gradient_info['color'][$i]['offset'] + 0) / 100;
447 }
448 if (isset($gradient_info['color'][($i + 1)]['offset']) && stristr($gradient_info['color'][($i + 1)]['offset'], '%') !== false) {
449 $gradient_info['color'][($i + 1)]['offset'] = ($gradient_info['color'][($i + 1)]['offset'] + 0) / 100;
450 }
451 if ($gradient_info['color'][$i]['offset'] < 0) {
452 $gradient_info['color'][$i]['offset'] = 0;
453 }
454 if ($gradient_info['color'][$i]['offset'] > 1) {
455 $gradient_info['color'][$i]['offset'] = 1;
456 }
457 if ($i > 0) {
458 if ($gradient_info['color'][$i]['offset'] < $gradient_info['color'][($i - 1)]['offset']) {
459 $gradient_info['color'][$i]['offset'] = $gradient_info['color'][($i - 1)]['offset'];
460 }
461 }
462 }
463
464 if (isset($gradient_info['color'][0]['offset']) && $gradient_info['color'][0]['offset'] > 0) {
465 array_unshift($gradient_info['color'], $gradient_info['color'][0]);
466 $gradient_info['color'][0]['offset'] = 0;
467 }
468 $ns = count($gradient_info['color']);
469 if (isset($gradient_info['color'][($ns - 1)]['offset']) && $gradient_info['color'][($ns - 1)]['offset'] < 1) {
470 $gradient_info['color'][] = $gradient_info['color'][($ns - 1)];
471 $gradient_info['color'][($ns)]['offset'] = 1;
472 }
473 $ns = count($gradient_info['color']);
474
475
476
477
478 if ($gradient_info['type'] == 'linear') {
479 // mPDF 4.4.003
480 if (isset($gradient_info['units']) && strtolower($gradient_info['units']) == 'userspaceonuse') {
481 if (isset($gradient_info['info']['x1'])) {
482 $gradient_info['info']['x1'] = ($gradient_info['info']['x1'] - $x_offset) / $w;
483 }
484 if (isset($gradient_info['info']['y1'])) {
485 $gradient_info['info']['y1'] = ($gradient_info['info']['y1'] - $y_offset) / $h;
486 }
487 if (isset($gradient_info['info']['x2'])) {
488 $gradient_info['info']['x2'] = ($gradient_info['info']['x2'] - $x_offset) / $w;
489 }
490 if (isset($gradient_info['info']['y2'])) {
491 $gradient_info['info']['y2'] = ($gradient_info['info']['y2'] - $y_offset) / $h;
492 }
493 }
494 if (isset($gradient_info['info']['x1'])) {
495 $x1 = $gradient_info['info']['x1'];
496 } else {
497 $x1 = 0;
498 }
499 if (isset($gradient_info['info']['y1'])) {
500 $y1 = $gradient_info['info']['y1'];
501 } else {
502 $y1 = 0;
503 }
504 if (isset($gradient_info['info']['x2'])) {
505 $x2 = $gradient_info['info']['x2'];
506 } else {
507 $x2 = 1;
508 }
509 if (isset($gradient_info['info']['y2'])) {
510 $y2 = $gradient_info['info']['y2'];
511 } else {
512 $y2 = 0;
513 } // mPDF 6
514
515 if (stristr($x1, '%') !== false) {
516 $x1 = ($x1 + 0) / 100;
517 }
518 if (stristr($x2, '%') !== false) {
519 $x2 = ($x2 + 0) / 100;
520 }
521 if (stristr($y1, '%') !== false) {
522 $y1 = ($y1 + 0) / 100;
523 }
524 if (stristr($y2, '%') !== false) {
525 $y2 = ($y2 + 0) / 100;
526 }
527
528 // mPDF 5.0.042
529 $bboxw = $w;
530 $bboxh = $h;
531 $usex = $x_offset;
532 $usey = $y_offset;
533 $usew = $bboxw;
534 $useh = $bboxh;
535 if (isset($gradient_info['units']) && strtolower($gradient_info['units']) == 'userspaceonuse') {
536 $angle = rad2deg(atan2(($gradient_info['info']['y2'] - $gradient_info['info']['y1']), ($gradient_info['info']['x2'] - $gradient_info['info']['x1'])));
537 if ($angle < 0) {
538 $angle += 360;
539 } else if ($angle > 360) {
540 $angle -= 360;
541 }
542 if ($angle != 0 && $angle != 360 && $angle != 90 && $angle != 180 && $angle != 270) {
543 if ($w >= $h) {
544 $y1 *= $h / $w;
545 $y2 *= $h / $w;
546 $usew = $useh = $bboxw;
547 } else {
548 $x1 *= $w / $h;
549 $x2 *= $w / $h;
550 $usew = $useh = $bboxh;
551 }
552 }
553 }
554 $a = $usew; // width
555 $d = -$useh; // height
556 $e = $usex; // x- offset
557 $f = -$usey; // -y-offset
558
559 $return .= sprintf('%.3F 0 0 %.3F %.3F %.3F cm ', $a * $this->kp, $d * $this->kp, $e * $this->kp, $f * $this->kp);
560
561 if (isset($gradient_info['units']) && strtolower($gradient_info['units']) == 'objectboundingbox') {
562 if ($transformations) {
563 $return .= $transformations;
564 }
565 }
566
567 $trans = false;
568
569 if ($spread == 'R' || $spread == 'F') { // Repeat / Reflect
570 $offs = array();
571 for ($i = 0; $i < $ns; $i++) {
572 $offs[$i] = $gradient_info['color'][$i]['offset'];
573 }
574 $gp = 0;
575 $inside = true;
576 while ($inside) {
577 $gp++;
578 for ($i = 0; $i < $ns; $i++) {
579 if ($spread == 'F' && ($gp % 2) == 1) { // Reflect
580 $gradient_info['color'][(($ns * $gp) + $i)] = $gradient_info['color'][(($ns * ($gp - 1)) + ($ns - $i - 1))];
581 $tmp = $gp + (1 - $offs[($ns - $i - 1)]);
582 $gradient_info['color'][(($ns * $gp) + $i)]['offset'] = $tmp;
583 } else { // Reflect
584 $gradient_info['color'][(($ns * $gp) + $i)] = $gradient_info['color'][$i];
585 $tmp = $gp + $offs[$i];
586 $gradient_info['color'][(($ns * $gp) + $i)]['offset'] = $tmp;
587 }
588 // IF STILL INSIDE BOX OR STILL VALID
589 // Point on axis to test
590 $px1 = $x1 + ($x2 - $x1) * $tmp;
591 $py1 = $y1 + ($y2 - $y1) * $tmp;
592 // Get perpendicular axis
593 $alpha = atan2($y2 - $y1, $x2 - $x1);
594 $alpha += M_PI / 2; // rotate 90 degrees
595 // Get arbitrary point to define line perpendicular to axis
596 $px2 = $px1 + cos($alpha);
597 $py2 = $py1 + sin($alpha);
598
599 $res1 = _testIntersect($px1, $py1, $px2, $py2, 0, 0, 0, 1); // $x=0 vert axis
600 $res2 = _testIntersect($px1, $py1, $px2, $py2, 1, 0, 1, 1); // $x=1 vert axis
601 $res3 = _testIntersect($px1, $py1, $px2, $py2, 0, 0, 1, 0); // $y=0 horiz axis
602 $res4 = _testIntersect($px1, $py1, $px2, $py2, 0, 1, 1, 1); // $y=1 horiz axis
603 if (!$res1 && !$res2 && !$res3 && !$res4) {
604 $inside = false;
605 }
606 }
607 }
608
609 $inside = true;
610 $gp = 0;
611 while ($inside) {
612 $gp++;
613 $newarr = array();
614 for ($i = 0; $i < $ns; $i++) {
615 if ($spread == 'F') { // Reflect
616 $newarr[$i] = $gradient_info['color'][($ns - $i - 1)];
617 if (($gp % 2) == 1) {
618 $tmp = -$gp + (1 - $offs[($ns - $i - 1)]);
619 $newarr[$i]['offset'] = $tmp;
620 } else {
621 $tmp = -$gp + $offs[$i];
622 $newarr[$i]['offset'] = $tmp;
623 }
624 } else { // Reflect
625 $newarr[$i] = $gradient_info['color'][$i];
626 $tmp = -$gp + $offs[$i];
627 $newarr[$i]['offset'] = $tmp;
628 }
629
630 // IF STILL INSIDE BOX OR STILL VALID
631 // Point on axis to test
632 $px1 = $x1 + ($x2 - $x1) * $tmp;
633 $py1 = $y1 + ($y2 - $y1) * $tmp;
634 // Get perpendicular axis
635 $alpha = atan2($y2 - $y1, $x2 - $x1);
636 $alpha += M_PI / 2; // rotate 90 degrees
637 // Get arbitrary point to define line perpendicular to axis
638 $px2 = $px1 + cos($alpha);
639 $py2 = $py1 + sin($alpha);
640
641 $res1 = _testIntersect($px1, $py1, $px2, $py2, 0, 0, 0, 1); // $x=0 vert axis
642 $res2 = _testIntersect($px1, $py1, $px2, $py2, 1, 0, 1, 1); // $x=1 vert axis
643 $res3 = _testIntersect($px1, $py1, $px2, $py2, 0, 0, 1, 0); // $y=0 horiz axis
644 $res4 = _testIntersect($px1, $py1, $px2, $py2, 0, 1, 1, 1); // $y=1 horiz axis
645 if (!$res1 && !$res2 && !$res3 && !$res4) {
646 $inside = false;
647 }
648 }
649 for ($i = ($ns - 1); $i >= 0; $i--) {
650 if (isset($newarr[$i]['offset']))
651 array_unshift($gradient_info['color'], $newarr[$i]);
652 }
653 }
654 }
655
656 // Gradient STOPs
657 $stops = count($gradient_info['color']);
658 if ($stops < 2) {
659 return '';
660 }
661
662 $range = $gradient_info['color'][count($gradient_info['color']) - 1]['offset'] - $gradient_info['color'][0]['offset'];
663 $min = $gradient_info['color'][0]['offset'];
664
665 for ($i = 0; $i < ($stops); $i++) {
666 if (!$gradient_info['color'][$i]['color']) {
667 if ($gradient_info['colorspace'] == 'RGB')
668 $gradient_info['color'][$i]['color'] = '0 0 0';
669 else if ($gradient_info['colorspace'] == 'Gray')
670 $gradient_info['color'][$i]['color'] = '0';
671 else if ($gradient_info['colorspace'] == 'CMYK')
672 $gradient_info['color'][$i]['color'] = '1 1 1 1';
673 }
674 $offset = ($gradient_info['color'][$i]['offset'] - $min) / $range;
675 $this->mpdf_ref->gradients[$n]['stops'][] = array(
676 'col' => $gradient_info['color'][$i]['color'],
677 'opacity' => $gradient_info['color'][$i]['opacity'],
678 'offset' => $offset);
679 if ($gradient_info['color'][$i]['opacity'] < 1) {
680 $trans = true;
681 }
682 }
683 $grx1 = $x1 + ($x2 - $x1) * $gradient_info['color'][0]['offset'];
684 $gry1 = $y1 + ($y2 - $y1) * $gradient_info['color'][0]['offset'];
685 $grx2 = $x1 + ($x2 - $x1) * $gradient_info['color'][count($gradient_info['color']) - 1]['offset'];
686 $gry2 = $y1 + ($y2 - $y1) * $gradient_info['color'][count($gradient_info['color']) - 1]['offset'];
687
688 $this->mpdf_ref->gradients[$n]['coords'] = array($grx1, $gry1, $grx2, $gry2);
689
690 $this->mpdf_ref->gradients[$n]['colorspace'] = $gradient_info['colorspace'];
691
692 $this->mpdf_ref->gradients[$n]['type'] = 2;
693 $this->mpdf_ref->gradients[$n]['fo'] = true;
694
695 $this->mpdf_ref->gradients[$n]['extend'] = array('true', 'true');
696 if ($trans) {
697 $this->mpdf_ref->gradients[$n]['trans'] = true;
698 $return .= ' /TGS' . ($n) . ' gs ';
699 }
700 $return .= ' /Sh' . ($n) . ' sh ';
701 $return .= " Q\n";
702 } else if ($gradient_info['type'] == 'radial') {
703 if (isset($gradient_info['units']) && strtolower($gradient_info['units']) == 'userspaceonuse') {
704 if ($w > $h) {
705 $h = $w;
706 } else {
707 $w = $h;
708 }
709 if (isset($gradient_info['info']['x0'])) {
710 $gradient_info['info']['x0'] = ($gradient_info['info']['x0'] - $x_offset) / $w;
711 }
712 if (isset($gradient_info['info']['y0'])) {
713 $gradient_info['info']['y0'] = ($gradient_info['info']['y0'] - $y_offset) / $h;
714 }
715 if (isset($gradient_info['info']['x1'])) {
716 $gradient_info['info']['x1'] = ($gradient_info['info']['x1'] - $x_offset) / $w;
717 }
718 if (isset($gradient_info['info']['y1'])) {
719 $gradient_info['info']['y1'] = ($gradient_info['info']['y1'] - $y_offset) / $h;
720 }
721 if (isset($gradient_info['info']['r'])) {
722 $gradient_info['info']['rx'] = $gradient_info['info']['r'] / $w;
723 }
724 if (isset($gradient_info['info']['r'])) {
725 $gradient_info['info']['ry'] = $gradient_info['info']['r'] / $h;
726 }
727 }
728
729 if (isset($gradient_info['info']['x0'])) {
730 $x0 = $gradient_info['info']['x0'];
731 } else {
732 $x0 = 0.5;
733 }
734 if (isset($gradient_info['info']['y0'])) {
735 $y0 = $gradient_info['info']['y0'];
736 } else {
737 $y0 = 0.5;
738 }
739 if (isset($gradient_info['info']['rx'])) {
740 $rx = $gradient_info['info']['rx'];
741 } else if (isset($gradient_info['info']['r'])) {
742 $rx = $gradient_info['info']['r'];
743 } else {
744 $rx = 0.5;
745 }
746 if (isset($gradient_info['info']['ry'])) {
747 $ry = $gradient_info['info']['ry'];
748 } else if (isset($gradient_info['info']['r'])) {
749 $ry = $gradient_info['info']['r'];
750 } else {
751 $ry = 0.5;
752 }
753 if (isset($gradient_info['info']['x1'])) {
754 $x1 = $gradient_info['info']['x1'];
755 } else {
756 $x1 = $x0;
757 }
758 if (isset($gradient_info['info']['y1'])) {
759 $y1 = $gradient_info['info']['y1'];
760 } else {
761 $y1 = $y0;
762 }
763
764 if (stristr($x1, '%') !== false) {
765 $x1 = ($x1 + 0) / 100;
766 }
767 if (stristr($x0, '%') !== false) {
768 $x0 = ($x0 + 0) / 100;
769 }
770 if (stristr($y1, '%') !== false) {
771 $y1 = ($y1 + 0) / 100;
772 }
773 if (stristr($y0, '%') !== false) {
774 $y0 = ($y0 + 0) / 100;
775 }
776 if (stristr($rx, '%') !== false) {
777 $rx = ($rx + 0) / 100;
778 }
779 if (stristr($ry, '%') !== false) {
780 $ry = ($ry + 0) / 100;
781 }
782
783 $bboxw = $w;
784 $bboxh = $h;
785 $usex = $x_offset;
786 $usey = $y_offset;
787 $usew = $bboxw;
788 $useh = $bboxh;
789 if (isset($gradient_info['units']) && strtolower($gradient_info['units']) == 'userspaceonuse') {
790 $angle = rad2deg(atan2(($gradient_info['info']['y0'] - $gradient_info['info']['y1']), ($gradient_info['info']['x0'] - $gradient_info['info']['x1'])));
791 if ($angle < 0) {
792 $angle += 360;
793 } else if ($angle > 360) {
794 $angle -= 360;
795 }
796 if ($angle != 0 && $angle != 360 && $angle != 90 && $angle != 180 && $angle != 270) {
797 if ($w >= $h) {
798 $y1 *= $h / $w;
799 $y0 *= $h / $w;
800 $rx *= $h / $w;
801 $ry *= $h / $w;
802 $usew = $useh = $bboxw;
803 } else {
804 $x1 *= $w / $h;
805 $x0 *= $w / $h;
806 $rx *= $w / $h;
807 $ry *= $w / $h;
808 $usew = $useh = $bboxh;
809 }
810 }
811 }
812 $a = $usew; // width
813 $d = -$useh; // height
814 $e = $usex; // x- offset
815 $f = -$usey; // -y-offset
816
817 $r = $rx;
818
819
820 $return .= sprintf('%.3F 0 0 %.3F %.3F %.3F cm ', $a * $this->kp, $d * $this->kp, $e * $this->kp, $f * $this->kp);
821
822 // mPDF 5.0.039
823 if (isset($gradient_info['units']) && strtolower($gradient_info['units']) == 'objectboundingbox') {
824 if ($transformations) {
825 $return .= $transformations;
826 }
827 }
828
829 // mPDF 5.7.4
830 // x1 and y1 (fx, fy) should be inside the circle defined by x0 y0 (cx, cy)
831 // "If the point defined by fx and fy lies outside the circle defined by cx, cy and r, then the user agent shall set
832 // the focal point to the intersection of the line from (cx, cy) to (fx, fy) with the circle defined by cx, cy and r."
833 while (pow(($x1 - $x0), 2) + pow(($y1 - $y0), 2) >= pow($r, 2)) {
834 // Gradually move along fx,fy towards cx,cy in 100'ths until meets criteria
835 $x1 -= ($x1 - $x0) / 100;
836 $y1 -= ($y1 - $y0) / 100;
837 }
838
839
840 if ($spread == 'R' || $spread == 'F') { // Repeat / Reflect
841 $offs = array();
842 for ($i = 0; $i < $ns; $i++) {
843 $offs[$i] = $gradient_info['color'][$i]['offset'];
844 }
845 $gp = 0;
846 $inside = true;
847 while ($inside) {
848 $gp++;
849 for ($i = 0; $i < $ns; $i++) {
850 if ($spread == 'F' && ($gp % 2) == 1) { // Reflect
851 $gradient_info['color'][(($ns * $gp) + $i)] = $gradient_info['color'][(($ns * ($gp - 1)) + ($ns - $i - 1))];
852 $tmp = $gp + (1 - $offs[($ns - $i - 1)]);
853 $gradient_info['color'][(($ns * $gp) + $i)]['offset'] = $tmp;
854 } else { // Reflect
855 $gradient_info['color'][(($ns * $gp) + $i)] = $gradient_info['color'][$i];
856 $tmp = $gp + $offs[$i];
857 $gradient_info['color'][(($ns * $gp) + $i)]['offset'] = $tmp;
858 }
859 // IF STILL INSIDE BOX OR STILL VALID
860 // TEST IF circle (perimeter) intersects with
861 // or is enclosed
862 // Point on axis to test
863 $px = $x1 + ($x0 - $x1) * $tmp;
864 $py = $y1 + ($y0 - $y1) * $tmp;
865 $pr = $r * $tmp;
866 $res = _testIntersectCircle($px, $py, $pr);
867 if (!$res) {
868 $inside = false;
869 }
870 }
871 }
872 }
873
874 // Gradient STOPs
875 $stops = count($gradient_info['color']);
876 if ($stops < 2) {
877 return '';
878 }
879
880 $range = $gradient_info['color'][count($gradient_info['color']) - 1]['offset'] - $gradient_info['color'][0]['offset'];
881 $min = $gradient_info['color'][0]['offset'];
882
883 for ($i = 0; $i < ($stops); $i++) {
884 if (!$gradient_info['color'][$i]['color']) {
885 if ($gradient_info['colorspace'] == 'RGB')
886 $gradient_info['color'][$i]['color'] = '0 0 0';
887 else if ($gradient_info['colorspace'] == 'Gray')
888 $gradient_info['color'][$i]['color'] = '0';
889 else if ($gradient_info['colorspace'] == 'CMYK')
890 $gradient_info['color'][$i]['color'] = '1 1 1 1';
891 }
892 $offset = ($gradient_info['color'][$i]['offset'] - $min) / $range;
893 $this->mpdf_ref->gradients[$n]['stops'][] = array(
894 'col' => $gradient_info['color'][$i]['color'],
895 'opacity' => $gradient_info['color'][$i]['opacity'],
896 'offset' => $offset);
897 if ($gradient_info['color'][$i]['opacity'] < 1) {
898 $trans = true;
899 }
900 }
901 $grx1 = $x1 + ($x0 - $x1) * $gradient_info['color'][0]['offset'];
902 $gry1 = $y1 + ($y0 - $y1) * $gradient_info['color'][0]['offset'];
903 $grx2 = $x1 + ($x0 - $x1) * $gradient_info['color'][count($gradient_info['color']) - 1]['offset'];
904 $gry2 = $y1 + ($y0 - $y1) * $gradient_info['color'][count($gradient_info['color']) - 1]['offset'];
905 $grir = $r * $gradient_info['color'][0]['offset'];
906 $grr = $r * $gradient_info['color'][count($gradient_info['color']) - 1]['offset'];
907
908 $this->mpdf_ref->gradients[$n]['coords'] = array($grx1, $gry1, $grx2, $gry2, abs($grr), abs($grir));
909
910 $this->mpdf_ref->gradients[$n]['colorspace'] = $gradient_info['colorspace'];
911
912 $this->mpdf_ref->gradients[$n]['type'] = 3;
913 $this->mpdf_ref->gradients[$n]['fo'] = true;
914
915 $this->mpdf_ref->gradients[$n]['extend'] = array('true', 'true');
916 if (isset($trans) && $trans) {
917 $this->mpdf_ref->gradients[$n]['trans'] = true;
918 $return .= ' /TGS' . ($n) . ' gs ';
919 }
920 $return .= ' /Sh' . ($n) . ' sh ';
921 $return .= " Q\n";
922 }
923
924 return $return;
925 }
926
927 function svgOffset($attribs)
928 {
929 // save all <svg> tag attributes
930 $this->svg_attribs = $attribs;
931 if (isset($this->svg_attribs['viewBox'])) {
932 $vb = preg_split('/\s+/is', trim($this->svg_attribs['viewBox']));
933 if (count($vb) == 4) {
934 $this->svg_info['x'] = $vb[0];
935 $this->svg_info['y'] = $vb[1];
936 $this->svg_info['w'] = $vb[2];
937 $this->svg_info['h'] = $vb[3];
938 // return;
939 }
940 }
941 $svg_w = 0;
942 $svg_h = 0;
943 if (isset($attribs['width']) && $attribs['width'])
944 $svg_w = $this->mpdf_ref->ConvertSize($attribs['width']); // mm (interprets numbers as pixels)
945 if (isset($attribs['height']) && $attribs['height'])
946 $svg_h = $this->mpdf_ref->ConvertSize($attribs['height']); // mm
947
948
949 ///*
950 // mPDF 5.0.005
951 if (isset($this->svg_info['w']) && $this->svg_info['w']) { // if 'w' set by viewBox
952 if ($svg_w) { // if width also set, use these values to determine to set size of "pixel"
953 $this->kp *= ($svg_w / 0.2645) / $this->svg_info['w'];
954 $this->kf = ($svg_w / 0.2645) / $this->svg_info['w'];
955 } else if ($svg_h) {
956 $this->kp *= ($svg_h / 0.2645) / $this->svg_info['h'];
957 $this->kf = ($svg_h / 0.2645) / $this->svg_info['h'];
958 }
959 return;
960 }
961 //*/
962 // Added to handle file without height or width specified
963 if (!$svg_w && !$svg_h) {
964 $svg_w = $svg_h = $this->mpdf_ref->blk[$this->mpdf_ref->blklvl]['inner_width'];
965 } // DEFAULT
966 if (!$svg_w) {
967 $svg_w = $svg_h;
968 }
969 if (!$svg_h) {
970 $svg_h = $svg_w;
971 }
972
973 $this->svg_info['x'] = 0;
974 $this->svg_info['y'] = 0;
975 $this->svg_info['w'] = $svg_w / 0.2645; // mm->pixels
976 $this->svg_info['h'] = $svg_h / 0.2645; // mm->pixels
977 }
978
979 //
980 // check if points are within svg, if not, set to max
981 function svg_overflow($x, $y)
982 {
983 $x2 = $x;
984 $y2 = $y;
985 if (isset($this->svg_attribs['overflow'])) {
986 if ($this->svg_attribs['overflow'] == 'hidden') {
987 // Not sure if this is supposed to strip off units, but since I dont use any I will omlt this step
988 $svg_w = preg_replace("/([0-9\.]*)(.*)/i", "$1", $this->svg_attribs['width']);
989 $svg_h = preg_replace("/([0-9\.]*)(.*)/i", "$1", $this->svg_attribs['height']);
990
991 // $xmax = floor($this->svg_attribs['width']);
992 $xmax = floor($svg_w);
993 $xmin = 0;
994 // $ymax = floor(($this->svg_attribs['height'] * -1));
995 $ymax = floor(($svg_h * -1));
996 $ymin = 0;
997
998 if ($x > $xmax)
999 $x2 = $xmax; // right edge
1000 if ($x < $xmin)
1001 $x2 = $xmin; // left edge
1002 if ($y < $ymax)
1003 $y2 = $ymax; // bottom
1004 if ($y > $ymin)
1005 $y2 = $ymin; // top
1006 }
1007 }
1008
1009
1010 return array('x' => $x2, 'y' => $y2);
1011 }
1012
1013 function svgDefineStyle($critere_style)
1014 {
1015
1016 $tmp = count($this->svg_style) - 1;
1017 $current_style = $this->svg_style[$tmp];
1018
1019 unset($current_style['transformations']);
1020
1021 // TRANSFORM SCALE
1022 $transformations = '';
1023 if (isset($critere_style['transform'])) {
1024 preg_match_all('/(matrix|translate|scale|rotate|skewX|skewY)\((.*?)\)/is', $critere_style['transform'], $m);
1025 if (count($m[0])) {
1026 for ($i = 0; $i < count($m[0]); $i++) {
1027 $c = strtolower($m[1][$i]);
1028 $v = trim($m[2][$i]);
1029 $vv = preg_split('/[ ,]+/', $v);
1030 if ($c == 'matrix' && count($vv) == 6) {
1031 // mPDF 5.0.039
1032 // Note angle of rotation is reversed (from SVG to PDF), so vv[1] and vv[2] are negated
1033 $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);
1034
1035 /*
1036 // The long way of doing this??
1037 // need to reverse angle of rotation from SVG to PDF
1038 $sx=sqrt(pow($vv[0],2)+pow($vv[2],2));
1039 if ($vv[0] < 0) { $sx *= -1; } // change sign
1040 $sy=sqrt(pow($vv[1],2)+pow($vv[3],2));
1041 if ($vv[3] < 0) { $sy *= -1; } // change sign
1042
1043 // rotation angle is
1044 $t=atan2($vv[1],$vv[3]);
1045 $t=atan2(-$vv[2],$vv[0]); // Should be the same value or skew has been applied
1046
1047 // Reverse angle
1048 $t *= -1;
1049
1050 // Rebuild matrix
1051 $ma = $sx * cos($t);
1052 $mb = $sy * sin($t);
1053 $mc = -$sx * sin($t);
1054 $md = $sy * cos($t);
1055
1056 // $transformations .= sprintf(' %.3F %.3F %.3F %.3F %.3F %.3F cm ', $ma, $mb, $mc, $md, $vv[4]*$this->kp, -$vv[5]*$this->kp);
1057 */
1058 } else if ($c == 'translate' && count($vv)) {
1059 $tm[4] = $vv[0];
1060 if (count($vv) == 2) {
1061 $t_y = -$vv[1];
1062 } else {
1063 $t_y = 0;
1064 }
1065 $tm[5] = $t_y;
1066 $transformations .= sprintf(' 1 0 0 1 %.3F %.3F cm ', $tm[4] * $this->kp, $tm[5] * $this->kp);
1067 } else if ($c == 'scale' && count($vv)) {
1068 if (count($vv) == 2) {
1069 $s_y = $vv[1];
1070 } else {
1071 $s_y = $vv[0];
1072 }
1073 $tm[0] = $vv[0];
1074 $tm[3] = $s_y;
1075 $transformations .= sprintf(' %.3F 0 0 %.3F 0 0 cm ', $tm[0], $tm[3]);
1076 } else if ($c == 'rotate' && count($vv)) {
1077 $tm[0] = cos(deg2rad(-$vv[0]));
1078 $tm[1] = sin(deg2rad(-$vv[0]));
1079 $tm[2] = -$tm[1];
1080 $tm[3] = $tm[0];
1081 if (count($vv) == 3) {
1082 $transformations .= sprintf(' 1 0 0 1 %.3F %.3F cm ', $vv[1] * $this->kp, -$vv[2] * $this->kp);
1083 }
1084 $transformations .= sprintf(' %.3F %.3F %.3F %.3F 0 0 cm ', $tm[0], $tm[1], $tm[2], $tm[3]);
1085 if (count($vv) == 3) {
1086 $transformations .= sprintf(' 1 0 0 1 %.3F %.3F cm ', -$vv[1] * $this->kp, $vv[2] * $this->kp);
1087 }
1088 } else if ($c == 'skewx' && count($vv)) {
1089 $tm[2] = tan(deg2rad(-$vv[0]));
1090 $transformations .= sprintf(' 1 0 %.3F 1 0 0 cm ', $tm[2]);
1091 } else if ($c == 'skewy' && count($vv)) {
1092 $tm[1] = tan(deg2rad(-$vv[0]));
1093 $transformations .= sprintf(' 1 %.3F 0 1 0 0 cm ', $tm[1]);
1094 }
1095 }
1096 }
1097 $current_style['transformations'] = $transformations;
1098 }
1099
1100 if (isset($critere_style['style'])) {
1101 if (preg_match('/fill:\s*rgb\((\d+),\s*(\d+),\s*(\d+)\)/i', $critere_style['style'], $m)) { // mPDF 5.7.2
1102 $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);
1103 } else {
1104 $tmp = preg_replace("/(.*)fill:\s*([a-z0-9#_()]*|none)(.*)/i", "$2", $critere_style['style']);
1105 if ($tmp && $tmp != 'inherit' && $tmp != $critere_style['style']) {
1106 $current_style['fill'] = $tmp;
1107 }
1108 }
1109
1110 // mPDF 5.7.2
1111 if ((preg_match("/[^-]opacity:\s*([a-z0-9.]*|none)/i", $critere_style['style'], $m) ||
1112 preg_match("/^opacity:\s*([a-z0-9.]*|none)/i", $critere_style['style'], $m)) && $m[1] != 'inherit') {
1113 $current_style['fill-opacity'] = $m[1];
1114 $current_style['stroke-opacity'] = $m[1];
1115 }
1116
1117 $tmp = preg_replace("/(.*)fill-opacity:\s*([a-z0-9.]*|none)(.*)/i", "$2", $critere_style['style']);
1118 if ($tmp && $tmp != 'inherit' && $tmp != $critere_style['style']) {
1119 $current_style['fill-opacity'] = $tmp;
1120 }
1121
1122 $tmp = preg_replace("/(.*)fill-rule:\s*([a-z0-9#]*|none)(.*)/i", "$2", $critere_style['style']);
1123 if ($tmp && $tmp != 'inherit' && $tmp != $critere_style['style']) {
1124 $current_style['fill-rule'] = $tmp;
1125 }
1126
1127 if (preg_match('/stroke:\s*rgb\((\d+),\s*(\d+),\s*(\d+)\)/', $critere_style['style'], $m)) {
1128 $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);
1129 } else {
1130 $tmp = preg_replace("/(.*)stroke:\s*([a-z0-9#]*|none)(.*)/i", "$2", $critere_style['style']);
1131 if ($tmp && $tmp != 'inherit' && $tmp != $critere_style['style']) {
1132 $current_style['stroke'] = $tmp;
1133 }
1134 }
1135
1136 $tmp = preg_replace("/(.*)stroke-linecap:\s*([a-z0-9#]*|none)(.*)/i", "$2", $critere_style['style']);
1137 if ($tmp && $tmp != 'inherit' && $tmp != $critere_style['style']) {
1138 $current_style['stroke-linecap'] = $tmp;
1139 }
1140
1141 $tmp = preg_replace("/(.*)stroke-linejoin:\s*([a-z0-9#]*|none)(.*)/i", "$2", $critere_style['style']);
1142 if ($tmp && $tmp != 'inherit' && $tmp != $critere_style['style']) {
1143 $current_style['stroke-linejoin'] = $tmp;
1144 }
1145
1146 $tmp = preg_replace("/(.*)stroke-miterlimit:\s*([a-z0-9#]*|none)(.*)/i", "$2", $critere_style['style']);
1147 if ($tmp && $tmp != 'inherit' && $tmp != $critere_style['style']) {
1148 $current_style['stroke-miterlimit'] = $tmp;
1149 }
1150
1151 $tmp = preg_replace("/(.*)stroke-opacity:\s*([a-z0-9.]*|none)(.*)/i", "$2", $critere_style['style']);
1152 if ($tmp && $tmp != 'inherit' && $tmp != $critere_style['style']) {
1153 $current_style['stroke-opacity'] = $tmp;
1154 }
1155
1156 $tmp = preg_replace("/(.*)stroke-width:\s*([a-z0-9.]*|none)(.*)/i", "$2", $critere_style['style']);
1157 if ($tmp && $tmp != 'inherit' && $tmp != $critere_style['style']) {
1158 $current_style['stroke-width'] = $tmp;
1159 }
1160
1161 $tmp = preg_replace("/(.*)stroke-dasharray:\s*([a-z0-9., ]*|none)(.*)/i", "$2", $critere_style['style']);
1162 if ($tmp && $tmp != 'inherit' && $tmp != $critere_style['style']) {
1163 $current_style['stroke-dasharray'] = $tmp;
1164 }
1165
1166 $tmp = preg_replace("/(.*)stroke-dashoffset:\s*([a-z0-9.]*|none)(.*)/i", "$2", $critere_style['style']);
1167 if ($tmp && $tmp != 'inherit' && $tmp != $critere_style['style']) {
1168 $current_style['stroke-dashoffset'] = $tmp;
1169 }
1170 }
1171 // mPDF 5.7.2
1172 if (isset($critere_style['opacity']) && $critere_style['opacity'] != 'inherit') {
1173 $current_style['fill-opacity'] = $critere_style['opacity'];
1174 $current_style['stroke-opacity'] = $critere_style['opacity'];
1175 }
1176
1177 if (isset($critere_style['fill']) && $critere_style['fill'] != 'inherit') {
1178 $current_style['fill'] = $critere_style['fill'];
1179 }
1180
1181 if (isset($critere_style['fill-opacity']) && $critere_style['fill-opacity'] != 'inherit') {
1182 $current_style['fill-opacity'] = $critere_style['fill-opacity'];
1183 }
1184
1185 if (isset($critere_style['fill-rule']) && $critere_style['fill-rule'] != 'inherit') {
1186 $current_style['fill-rule'] = $critere_style['fill-rule'];
1187 }
1188
1189 if (isset($critere_style['stroke']) && $critere_style['stroke'] != 'inherit') {
1190 $current_style['stroke'] = $critere_style['stroke'];
1191 }
1192
1193 if (isset($critere_style['stroke-linecap']) && $critere_style['stroke-linecap'] != 'inherit') {
1194 $current_style['stroke-linecap'] = $critere_style['stroke-linecap'];
1195 }
1196
1197 if (isset($critere_style['stroke-linejoin']) && $critere_style['stroke-linejoin'] != 'inherit') {
1198 $current_style['stroke-linejoin'] = $critere_style['stroke-linejoin'];
1199 }
1200
1201 if (isset($critere_style['stroke-miterlimit']) && $critere_style['stroke-miterlimit'] != 'inherit') {
1202 $current_style['stroke-miterlimit'] = $critere_style['stroke-miterlimit'];
1203 }
1204
1205 if (isset($critere_style['stroke-opacity']) && $critere_style['stroke-opacity'] != 'inherit') {
1206 $current_style['stroke-opacity'] = $critere_style['stroke-opacity'];
1207 }
1208
1209 if (isset($critere_style['stroke-width']) && $critere_style['stroke-width'] != 'inherit') {
1210 $current_style['stroke-width'] = $critere_style['stroke-width'];
1211 }
1212
1213 if (isset($critere_style['stroke-dasharray']) && $critere_style['stroke-dasharray'] != 'inherit') {
1214 $current_style['stroke-dasharray'] = $critere_style['stroke-dasharray'];
1215 }
1216 if (isset($critere_style['stroke-dashoffset']) && $critere_style['stroke-dashoffset'] != 'inherit') {
1217 $current_style['stroke-dashoffset'] = $critere_style['stroke-dashoffset'];
1218 }
1219
1220 // Used as indirect setting for currentColor
1221 if (isset($critere_style['color']) && $critere_style['color'] != 'inherit') {
1222 $current_style['color'] = $critere_style['color'];
1223 }
1224
1225 return $current_style;
1226 }
1227
1228 //
1229 // Cette fonction ecrit le style dans le stream svg.
1230 function svgStyle($critere_style, $attribs, $element)
1231 {
1232 $path_style = '';
1233 $fill_gradient = '';
1234 $w = '';
1235 $style = '';
1236 if (substr_count($critere_style['fill'], 'url') > 0 && $element != 'line') {
1237 //
1238 // couleur degradé
1239 $id_gradient = preg_replace("/url\(#([\w_]*)\)/i", "$1", $critere_style['fill']);
1240 if ($id_gradient != $critere_style['fill']) {
1241 if (isset($this->svg_gradient[$id_gradient])) {
1242 $fill_gradient = $this->svgGradient($this->svg_gradient[$id_gradient], $attribs, $element);
1243 if ($fill_gradient) {
1244 $path_style = "q ";
1245 $w = "W";
1246 $style .= 'N';
1247 }
1248 }
1249 }
1250 }
1251 // Used as indirect setting for currentColor
1252 else if (strtolower($critere_style['fill']) == 'currentcolor' && $element != 'line') {
1253 $col = $this->mpdf_ref->ConvertColor($critere_style['color']);
1254 if ($col) {
1255 if ($col[0] == 5) {
1256 $critere_style['fill-opacity'] = ord($col[4] / 100);
1257 } // RGBa
1258 if ($col[0] == 6) {
1259 $critere_style['fill-opacity'] = ord($col[5] / 100);
1260 } // CMYKa
1261 $path_style .= $this->mpdf_ref->SetFColor($col, true) . ' ';
1262 $style .= 'F';
1263 }
1264 } else if ($critere_style['fill'] != 'none' && $element != 'line') {
1265 $col = $this->mpdf_ref->ConvertColor($critere_style['fill']);
1266 if ($col) {
1267 if ($col[0] == 5) {
1268 $critere_style['fill-opacity'] = ord($col[4] / 100);
1269 } // RGBa
1270 if ($col[0] == 6) {
1271 $critere_style['fill-opacity'] = ord($col[5] / 100);
1272 } // CMYKa
1273 $path_style .= $this->mpdf_ref->SetFColor($col, true) . ' ';
1274 $style .= 'F';
1275 }
1276 }
1277 if (substr_count($critere_style['stroke'], 'url') > 0) {
1278 /*
1279 // Cannot put a gradient on a "stroke" in PDF?
1280 $id_gradient = preg_replace("/url\(#([\w_]*)\)/i","$1",$critere_style['stroke']);
1281 if ($id_gradient != $critere_style['stroke']) {
1282 if (isset($this->svg_gradient[$id_gradient])) {
1283 $fill_gradient = $this->svgGradient($this->svg_gradient[$id_gradient], $attribs, $element);
1284 if ($fill_gradient) {
1285 $path_style = "q ";
1286 $w = "W";
1287 $style .= 'D';
1288 }
1289 }
1290 }
1291 */
1292 }
1293 // Used as indirect setting for currentColor
1294 else if (strtolower($critere_style['stroke']) == 'currentcolor') {
1295 $col = $this->mpdf_ref->ConvertColor($critere_style['color']);
1296 if ($col) {
1297 if ($col[0] == 5) {
1298 $critere_style['stroke-opacity'] = ord($col[4] / 100);
1299 } // RGBa
1300 if ($col[0] == 6) {
1301 $critere_style['stroke-opacity'] = ord($col[5] / 100);
1302 } // CMYKa
1303 $path_style .= $this->mpdf_ref->SetDColor($col, true) . ' ';
1304 $style .= 'D';
1305 $lw = $this->ConvertSVGSizePixels($critere_style['stroke-width']);
1306 $path_style .= sprintf('%.3F w ', $lw * $this->kp);
1307 }
1308 } else if ($critere_style['stroke'] != 'none') {
1309 $col = $this->mpdf_ref->ConvertColor($critere_style['stroke']);
1310 if ($col) {
1311 // mPDF 5.0.051
1312 // mPDF 5.3.74
1313 if ($col[0] == 5) {
1314 $critere_style['stroke-opacity'] = ord($col[4] / 100);
1315 } // RGBa
1316 if ($col[0] == 6) {
1317 $critere_style['stroke-opacity'] = ord($col[5] / 100);
1318 } // CMYKa
1319 $path_style .= $this->mpdf_ref->SetDColor($col, true) . ' ';
1320 $style .= 'D';
1321 $lw = $this->ConvertSVGSizePixels($critere_style['stroke-width']);
1322 $path_style .= sprintf('%.3F w ', $lw * $this->kp);
1323 }
1324 }
1325
1326
1327 if ($critere_style['stroke'] != 'none') {
1328 if ($critere_style['stroke-linejoin'] == 'miter') {
1329 $path_style .= ' 0 j ';
1330 } else if ($critere_style['stroke-linejoin'] == 'round') {
1331 $path_style .= ' 1 j ';
1332 } else if ($critere_style['stroke-linejoin'] == 'bevel') {
1333 $path_style .= ' 2 j ';
1334 }
1335
1336 if ($critere_style['stroke-linecap'] == 'butt') {
1337 $path_style .= ' 0 J ';
1338 } else if ($critere_style['stroke-linecap'] == 'round') {
1339 $path_style .= ' 1 J ';
1340 } else if ($critere_style['stroke-linecap'] == 'square') {
1341 $path_style .= ' 2 J ';
1342 }
1343
1344 if (isset($critere_style['stroke-miterlimit'])) {
1345 if ($critere_style['stroke-miterlimit'] == 'none') {
1346
1347 } else if (preg_match('/^[\d.]+$/', $critere_style['stroke-miterlimit'])) {
1348 $path_style .= sprintf('%.2F M ', $critere_style['stroke-miterlimit']);
1349 }
1350 }
1351 if (isset($critere_style['stroke-dasharray'])) {
1352 $off = 0;
1353 $d = preg_split('/[ ,]/', $critere_style['stroke-dasharray']);
1354 if (count($d) == 1 && $d[0] == 0) {
1355 $path_style .= '[] 0 d ';
1356 } else {
1357 if (count($d) % 2 == 1) {
1358 $d = array_merge($d, $d);
1359 } // 5, 3, 1 => 5,3,1,5,3,1 OR 3 => 3,3
1360 $arr = '';
1361 for ($i = 0; $i < count($d); $i+=2) {
1362 $arr .= sprintf('%.3F %.3F ', $d[$i] * $this->kp, $d[$i + 1] * $this->kp);
1363 }
1364 if (isset($critere_style['stroke-dashoffset'])) {
1365 $off = $critere_style['stroke-dashoffset'] + 0;
1366 }
1367 $path_style .= sprintf('[%s] %.3F d ', $arr, $off * $this->kp);
1368 }
1369 }
1370 }
1371
1372 if ($critere_style['fill-rule'] == 'evenodd') {
1373 $fr = '*';
1374 } else {
1375 $fr = '';
1376 }
1377
1378 if (isset($critere_style['fill-opacity'])) {
1379 $opacity = 1;
1380 if ($critere_style['fill-opacity'] == 0) {
1381 $opacity = 0;
1382 } else if ($critere_style['fill-opacity'] > 1) {
1383 $opacity = 1;
1384 } else if ($critere_style['fill-opacity'] > 0) {
1385 $opacity = $critere_style['fill-opacity'];
1386 } else if ($critere_style['fill-opacity'] < 0) {
1387 $opacity = 0;
1388 }
1389 $gs = $this->mpdf_ref->AddExtGState(array('ca' => $opacity, 'BM' => '/Normal'));
1390 $this->mpdf_ref->extgstates[$gs]['fo'] = true;
1391 $path_style .= sprintf(' /GS%d gs ', $gs);
1392 }
1393
1394 if (isset($critere_style['stroke-opacity'])) {
1395 $opacity = 1;
1396 if ($critere_style['stroke-opacity'] == 0) {
1397 $opacity = 0;
1398 } else if ($critere_style['stroke-opacity'] > 1) {
1399 $opacity = 1;
1400 } else if ($critere_style['stroke-opacity'] > 0) {
1401 $opacity = $critere_style['stroke-opacity'];
1402 } else if ($critere_style['stroke-opacity'] < 0) {
1403 $opacity = 0;
1404 }
1405 $gs = $this->mpdf_ref->AddExtGState(array('CA' => $opacity, 'BM' => '/Normal'));
1406 $this->mpdf_ref->extgstates[$gs]['fo'] = true;
1407 $path_style .= sprintf(' /GS%d gs ', $gs);
1408 }
1409
1410 switch ($style) {
1411 case 'F':
1412 $op = 'f';
1413 break;
1414 case 'FD':
1415 $op = 'B';
1416 break;
1417 case 'ND':
1418 $op = 'S';
1419 break;
1420 case 'D':
1421 $op = 'S';
1422 break;
1423 default:
1424 $op = 'n';
1425 }
1426
1427 $prestyle = $path_style . ' ';
1428 $poststyle = $w . ' ' . $op . $fr . ' ' . $fill_gradient . "\n";
1429 return array($prestyle, $poststyle);
1430 }
1431
1432 // fonction retracant les <path />
1433 function svgPath($command, $arguments)
1434 {
1435 $path_cmd = '';
1436 $newsubpath = false;
1437 // mPDF 5.0.039
1438 $minl = $this->pathBBox[0];
1439 $mint = $this->pathBBox[1];
1440 $maxr = $this->pathBBox[2] + $this->pathBBox[0];
1441 $maxb = $this->pathBBox[3] + $this->pathBBox[1];
1442
1443 $start = array($this->xbase, -$this->ybase);
1444
1445 preg_match_all('/[\-^]?[\d.]+(e[\-]?[\d]+){0,1}/i', $arguments, $a, PREG_SET_ORDER);
1446
1447 // if the command is a capital letter, the coords go absolute, otherwise relative
1448 if (strtolower($command) == $command)
1449 $relative = true;
1450 else
1451 $relative = false;
1452
1453
1454 $ile_argumentow = count($a);
1455
1456 // each command may have different needs for arguments [1 to 8]
1457
1458 switch (strtolower($command)) {
1459 case 'm': // move
1460 for ($i = 0; $i < $ile_argumentow; $i+=2) {
1461 $x = $a[$i][0];
1462 $y = $a[$i + 1][0];
1463 if ($relative) {
1464 $pdfx = ($this->xbase + $x);
1465 $pdfy = ($this->ybase - $y);
1466 $this->xbase += $x;
1467 $this->ybase += -$y;
1468 } else {
1469 $pdfx = $x;
1470 $pdfy = -$y;
1471 $this->xbase = $x;
1472 $this->ybase = -$y;
1473 }
1474 $pdf_pt = $this->svg_overflow($pdfx, $pdfy);
1475 $minl = min($minl, $pdf_pt['x']);
1476 $maxr = max($maxr, $pdf_pt['x']);
1477 $mint = min($mint, -$pdf_pt['y']);
1478 $maxb = max($maxb, -$pdf_pt['y']);
1479 if ($i == 0)
1480 $path_cmd .= sprintf('%.3F %.3F m ', $pdf_pt['x'] * $this->kp, $pdf_pt['y'] * $this->kp);
1481 else
1482 $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x'] * $this->kp, $pdf_pt['y'] * $this->kp);
1483 // mPDF 4.4.003 Save start points of subpath
1484 if ($this->subPathInit) {
1485 $this->spxstart = $this->xbase;
1486 $this->spystart = $this->ybase;
1487 $this->subPathInit = false;
1488 }
1489 }
1490 break;
1491 case 'l': // a simple line
1492 for ($i = 0; $i < $ile_argumentow; $i+=2) {
1493 $x = ($a[$i][0]);
1494 $y = ($a[$i + 1][0]);
1495 if ($relative) {
1496 $pdfx = ($this->xbase + $x);
1497 $pdfy = ($this->ybase - $y);
1498 $this->xbase += $x;
1499 $this->ybase += -$y;
1500 } else {
1501 $pdfx = $x;
1502 $pdfy = -$y;
1503 $this->xbase = $x;
1504 $this->ybase = -$y;
1505 }
1506 $pdf_pt = $this->svg_overflow($pdfx, $pdfy);
1507 $minl = min($minl, $pdf_pt['x']);
1508 $maxr = max($maxr, $pdf_pt['x']);
1509 $mint = min($mint, -$pdf_pt['y']);
1510 $maxb = max($maxb, -$pdf_pt['y']);
1511 $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x'] * $this->kp, $pdf_pt['y'] * $this->kp);
1512 }
1513 break;
1514 case 'h': // a very simple horizontal line
1515 for ($i = 0; $i < $ile_argumentow; $i++) {
1516 $x = ($a[$i][0]);
1517 if ($relative) {
1518 $y = 0;
1519 $pdfx = ($this->xbase + $x);
1520 $pdfy = ($this->ybase - $y);
1521 $this->xbase += $x;
1522 $this->ybase += -$y;
1523 } else {
1524 $y = -$this->ybase;
1525 $pdfx = $x;
1526 $pdfy = -$y;
1527 $this->xbase = $x;
1528 $this->ybase = -$y;
1529 }
1530 $pdf_pt = $this->svg_overflow($pdfx, $pdfy);
1531 $minl = min($minl, $pdf_pt['x']);
1532 $maxr = max($maxr, $pdf_pt['x']);
1533 $mint = min($mint, -$pdf_pt['y']);
1534 $maxb = max($maxb, -$pdf_pt['y']);
1535 $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x'] * $this->kp, $pdf_pt['y'] * $this->kp);
1536 }
1537 break;
1538 case 'v': // the simplest line, vertical
1539 for ($i = 0; $i < $ile_argumentow; $i++) {
1540 $y = ($a[$i][0]);
1541 if ($relative) {
1542 $x = 0;
1543 $pdfx = ($this->xbase + $x);
1544 $pdfy = ($this->ybase - $y);
1545 $this->xbase += $x;
1546 $this->ybase += -$y;
1547 } else {
1548 $x = $this->xbase;
1549 $pdfx = $x;
1550 $pdfy = -$y;
1551 $this->xbase = $x;
1552 $this->ybase = -$y;
1553 }
1554 $pdf_pt = $this->svg_overflow($pdfx, $pdfy);
1555 $minl = min($minl, $pdf_pt['x']);
1556 $maxr = max($maxr, $pdf_pt['x']);
1557 $mint = min($mint, -$pdf_pt['y']);
1558 $maxb = max($maxb, -$pdf_pt['y']);
1559 $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x'] * $this->kp, $pdf_pt['y'] * $this->kp);
1560 }
1561 break;
1562 case 's': // bezier with first vertex equal first control
1563 // mPDF 4.4.003
1564 if (!($this->lastcommand == 'C' || $this->lastcommand == 'c' || $this->lastcommand == 'S' || $this->lastcommand == 's')) {
1565 $this->lastcontrolpoints = array(0, 0);
1566 }
1567 for ($i = 0; $i < $ile_argumentow; $i += 4) {
1568 $x1 = $this->lastcontrolpoints[0];
1569 $y1 = $this->lastcontrolpoints[1];
1570 $x2 = ($a[$i][0]);
1571 $y2 = ($a[$i + 1][0]);
1572 $x = ($a[$i + 2][0]);
1573 $y = ($a[$i + 3][0]);
1574 if ($relative) {
1575 $pdfx1 = ($this->xbase + $x1);
1576 $pdfy1 = ($this->ybase - $y1);
1577 $pdfx2 = ($this->xbase + $x2);
1578 $pdfy2 = ($this->ybase - $y2);
1579 $pdfx = ($this->xbase + $x);
1580 $pdfy = ($this->ybase - $y);
1581 $this->xbase += $x;
1582 $this->ybase += -$y;
1583 } else {
1584 $pdfx1 = $this->xbase + $x1;
1585 $pdfy1 = $this->ybase - $y1;
1586 $pdfx2 = $x2;
1587 $pdfy2 = -$y2;
1588 $pdfx = $x;
1589 $pdfy = -$y;
1590 $this->xbase = $x;
1591 $this->ybase = -$y;
1592 }
1593 $this->lastcontrolpoints = array(($pdfx - $pdfx2), -($pdfy - $pdfy2)); // mPDF 4.4.003 always relative
1594
1595 $pdf_pt = $this->svg_overflow($pdfx, $pdfy);
1596
1597 $curves = array($pdfx1, -$pdfy1, $pdfx2, -$pdfy2, $pdfx, -$pdfy);
1598 $bx = calc_bezier_bbox($start, $curves);
1599 $minl = min($minl, $bx[0]);
1600 $maxr = max($maxr, $bx[2]);
1601 $mint = min($mint, $bx[1]);
1602 $maxb = max($maxb, $bx[3]);
1603
1604 if (($pdf_pt['x'] != $pdfx) || ($pdf_pt['y'] != $pdfy)) {
1605 $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x'] * $this->kp, $pdf_pt['y'] * $this->kp);
1606 } else {
1607 $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);
1608 }
1609 }
1610 break;
1611 case 'c': // bezier with second vertex equal second control
1612 for ($i = 0; $i < $ile_argumentow; $i += 6) {
1613 $x1 = ($a[$i][0]);
1614 $y1 = ($a[$i + 1][0]);
1615 $x2 = ($a[$i + 2][0]);
1616 $y2 = ($a[$i + 3][0]);
1617 $x = ($a[$i + 4][0]);
1618 $y = ($a[$i + 5][0]);
1619
1620
1621 if ($relative) {
1622 $pdfx1 = ($this->xbase + $x1);
1623 $pdfy1 = ($this->ybase - $y1);
1624 $pdfx2 = ($this->xbase + $x2);
1625 $pdfy2 = ($this->ybase - $y2);
1626 $pdfx = ($this->xbase + $x);
1627 $pdfy = ($this->ybase - $y);
1628 $this->xbase += $x;
1629 $this->ybase += -$y;
1630 } else {
1631 $pdfx1 = $x1;
1632 $pdfy1 = -$y1;
1633 $pdfx2 = $x2;
1634 $pdfy2 = -$y2;
1635 $pdfx = $x;
1636 $pdfy = -$y;
1637 $this->xbase = $x;
1638 $this->ybase = -$y;
1639 }
1640 $this->lastcontrolpoints = array(($pdfx - $pdfx2), -($pdfy - $pdfy2)); // mPDF 4.4.003 always relative
1641 // $pdf_pt2 = $this->svg_overflow($pdfx2,$pdfy2);
1642 // $pdf_pt1 = $this->svg_overflow($pdfx1,$pdfy1);
1643 $pdf_pt = $this->svg_overflow($pdfx, $pdfy);
1644
1645 $curves = array($pdfx1, -$pdfy1, $pdfx2, -$pdfy2, $pdfx, -$pdfy);
1646 $bx = calc_bezier_bbox($start, $curves);
1647 $minl = min($minl, $bx[0]);
1648 $maxr = max($maxr, $bx[2]);
1649 $mint = min($mint, $bx[1]);
1650 $maxb = max($maxb, $bx[3]);
1651
1652 if (($pdf_pt['x'] != $pdfx) || ($pdf_pt['y'] != $pdfy)) {
1653 $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x'] * $this->kp, $pdf_pt['y'] * $this->kp);
1654 } else {
1655 $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);
1656 }
1657 }
1658 break;
1659
1660 case 'q': // bezier quadratic avec point de control
1661 for ($i = 0; $i < $ile_argumentow; $i += 4) {
1662 $x1 = ($a[$i][0]);
1663 $y1 = ($a[$i + 1][0]);
1664 $x = ($a[$i + 2][0]);
1665 $y = ($a[$i + 3][0]);
1666 if ($relative) {
1667 $pdfx = ($this->xbase + $x);
1668 $pdfy = ($this->ybase - $y);
1669
1670 $pdfx1 = ($this->xbase + ($x1 * 2 / 3));
1671 $pdfy1 = ($this->ybase - ($y1 * 2 / 3));
1672 // mPDF 4.4.003
1673 $pdfx2 = $pdfx1 + 1 / 3 * ($x);
1674 $pdfy2 = $pdfy1 + 1 / 3 * (-$y);
1675
1676 $this->xbase += $x;
1677 $this->ybase += -$y;
1678 } else {
1679 $pdfx = $x;
1680 $pdfy = -$y;
1681
1682 $pdfx1 = ($this->xbase + (($x1 - $this->xbase) * 2 / 3));
1683 $pdfy1 = ($this->ybase - (($y1 + $this->ybase) * 2 / 3));
1684
1685 $pdfx2 = ($x + (($x1 - $x) * 2 / 3));
1686 $pdfy2 = (-$y - (($y1 - $y) * 2 / 3));
1687
1688 // mPDF 4.4.003
1689 $pdfx2 = $pdfx1 + 1 / 3 * ($x - $this->xbase);
1690 $pdfy2 = $pdfy1 + 1 / 3 * (-$y - $this->ybase);
1691
1692 $this->xbase = $x;
1693 $this->ybase = -$y;
1694 }
1695 $this->lastcontrolpoints = array(($pdfx - $pdfx2), -($pdfy - $pdfy2)); // mPDF 4.4.003 always relative
1696
1697 $pdf_pt = $this->svg_overflow($pdfx, $pdfy);
1698
1699 $curves = array($pdfx1, -$pdfy1, $pdfx2, -$pdfy2, $pdfx, -$pdfy);
1700 $bx = calc_bezier_bbox($start, $curves);
1701 $minl = min($minl, $bx[0]);
1702 $maxr = max($maxr, $bx[2]);
1703 $mint = min($mint, $bx[1]);
1704 $maxb = max($maxb, $bx[3]);
1705
1706 if (($pdf_pt['x'] != $pdfx) || ($pdf_pt['y'] != $pdfy)) {
1707 $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x'] * $this->kp, $pdf_pt['y'] * $this->kp);
1708 } else {
1709 $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);
1710 }
1711 }
1712 break;
1713 case 't': // bezier quadratic avec point de control simetrique a lancien point de control
1714 if (!($this->lastcommand == 'Q' || $this->lastcommand == 'q' || $this->lastcommand == 'T' || $this->lastcommand == 't')) {
1715 $this->lastcontrolpoints = array(0, 0);
1716 }
1717 for ($i = 0; $i < $ile_argumentow; $i += 2) {
1718 $x = ($a[$i][0]);
1719 $y = ($a[$i + 1][0]);
1720
1721 $x1 = $this->lastcontrolpoints[0];
1722 $y1 = $this->lastcontrolpoints[1];
1723
1724 if ($relative) {
1725 $pdfx = ($this->xbase + $x);
1726 $pdfy = ($this->ybase - $y);
1727
1728 $pdfx1 = ($this->xbase + ($x1));
1729 $pdfy1 = ($this->ybase - ($y1));
1730 // mPDF 4.4.003
1731 $pdfx2 = $pdfx1 + 1 / 3 * ($x);
1732 $pdfy2 = $pdfy1 + 1 / 3 * (-$y);
1733
1734 $this->xbase += $x;
1735 $this->ybase += -$y;
1736 } else {
1737 $pdfx = $x;
1738 $pdfy = -$y;
1739
1740 $pdfx1 = ($this->xbase + ($x1));
1741 $pdfy1 = ($this->ybase - ($y1));
1742 // mPDF 4.4.003
1743 $pdfx2 = $pdfx1 + 1 / 3 * ($x - $this->xbase);
1744 $pdfy2 = $pdfy1 + 1 / 3 * (-$y - $this->ybase);
1745
1746 $this->xbase = $x;
1747 $this->ybase = -$y;
1748 }
1749
1750 $this->lastcontrolpoints = array(($pdfx - $pdfx2), -($pdfy - $pdfy2)); // mPDF 4.4.003 always relative
1751
1752 $curves = array($pdfx1, -$pdfy1, $pdfx2, -$pdfy2, $pdfx, -$pdfy);
1753 $bx = calc_bezier_bbox($start, $curves);
1754 $minl = min($minl, $bx[0]);
1755 $maxr = max($maxr, $bx[2]);
1756 $mint = min($mint, $bx[1]);
1757 $maxb = max($maxb, $bx[3]);
1758
1759 $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);
1760 }
1761
1762 break;
1763 case 'a': // Elliptical arc
1764 for ($i = 0; $i < $ile_argumentow; $i += 7) {
1765 $rx = ($a[$i][0]);
1766 $ry = ($a[$i + 1][0]);
1767 $angle = ($a[$i + 2][0]); //x-axis-rotation
1768 $largeArcFlag = ($a[$i + 3][0]);
1769 $sweepFlag = ($a[$i + 4][0]);
1770 $x2 = ($a[$i + 5][0]);
1771 $y2 = ($a[$i + 6][0]);
1772 $x1 = $this->xbase;
1773 $y1 = -$this->ybase;
1774 if ($relative) {
1775 $x2 = $this->xbase + $x2;
1776 $y2 = -$this->ybase + $y2;
1777 $this->xbase += ($a[$i + 5][0]);
1778 $this->ybase += -($a[$i + 6][0]);
1779 } else {
1780 $this->xbase = $x2;
1781 $this->ybase = -$y2;
1782 }
1783 list($pcmd, $bounds) = $this->Arcto($x1, $y1, $x2, $y2, $rx, $ry, $angle, $largeArcFlag, $sweepFlag);
1784 $minl = min($minl, $x2, min($bounds[0]));
1785 $maxr = max($maxr, $x2, max($bounds[0]));
1786 $mint = min($mint, $y2, min($bounds[1]));
1787 $maxb = max($maxb, $y2, max($bounds[1]));
1788 $path_cmd .= $pcmd;
1789 }
1790 break;
1791 case'z':
1792 $path_cmd .= 'h ';
1793 $this->subPathInit = true;
1794 $newsubpath = true;
1795 $this->xbase = $this->spxstart;
1796 $this->ybase = $this->spystart;
1797 break;
1798 default:
1799 break;
1800 }
1801
1802 if (!$newsubpath) {
1803 $this->subPathInit = false;
1804 }
1805 $this->lastcommand = $command;
1806 // mPDF 5.0.039
1807 $this->pathBBox[0] = $minl;
1808 $this->pathBBox[1] = $mint;
1809 $this->pathBBox[2] = $maxr - $this->pathBBox[0];
1810 $this->pathBBox[3] = $maxb - $this->pathBBox[1];
1811 return $path_cmd;
1812 }
1813
1814 function Arcto($x1, $y1, $x2, $y2, $rx, $ry, $angle, $largeArcFlag, $sweepFlag)
1815 {
1816
1817 $bounds = array(0 => array($x1, $x2), 1 => array($y1, $y2));
1818 // 1. Treat out-of-range parameters as described in
1819 // http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
1820 // If the endpoints (x1, y1) and (x2, y2) are identical, then this
1821 // is equivalent to omitting the elliptical arc segment entirely
1822 if ($x1 == $x2 && $y1 == $y2)
1823 return array('', $bounds); // mPD 5.0.040
1824
1825
1826 // If rX = 0 or rY = 0 then this arc is treated as a straight line
1827 // segment (a "lineto") joining the endpoints.
1828 if ($rx == 0.0 || $ry == 0.0) {
1829 // return array(Lineto(x2, y2), $bounds);
1830 }
1831
1832 // If rX or rY have negative signs, these are dropped; the absolute
1833 // value is used instead.
1834 if ($rx < 0.0)
1835 $rx = -$rx;
1836 if ($ry < 0.0)
1837 $ry = -$ry;
1838
1839 // 2. convert to center parameterization as shown in
1840 // http://www.w3.org/TR/SVG/implnote.html
1841 $sinPhi = sin(deg2rad($angle));
1842 $cosPhi = cos(deg2rad($angle));
1843
1844 $x1dash = $cosPhi * ($x1 - $x2) / 2.0 + $sinPhi * ($y1 - $y2) / 2.0;
1845 $y1dash = -$sinPhi * ($x1 - $x2) / 2.0 + $cosPhi * ($y1 - $y2) / 2.0;
1846
1847
1848 $numerator = $rx * $rx * $ry * $ry - $rx * $rx * $y1dash * $y1dash - $ry * $ry * $x1dash * $x1dash;
1849
1850 if ($numerator < 0.0) {
1851 // If rX , rY and are such that there is no solution (basically,
1852 // the ellipse is not big enough to reach from (x1, y1) to (x2,
1853 // y2)) then the ellipse is scaled up uniformly until there is
1854 // exactly one solution (until the ellipse is just big enough).
1855 // -> find factor s, such that numerator' with rx'=s*rx and
1856 // ry'=s*ry becomes 0 :
1857 $s = sqrt(1.0 - $numerator / ($rx * $rx * $ry * $ry));
1858
1859 $rx *= $s;
1860 $ry *= $s;
1861 $root = 0.0;
1862 } else {
1863 $root = ($largeArcFlag == $sweepFlag ? -1.0 : 1.0) * sqrt($numerator / ($rx * $rx * $y1dash * $y1dash + $ry * $ry * $x1dash * $x1dash));
1864 }
1865
1866 $cxdash = $root * $rx * $y1dash / $ry;
1867 $cydash = -$root * $ry * $x1dash / $rx;
1868
1869 $cx = $cosPhi * $cxdash - $sinPhi * $cydash + ($x1 + $x2) / 2.0;
1870 $cy = $sinPhi * $cxdash + $cosPhi * $cydash + ($y1 + $y2) / 2.0;
1871
1872
1873 $theta1 = $this->CalcVectorAngle(1.0, 0.0, ($x1dash - $cxdash) / $rx, ($y1dash - $cydash) / $ry);
1874 $dtheta = $this->CalcVectorAngle(($x1dash - $cxdash) / $rx, ($y1dash - $cydash) / $ry, (-$x1dash - $cxdash) / $rx, (-$y1dash - $cydash) / $ry);
1875 if (!$sweepFlag && $dtheta > 0)
1876 $dtheta -= 2.0 * M_PI;
1877 else if ($sweepFlag && $dtheta < 0)
1878 $dtheta += 2.0 * M_PI;
1879
1880 // 3. convert into cubic bezier segments <= 90deg
1881 $segments = ceil(abs($dtheta / (M_PI / 2.0)));
1882 $delta = $dtheta / $segments;
1883 $t = 8.0 / 3.0 * sin($delta / 4.0) * sin($delta / 4.0) / sin($delta / 2.0);
1884 $coords = array();
1885 for ($i = 0; $i < $segments; $i++) {
1886 $cosTheta1 = cos($theta1);
1887 $sinTheta1 = sin($theta1);
1888 $theta2 = $theta1 + $delta;
1889 $cosTheta2 = cos($theta2);
1890 $sinTheta2 = sin($theta2);
1891
1892 // a) calculate endpoint of the segment:
1893 $xe = $cosPhi * $rx * $cosTheta2 - $sinPhi * $ry * $sinTheta2 + $cx;
1894 $ye = $sinPhi * $rx * $cosTheta2 + $cosPhi * $ry * $sinTheta2 + $cy;
1895
1896 // b) calculate gradients at start/end points of segment:
1897 $dx1 = $t * ( - $cosPhi * $rx * $sinTheta1 - $sinPhi * $ry * $cosTheta1);
1898 $dy1 = $t * ( - $sinPhi * $rx * $sinTheta1 + $cosPhi * $ry * $cosTheta1);
1899
1900 $dxe = $t * ( $cosPhi * $rx * $sinTheta2 + $sinPhi * $ry * $cosTheta2);
1901 $dye = $t * ( $sinPhi * $rx * $sinTheta2 - $cosPhi * $ry * $cosTheta2);
1902
1903 // c) draw the cubic bezier:
1904 $coords[$i] = array(($x1 + $dx1), ($y1 + $dy1), ($xe + $dxe), ($ye + $dye), $xe, $ye);
1905
1906 // do next segment
1907 $theta1 = $theta2;
1908 $x1 = $xe;
1909 $y1 = $ye;
1910 }
1911 $path = ' ';
1912 foreach ($coords AS $c) {
1913 $cpx1 = $c[0];
1914 $cpy1 = $c[1];
1915 $cpx2 = $c[2];
1916 $cpy2 = $c[3];
1917 $x2 = $c[4];
1918 $y2 = $c[5];
1919 $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";
1920
1921 // mPDF 5.0.040
1922 $bounds[0][] = $c[4];
1923 $bounds[1][] = $c[5];
1924 }
1925 return array($path, $bounds); // mPD 5.0.040
1926 }
1927
1928 function CalcVectorAngle($ux, $uy, $vx, $vy)
1929 {
1930 $ta = atan2($uy, $ux);
1931 $tb = atan2($vy, $vx);
1932 if ($tb >= $ta)
1933 return ($tb - $ta);
1934 return (6.28318530718 - ($ta - $tb));
1935 }
1936
1937 function ConvertSVGSizePixels($size = 5, $maxsize = 'x')
1938 {
1939 // maxsize in pixels (user units) or 'y' or 'x'
1940 // e.g. $w = $this->ConvertSVGSizePixels($arguments['w'],$this->svg_info['w']*(25.4/$this->mpdf_ref->dpi));
1941 // usefontsize - setfalse for e.g. margins - will ignore fontsize for % values
1942 // Depends of maxsize value to make % work properly. Usually maxsize == pagewidth
1943 // For text $maxsize = Fontsize
1944 // Setting e.g. margin % will use maxsize (pagewidth) and em will use fontsize
1945
1946 if ($maxsize == 'y') {
1947 $maxsize = $this->svg_info['h'];
1948 } else if ($maxsize == 'x') {
1949 $maxsize = $this->svg_info['w'];
1950 }
1951 $maxsize *= (25.4 / $this->mpdf_ref->dpi); // convert pixels to mm
1952 $fontsize = $this->mpdf_ref->FontSize / $this->kf;
1953 //Return as pixels
1954 $size = $this->mpdf_ref->ConvertSize($size, $maxsize, $fontsize, false) * 1 / (25.4 / $this->mpdf_ref->dpi);
1955 return $size;
1956 }
1957
1958 function ConvertSVGSizePts($size = 5)
1959 {
1960 // usefontsize - setfalse for e.g. margins - will ignore fontsize for % values
1961 // Depends of maxsize value to make % work properly. Usually maxsize == pagewidth
1962 // For text $maxsize = Fontsize
1963 // Setting e.g. margin % will use maxsize (pagewidth) and em will use fontsize
1964 $maxsize = $this->mpdf_ref->FontSize;
1965 //Return as pts
1966 $size = $this->mpdf_ref->ConvertSize($size, $maxsize, false, true) * 72 / 25.4;
1967 return $size;
1968 }
1969
1970 //
1971 // fonction retracant les <rect />
1972 function svgRect($arguments)
1973 {
1974
1975 if ($arguments['h'] == 0 || $arguments['w'] == 0) {
1976 return '';
1977 }
1978
1979 $x = $this->ConvertSVGSizePixels($arguments['x'], 'x'); // mPDF 4.4.003
1980 $y = $this->ConvertSVGSizePixels($arguments['y'], 'y'); // mPDF 4.4.003
1981 $h = $this->ConvertSVGSizePixels($arguments['h'], 'y'); // mPDF 4.4.003
1982 $w = $this->ConvertSVGSizePixels($arguments['w'], 'x'); // mPDF 4.4.003
1983 $rx = $this->ConvertSVGSizePixels($arguments['rx'], 'x'); // mPDF 4.4.003
1984 $ry = $this->ConvertSVGSizePixels($arguments['ry'], 'y'); // mPDF 4.4.003
1985
1986 if ($rx > $w / 2) {
1987 $rx = $w / 2;
1988 } // mPDF 4.4.003
1989 if ($ry > $h / 2) {
1990 $ry = $h / 2;
1991 } // mPDF 4.4.003
1992
1993 if ($rx > 0 and $ry == 0) {
1994 $ry = $rx;
1995 }
1996 if ($ry > 0 and $rx == 0) {
1997 $rx = $ry;
1998 }
1999
2000 if ($rx == 0 and $ry == 0) {
2001 // trace un rectangle sans angle arrondit
2002 $path_cmd = sprintf('%.3F %.3F m ', ($x * $this->kp), -($y * $this->kp));
2003 $path_cmd .= sprintf('%.3F %.3F l ', (($x + $w) * $this->kp), -($y * $this->kp));
2004 $path_cmd .= sprintf('%.3F %.3F l ', (($x + $w) * $this->kp), -(($y + $h) * $this->kp));
2005 $path_cmd .= sprintf('%.3F %.3F l ', ($x) * $this->kp, -(($y + $h) * $this->kp));
2006 $path_cmd .= sprintf('%.3F %.3F l h ', ($x * $this->kp), -($y * $this->kp));
2007 } else {
2008 // trace un rectangle avec les arrondit
2009 // les points de controle du bezier sont deduis grace a la constante kappa
2010 $kappa = 4 * (sqrt(2) - 1) / 3;
2011
2012 $kx = $kappa * $rx;
2013 $ky = $kappa * $ry;
2014
2015 $path_cmd = sprintf('%.3F %.3F m ', ($x + $rx) * $this->kp, -$y * $this->kp);
2016 $path_cmd .= sprintf('%.3F %.3F l ', ($x + ($w - $rx)) * $this->kp, -$y * $this->kp);
2017 $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);
2018 $path_cmd .= sprintf('%.3F %.3F l ', ($x + $w) * $this->kp, (-$y + (-$h + $ry)) * $this->kp);
2019 $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);
2020
2021 $path_cmd .= sprintf('%.3F %.3F l ', ($x + $rx) * $this->kp, (-$y + (-$h)) * $this->kp);
2022 $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);
2023 $path_cmd .= sprintf('%.3F %.3F l ', $x * $this->kp, (-$y + (-$ry)) * $this->kp);
2024 $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);
2025 }
2026 return $path_cmd;
2027 }
2028
2029 //
2030 // fonction retracant les <ellipse /> et <circle />
2031 // le cercle est tracé grave a 4 bezier cubic, les poitn de controles
2032 // sont deduis grace a la constante kappa * rayon
2033 function svgEllipse($arguments)
2034 {
2035 if ($arguments['rx'] == 0 || $arguments['ry'] == 0) {
2036 return '';
2037 }
2038
2039 $kappa = 4 * (sqrt(2) - 1) / 3;
2040
2041 $cx = $this->ConvertSVGSizePixels($arguments['cx'], 'x');
2042 $cy = $this->ConvertSVGSizePixels($arguments['cy'], 'y');
2043 $rx = $this->ConvertSVGSizePixels($arguments['rx'], 'x');
2044 $ry = $this->ConvertSVGSizePixels($arguments['ry'], 'y');
2045
2046 $x1 = $cx;
2047 $y1 = -$cy + $ry;
2048
2049 $x2 = $cx + $rx;
2050 $y2 = -$cy;
2051
2052 $x3 = $cx;
2053 $y3 = -$cy - $ry;
2054
2055 $x4 = $cx - $rx;
2056 $y4 = -$cy;
2057
2058 $path_cmd = sprintf('%.3F %.3F m ', $x1 * $this->kp, $y1 * $this->kp);
2059 $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);
2060 $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);
2061 $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);
2062 $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);
2063 $path_cmd .= 'h ';
2064
2065 return $path_cmd;
2066 }
2067
2068 //
2069 // fonction retracant les <polyline /> et les <line />
2070 function svgPolyline($arguments, $ispolyline = true)
2071 {
2072 if ($ispolyline) {
2073 $xbase = $arguments[0];
2074 $ybase = - $arguments[1];
2075 } else {
2076 if ($arguments[0] == $arguments[2] && $arguments[1] == $arguments[3]) {
2077 return '';
2078 } // Zero length line
2079 $xbase = $this->ConvertSVGSizePixels($arguments[0], 'x');
2080 $ybase = - $this->ConvertSVGSizePixels($arguments[1], 'y');
2081 }
2082 $path_cmd = sprintf('%.3F %.3F m ', $xbase * $this->kp, $ybase * $this->kp);
2083 for ($i = 2; $i < count($arguments); $i += 2) {
2084 if ($ispolyline) {
2085 $tmp_x = $arguments[$i];
2086 $tmp_y = - $arguments[($i + 1)];
2087 } else {
2088 $tmp_x = $this->ConvertSVGSizePixels($arguments[$i], 'x');
2089 $tmp_y = - $this->ConvertSVGSizePixels($arguments[($i + 1)], 'y');
2090 }
2091 $path_cmd .= sprintf('%.3F %.3F l ', $tmp_x * $this->kp, $tmp_y * $this->kp);
2092 }
2093
2094 // $path_cmd .= 'h '; // ?? In error - don't close subpath here
2095 return $path_cmd;
2096 }
2097
2098 //
2099 // fonction retracant les <polygone />
2100 function svgPolygon($arguments)
2101 {
2102 $xbase = $arguments[0];
2103 $ybase = - $arguments[1];
2104 $path_cmd = sprintf('%.3F %.3F m ', $xbase * $this->kp, $ybase * $this->kp);
2105 for ($i = 2; $i < count($arguments); $i += 2) {
2106 $tmp_x = $arguments[$i];
2107 $tmp_y = - $arguments[($i + 1)];
2108
2109 $path_cmd .= sprintf('%.3F %.3F l ', $tmp_x * $this->kp, $tmp_y * $this->kp);
2110 }
2111 $path_cmd .= sprintf('%.3F %.3F l ', $xbase * $this->kp, $ybase * $this->kp);
2112 $path_cmd .= 'h ';
2113 return $path_cmd;
2114 }
2115
2116 //
2117 // write string to image
2118 function svgText()
2119 {
2120 // $tmp = count($this->txt_style)-1;
2121 $current_style = $this->txt_style[count($this->txt_style) - 1]; // mPDF 5.7.4
2122 $style = '';
2123 $op = '';
2124 $render = -1;
2125 if (isset($this->txt_data[2])) {
2126 // mPDF 6
2127 // If using SVG Font
2128 if (isset($this->svg_font[$current_style['font-family']])) {
2129 // select font
2130 $style = 'R';
2131 $style .= (isset($current_style['font-weight']) && $current_style['font-weight'] == 'bold') ? 'B' : '';
2132 $style .= (isset($current_style['font-style']) && $current_style['font-style'] == 'italic') ? 'I' : '';
2133 $style .= (isset($current_style['font-variant']) && $current_style['font-variant'] == 'small-caps') ? 'S' : '';
2134
2135 $fontsize = $current_style['font-size'] * $this->mpdf_ref->dpi / 72;
2136 if (isset($this->svg_font[$current_style['font-family']][$style])) {
2137 $svg_font = $this->svg_font[$current_style['font-family']][$style];
2138 } else if (isset($this->svg_font[$current_style['font-family']]['R'])) {
2139 $svg_font = $this->svg_font[$current_style['font-family']]['R'];
2140 }
2141
2142 if (!isset($svg_font['units-per-em']) || $svg_font['units-per-em'] < 1) {
2143 $svg_font['units-per-em'] = 1000;
2144 }
2145 $units_per_em = $svg_font['units-per-em'];
2146 $scale = $fontsize / $units_per_em;
2147 $stroke_width = $current_style['stroke-width'];
2148 $stroke_width /= $scale;
2149
2150 $opacitystr = '';
2151 $fopacity = 1;
2152 if (isset($current_style['fill-opacity'])) {
2153 if ($current_style['fill-opacity'] == 0) {
2154 $fopacity = 0;
2155 } else if ($current_style['fill-opacity'] > 1) {
2156 $fopacity = 1;
2157 } else if ($current_style['fill-opacity'] > 0) {
2158 $fopacity = $current_style['fill-opacity'];
2159 } else if ($current_style['fill-opacity'] < 0) {
2160 $fopacity = 0;
2161 }
2162 }
2163 $sopacity = 1;
2164 if (isset($current_style['stroke-opacity'])) {
2165 if ($current_style['stroke-opacity'] == 0) {
2166 $sopacity = 0;
2167 } else if ($current_style['stroke-opacity'] > 1) {
2168 $sopacity = 1;
2169 } else if ($current_style['stroke-opacity'] > 0) {
2170 $sopacity = $current_style['stroke-opacity'];
2171 } else if ($current_style['stroke-opacity'] < 0) {
2172 $sopacity = 0;
2173 }
2174 }
2175 $gs = $this->mpdf_ref->AddExtGState(array('ca' => $fopacity, 'CA' => $sopacity, 'BM' => '/Normal'));
2176 $this->mpdf_ref->extgstates[$gs]['fo'] = true;
2177 $opacitystr = sprintf(' /GS%d gs ', $gs);
2178
2179 $fillstr = '';
2180 if (isset($current_style['fill']) && $current_style['fill'] != 'none') {
2181 $col = $this->mpdf_ref->ConvertColor($current_style['fill']);
2182 $fillstr = $this->mpdf_ref->SetFColor($col, true);
2183 $render = "0"; // Fill (only)
2184 $op = 'f';
2185 }
2186 $strokestr = '';
2187 if ($stroke_width > 0 && $current_style['stroke'] != 'none') {
2188 $scol = $this->mpdf_ref->ConvertColor($current_style['stroke']);
2189 if ($scol) {
2190 $strokestr .= $this->mpdf_ref->SetDColor($scol, true) . ' ';
2191 }
2192 $linewidth = $this->ConvertSVGSizePixels($stroke_width);
2193 if ($linewidth > 0) {
2194 $strokestr .= sprintf('%.3F w 0 J 0 j ', $linewidth * $this->kp);
2195 if ($render == -1) {
2196 $render = "1";
2197 } // stroke only
2198 else {
2199 $render = "2";
2200 } // fill and stroke
2201 $op .= 'S';
2202 }
2203 }
2204 if ($render == -1) {
2205 return '';
2206 }
2207 if ($op == 'fS') {
2208 $op = 'B';
2209 }
2210
2211 $x = $this->txt_data[0]; // mPDF 5.7.4
2212 $y = $this->txt_data[1]; // mPDF 5.7.4
2213 $txt = $this->txt_data[2];
2214
2215 $txt = preg_replace('/\f/', '', $txt);
2216 $txt = preg_replace('/\r/', '', $txt);
2217 $txt = preg_replace('/\n/', ' ', $txt);
2218 $txt = preg_replace('/\t/', ' ', $txt);
2219 $txt = preg_replace("/[ ]+/u", ' ', $txt);
2220
2221 if ($this->textjuststarted) {
2222 $txt = ltrim($txt);
2223 } // mPDF 5.7.4
2224 $this->textjuststarted = false; // mPDF 5.7.4
2225
2226 $txt = $this->mpdf_ref->purify_utf8_text($txt);
2227 if ($this->mpdf_ref->text_input_as_HTML) {
2228 $txt = $this->mpdf_ref->all_entities_to_utf8($txt);
2229 }
2230
2231 $nb = mb_strlen($txt, 'UTF-8');
2232 $i = 0;
2233 $sw = 0;
2234 $subpath_cmd = '';
2235 while ($i < $nb) {
2236 //Get next character
2237 $char = mb_substr($txt, $i, 1, 'UTF-8');
2238
2239
2240 if (isset($svg_font['glyphs'][$char])) {
2241 $d = $svg_font['glyphs'][$char]['d'];
2242 if (isset($svg_font['glyphs'][$char]['horiz-adv-x'])) {
2243 $horiz_adv_x = $svg_font['glyphs'][$char]['horiz-adv-x'];
2244 } else {
2245 $horiz_adv_x = $svg_font['horiz-adv-x'];
2246 } // missing glyph width
2247 } else {
2248 $d = $svg_font['d'];
2249 $horiz_adv_x = $svg_font['horiz-adv-x']; // missing glyph width
2250 }
2251 preg_match_all('/([MZLHVCSQTAmzlhvcsqta])([eE ,\-.\d]+)*/', $d, $commands, PREG_SET_ORDER);
2252 $subpath_cmd .= sprintf('q %.4F 0 0 %.4F mPDF-AXS(%.4F) %.4F cm ', $scale, -$scale, ($x + $sw * $scale) * $this->kp, -$y * $this->kp);
2253
2254 $this->subPathInit = true;
2255 $this->pathBBox = array(999999, 999999, -999999, -999999);
2256 foreach ($commands as $cmd) {
2257 if (count($cmd) == 3 || (isset($cmd[2]) && $cmd[2] == '')) {
2258 list($tmp, $command, $arguments) = $cmd;
2259 } else {
2260 list($tmp, $command) = $cmd;
2261 $arguments = '';
2262 }
2263
2264 $subpath_cmd .= $this->svgPath($command, $arguments);
2265 }
2266 $subpath_cmd .= $op . ' Q ';
2267 if ($this->pathBBox[2] == -1999998) {
2268 $this->pathBBox[2] = 100;
2269 }
2270 if ($this->pathBBox[3] == -1999998) {
2271 $this->pathBBox[3] = 100;
2272 }
2273 if ($this->pathBBox[0] == 999999) {
2274 $this->pathBBox[0] = 0;
2275 }
2276 if ($this->pathBBox[1] == 999999) {
2277 $this->pathBBox[1] = 0;
2278 }
2279
2280
2281 $sw += $horiz_adv_x;
2282 $i++;
2283 }
2284
2285 $sw *= $scale; // convert stringwidth to units
2286 // mPDF 5.7.4
2287 $this->textlength = $sw;
2288 $this->texttotallength += $this->textlength;
2289
2290 $path_cmd = sprintf('q %s %s Tr %s %s ', $opacitystr, $render, $fillstr, $strokestr);
2291 $path_cmd .= $subpath_cmd;
2292 $path_cmd .= 'Q ';
2293
2294 unset($this->txt_data[0], $this->txt_data[1], $this->txt_data[2]);
2295 return $path_cmd;
2296 }
2297
2298 // select font
2299 $style .= ($current_style['font-weight'] == 'bold') ? 'B' : '';
2300 $style .= ($current_style['font-style'] == 'italic') ? 'I' : '';
2301 $size = $current_style['font-size'] * $this->kf;
2302
2303 $current_style['font-family'] = $this->mpdf_ref->SetFont($current_style['font-family'], $style, $size, false);
2304 $this->mpdf_ref->CurrentFont['fo'] = true;
2305
2306 $opacitystr = '';
2307 // mPDF 6
2308 $fopacity = 1;
2309 if (isset($current_style['fill-opacity'])) {
2310 if ($current_style['fill-opacity'] == 0) {
2311 $fopacity = 0;
2312 } else if ($current_style['fill-opacity'] > 1) {
2313 $fopacity = 1;
2314 } else if ($current_style['fill-opacity'] > 0) {
2315 $fopacity = $current_style['fill-opacity'];
2316 } else if ($current_style['fill-opacity'] < 0) {
2317 $fopacity = 0;
2318 }
2319 }
2320 $sopacity = 1;
2321 if (isset($current_style['stroke-opacity'])) {
2322 if ($current_style['stroke-opacity'] == 0) {
2323 $sopacity = 0;
2324 } else if ($current_style['stroke-opacity'] > 1) {
2325 $sopacity = 1;
2326 } else if ($current_style['stroke-opacity'] > 0) {
2327 $sopacity = $current_style['stroke-opacity'];
2328 } else if ($current_style['stroke-opacity'] < 0) {
2329 $sopacity = 0;
2330 }
2331 }
2332 $gs = $this->mpdf_ref->AddExtGState(array('ca' => $fopacity, 'CA' => $sopacity, 'BM' => '/Normal'));
2333 $this->mpdf_ref->extgstates[$gs]['fo'] = true;
2334 $opacitystr = sprintf(' /GS%d gs ', $gs);
2335
2336 $fillstr = '';
2337 if (isset($current_style['fill']) && $current_style['fill'] != 'none') {
2338 $col = $this->mpdf_ref->ConvertColor($current_style['fill']);
2339 $fillstr = $this->mpdf_ref->SetFColor($col, true);
2340 $render = "0"; // Fill (only)
2341 }
2342 $strokestr = '';
2343 if (isset($current_style['stroke-width']) && $current_style['stroke-width'] > 0 && $current_style['stroke'] != 'none') {
2344 $scol = $this->mpdf_ref->ConvertColor($current_style['stroke']);
2345 if ($scol) {
2346 $strokestr .= $this->mpdf_ref->SetDColor($scol, true) . ' ';
2347 }
2348 $linewidth = $this->ConvertSVGSizePixels($current_style['stroke-width']);
2349 if ($linewidth > 0) {
2350 $strokestr .= sprintf('%.3F w 1 J 1 j ', $linewidth * $this->kp);
2351 if ($render == -1) {
2352 $render = "1";
2353 } // stroke only
2354 else {
2355 $render = "2";
2356 } // fill and stroke
2357 }
2358 }
2359 if ($render == -1) {
2360 return '';
2361 }
2362
2363 $x = $this->txt_data[0]; // mPDF 5.7.4
2364 $y = $this->txt_data[1]; // mPDF 5.7.4
2365 $txt = $this->txt_data[2];
2366
2367 $txt = preg_replace('/\f/', '', $txt);
2368 $txt = preg_replace('/\r/', '', $txt);
2369 $txt = preg_replace('/\n/', ' ', $txt);
2370 $txt = preg_replace('/\t/', ' ', $txt);
2371 $txt = preg_replace("/[ ]+/u", ' ', $txt);
2372
2373 if ($this->textjuststarted) {
2374 $txt = ltrim($txt);
2375 } // mPDF 5.7.4
2376 $this->textjuststarted = false; // mPDF 5.7.4
2377
2378 $txt = $this->mpdf_ref->purify_utf8_text($txt);
2379 if ($this->mpdf_ref->text_input_as_HTML) {
2380 $txt = $this->mpdf_ref->all_entities_to_utf8($txt);
2381 }
2382
2383 if ($this->mpdf_ref->usingCoreFont) {
2384 $txt = mb_convert_encoding($txt, $this->mpdf_ref->mb_enc, 'UTF-8');
2385 }
2386 if (preg_match("/([" . $this->mpdf_ref->pregRTLchars . "])/u", $txt)) {
2387 $this->mpdf_ref->biDirectional = true;
2388 }
2389
2390 $textvar = 0;
2391 $save_OTLtags = $this->mpdf_ref->OTLtags;
2392 $this->mpdf_ref->OTLtags = array();
2393 if ($this->mpdf_ref->useKerning) {
2394 if ($this->mpdf_ref->CurrentFont['haskernGPOS']) {
2395 if (isset($this->mpdf_ref->OTLtags['Plus'])) {
2396 $this->mpdf_ref->OTLtags['Plus'] .= ' kern';
2397 } else {
2398 $this->mpdf_ref->OTLtags['Plus'] = ' kern';
2399 }
2400 } else {
2401 $textvar = ($textvar | FC_KERNING);
2402 }
2403 }
2404
2405 // Use OTL OpenType Table Layout - GSUB & GPOS
2406 if (isset($this->mpdf_ref->CurrentFont['useOTL']) && $this->mpdf_ref->CurrentFont['useOTL']) {
2407 $txt = $this->mpdf_ref->otl->applyOTL($txt, $this->mpdf_ref->CurrentFont['useOTL']);
2408 $OTLdata = $this->mpdf_ref->otl->OTLdata;
2409 }
2410 $this->mpdf_ref->OTLtags = $save_OTLtags;
2411
2412 $this->mpdf_ref->magic_reverse_dir($txt, $this->mpdf_ref->directionality, $OTLdata);
2413
2414 $this->mpdf_ref->CurrentFont['used'] = true;
2415
2416 $sw = $this->mpdf_ref->GetStringWidth($txt, true, $OTLdata, $textvar); // also adds characters to subset
2417 // mPDF 5.7.4
2418 $this->textlength = $sw * 1 / (25.4 / $this->mpdf_ref->dpi);
2419 $this->texttotallength += $this->textlength;
2420
2421 $pdfx = $x * $this->kp;
2422 $pdfy = -$y * $this->kp;
2423
2424 $aixextra = sprintf(' /F%d %.3F Tf %s %s Tr %s %s ', $this->mpdf_ref->CurrentFont['i'], $this->mpdf_ref->FontSizePt, $opacitystr, $render, $fillstr, $strokestr);
2425
2426 $path_cmd = 'q 1 0 0 1 mPDF-AXS(0.00) 0 cm '; // Align X-shift
2427 $path_cmd .= $this->mpdf_ref->Text($pdfx, $pdfy, $txt, $OTLdata, $textvar, $aixextra, 'SVG', true);
2428 $path_cmd .= " Q\n";
2429
2430 unset($this->txt_data[0], $this->txt_data[1], $this->txt_data[2]);
2431
2432 if (isset($current_style['font-size-parent'])) {
2433 $this->mpdf_ref->SetFontSize($current_style['font-size-parent']);
2434 }
2435 } else {
2436 return ' ';
2437 }
2438 // Reset font // mPDF 5.7.4
2439 $prev_style = $this->txt_style[count($this->txt_style) - 1];
2440 $style = '';
2441 $style .= ($prev_style['font-weight'] == 'bold') ? 'B' : '';
2442 $style .= ($prev_style['font-style'] == 'italic') ? 'I' : '';
2443 $size = $prev_style['font-size'] * $this->kf;
2444 $this->mpdf_ref->SetFont($prev_style['font-family'], $style, $size, false);
2445
2446 return $path_cmd;
2447 }
2448
2449 function svgDefineTxtStyle($critere_style)
2450 {
2451 // get copy of current/default txt style, and modify it with supplied attributes
2452 $tmp = count($this->txt_style) - 1;
2453 $current_style = $this->txt_style[$tmp];
2454 if (isset($critere_style['style'])) {
2455 if (preg_match('/fill:\s*rgb\((\d+),\s*(\d+),\s*(\d+)\)/', $critere_style['style'], $m)) {
2456 $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);
2457 } else {
2458 $tmp = preg_replace("/(.*)fill:\s*([a-z0-9#_()]*|none)(.*)/i", "$2", $critere_style['style']);
2459 if ($tmp && $tmp != 'inherit' && $tmp != $critere_style['style']) {
2460 $current_style['fill'] = $tmp;
2461 }
2462 }
2463
2464 // mPDF 6
2465 if (preg_match("/[^-]opacity:\s*([a-z0-9.]*|none)/i", $critere_style['style'], $m) ||
2466 preg_match("/^opacity:\s*([a-z0-9.]*|none)/i", $critere_style['style'], $m)) {
2467 $current_style['fill-opacity'] = $m[1];
2468 $current_style['stroke-opacity'] = $m[1];
2469 }
2470
2471 $tmp = preg_replace("/(.*)fill-opacity:\s*([a-z0-9.]*|none)(.*)/i", "$2", $critere_style['style']);
2472 if ($tmp && $tmp != 'inherit' && $tmp != $critere_style['style']) {
2473 $current_style['fill-opacity'] = $tmp;
2474 }
2475
2476 $tmp = preg_replace("/(.*)fill-rule:\s*([a-z0-9#]*|none)(.*)/i", "$2", $critere_style['style']);
2477 if ($tmp != $critere_style['style'] && $tmp != $critere_style['style']) {
2478 $current_style['fill-rule'] = $tmp;
2479 }
2480
2481 if (preg_match('/stroke:\s*rgb\((\d+),\s*(\d+),\s*(\d+)\)/', $critere_style['style'], $m)) {
2482 $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);
2483 } else {
2484 $tmp = preg_replace("/(.*)stroke:\s*([a-z0-9#]*|none)(.*)/i", "$2", $critere_style['style']);
2485 if ($tmp && $tmp != 'inherit' && $tmp != $critere_style['style']) {
2486 $current_style['stroke'] = $tmp;
2487 }
2488 }
2489
2490 $tmp = preg_replace("/(.*)stroke-linecap:\s*([a-z0-9#]*|none)(.*)/i", "$2", $critere_style['style']);
2491 if ($tmp && $tmp != 'inherit' && $tmp != $critere_style['style']) {
2492 $current_style['stroke-linecap'] = $tmp;
2493 }
2494
2495 $tmp = preg_replace("/(.*)stroke-linejoin:\s*([a-z0-9#]*|none)(.*)/i", "$2", $critere_style['style']);
2496 if ($tmp && $tmp != 'inherit' && $tmp != $critere_style['style']) {
2497 $current_style['stroke-linejoin'] = $tmp;
2498 }
2499
2500 $tmp = preg_replace("/(.*)stroke-miterlimit:\s*([a-z0-9#]*|none)(.*)/i", "$2", $critere_style['style']);
2501 if ($tmp && $tmp != 'inherit' && $tmp != $critere_style['style']) {
2502 $current_style['stroke-miterlimit'] = $tmp;
2503 }
2504
2505 $tmp = preg_replace("/(.*)stroke-opacity:\s*([a-z0-9.]*|none)(.*)/i", "$2", $critere_style['style']);
2506 if ($tmp && $tmp != 'inherit' && $tmp != $critere_style['style']) {
2507 $current_style['stroke-opacity'] = $tmp;
2508 }
2509
2510 $tmp = preg_replace("/(.*)stroke-width:\s*([a-z0-9.]*|none)(.*)/i", "$2", $critere_style['style']);
2511 if ($tmp && $tmp != 'inherit' && $tmp != $critere_style['style']) {
2512 $current_style['stroke-width'] = $tmp;
2513 }
2514
2515 $tmp = preg_replace("/(.*)stroke-dasharray:\s*([a-z0-9., ]*|none)(.*)/i", "$2", $critere_style['style']);
2516 if ($tmp && $tmp != 'inherit' && $tmp != $critere_style['style']) {
2517 $current_style['stroke-dasharray'] = $tmp;
2518 }
2519
2520 $tmp = preg_replace("/(.*)stroke-dashoffset:\s*([a-z0-9.]*|none)(.*)/i", "$2", $critere_style['style']);
2521 if ($tmp && $tmp != 'inherit' && $tmp != $critere_style['style']) {
2522 $current_style['stroke-dashoffset'] = $tmp;
2523 }
2524
2525 $tmp = preg_replace("/(.*)font-family:\s*([a-z0-9.\"' ,\-]*|none)(.*)/i", "$2", $critere_style['style']);
2526 if ($tmp && $tmp != 'inherit' && $tmp != $critere_style['style']) {
2527 $critere_style['font-family'] = $tmp;
2528 }
2529
2530 $tmp = preg_replace("/(.*)font-size:\s*([a-z0-9.]*|none)(.*)/i", "$2", $critere_style['style']);
2531 if ($tmp && $tmp != 'inherit' && $tmp != $critere_style['style']) {
2532 $critere_style['font-size'] = $tmp;
2533 }
2534
2535 $tmp = preg_replace("/(.*)font-weight:\s*([a-z0-9.]*|normal)(.*)/i", "$2", $critere_style['style']);
2536 if ($tmp && $tmp != 'inherit' && $tmp != $critere_style['style']) {
2537 $critere_style['font-weight'] = $tmp;
2538 }
2539
2540 $tmp = preg_replace("/(.*)font-style:\s*([a-z0-9.]*|normal)(.*)/i", "$2", $critere_style['style']);
2541 if ($tmp && $tmp != 'inherit' && $tmp != $critere_style['style']) {
2542 $critere_style['font-style'] = $tmp;
2543 }
2544
2545 $tmp = preg_replace("/(.*)font-variant:\s*([a-z0-9.]*|normal)(.*)/i", "$2", $critere_style['style']);
2546 if ($tmp && $tmp != 'inherit' && $tmp != $critere_style['style']) {
2547 $critere_style['font-variant'] = $tmp;
2548 }
2549
2550 $tmp = preg_replace("/(.*)text-anchor:\s*(start|middle|end)(.*)/i", "$2", $critere_style['style']);
2551 if ($tmp && $tmp != 'inherit' && $tmp != $critere_style['style']) {
2552 $critere_style['text-anchor'] = $tmp;
2553 }
2554 }
2555 if (isset($critere_style['font'])) {
2556
2557 // [ [ <'font-style'> || <'font-variant'> || <'font-weight'> ]?<'font-size'> [ / <'line-height'> ]? <'font-family'> ]
2558
2559 $tmp = preg_replace("/(.*)(italic|oblique)(.*)/i", "$2", $critere_style['font']);
2560 if ($tmp != $critere_style['font']) {
2561 if ($tmp == 'oblique') {
2562 $tmp = 'italic';
2563 }
2564 $current_style['font-style'] = $tmp;
2565 }
2566 $tmp = preg_replace("/(.*)(bold|bolder)(.*)/i", "$2", $critere_style['font']);
2567 if ($tmp != $critere_style['font']) {
2568 if ($tmp == 'bolder') {
2569 $tmp = 'bold';
2570 }
2571 $current_style['font-weight'] = $tmp;
2572 }
2573
2574 $tmp = preg_replace("/(.*)(small\-caps)(.*)/i", "$2", $critere_style['font']);
2575 if ($tmp != $critere_style['font']) {
2576 $current_style['font-variant'] = $tmp;
2577 }
2578
2579 // select digits not followed by percent sign nor preceeded by forward slash
2580 $tmp = preg_replace("/(.*)\b(\d+)[\b|\/](.*)/i", "$2", $critere_style['font']);
2581 if ($tmp != $critere_style['font']) {
2582 $current_style['font-size'] = $this->ConvertSVGSizePts($tmp);
2583 $this->mpdf_ref->SetFont('', '', $current_style['font-size'], false);
2584 }
2585 }
2586
2587 // mPDF 6
2588 if (isset($critere_style['opacity']) && $critere_style['opacity'] != 'inherit') {
2589 $current_style['fill-opacity'] = $critere_style['opacity'];
2590 $current_style['stroke-opacity'] = $critere_style['opacity'];
2591 }
2592 // mPDF 6
2593 if (isset($critere_style['stroke-opacity']) && $critere_style['stroke-opacity'] != 'inherit') {
2594 $current_style['stroke-opacity'] = $critere_style['stroke-opacity'];
2595 }
2596 // mPDF 6
2597 if (isset($critere_style['fill-opacity']) && $critere_style['fill-opacity'] != 'inherit') {
2598 $current_style['fill-opacity'] = $critere_style['fill-opacity'];
2599 }
2600 if (isset($critere_style['fill']) && $critere_style['fill'] != 'inherit') {
2601 $current_style['fill'] = $critere_style['fill'];
2602 }
2603 if (isset($critere_style['stroke']) && $critere_style['stroke'] != 'inherit') {
2604 $current_style['stroke'] = $critere_style['stroke'];
2605 }
2606 if (isset($critere_style['stroke-width']) && $critere_style['stroke-width'] != 'inherit') {
2607 $current_style['stroke-width'] = $critere_style['stroke-width'];
2608 }
2609
2610 if (isset($critere_style['font-style']) && $critere_style['font-style'] != 'inherit') {
2611 if (strtolower($critere_style['font-style']) == 'oblique') {
2612 $critere_style['font-style'] = 'italic';
2613 }
2614 $current_style['font-style'] = $critere_style['font-style'];
2615 }
2616
2617 if (isset($critere_style['font-weight']) && $critere_style['font-weight'] != 'inherit') {
2618 if (strtolower($critere_style['font-weight']) == 'bolder') {
2619 $critere_style['font-weight'] = 'bold';
2620 }
2621 $current_style['font-weight'] = $critere_style['font-weight'];
2622 }
2623
2624 if (isset($critere_style['font-variant']) && $critere_style['font-variant'] != 'inherit') {
2625 $current_style['font-variant'] = $critere_style['font-variant'];
2626 }
2627
2628 if (isset($critere_style['font-size']) && $critere_style['font-size'] != 'inherit') {
2629 if (strpos($critere_style['font-size'], '%') !== false) {
2630 $current_style['font-size-parent'] = $current_style['font-size'];
2631 }
2632 $current_style['font-size'] = $this->ConvertSVGSizePts($critere_style['font-size']);
2633 $this->mpdf_ref->SetFont('', '', $current_style['font-size'], false);
2634 }
2635
2636 if (isset($critere_style['font-family']) && $critere_style['font-family'] != 'inherit') {
2637 $v = $critere_style['font-family'];
2638 $aux_fontlist = explode(",", $v);
2639 $found = 0;
2640
2641 $svgfontstyle = 'R';
2642 $svgfontstyle .= (isset($current_style['font-weight']) && $current_style['font-weight'] == 'bold') ? 'B' : '';
2643 $svgfontstyle .= (isset($current_style['font-style']) && $current_style['font-style'] == 'italic') ? 'I' : '';
2644 $svgfontstyle .= (isset($current_style['font-variant']) && $current_style['font-variant'] == 'small-caps') ? 'S' : '';
2645
2646 foreach ($aux_fontlist AS $f) {
2647 $fonttype = trim($f);
2648 $fonttype = preg_replace('/["\']*(.*?)["\']*/', '\\1', $fonttype);
2649 $fonttype = preg_replace('/ /', '', $fonttype);
2650 $v = strtolower(trim($fonttype));
2651 if (isset($this->mpdf_ref->fonttrans[$v]) && $this->mpdf_ref->fonttrans[$v]) {
2652 $v = $this->mpdf_ref->fonttrans[$v];
2653 }
2654 if ((!$this->mpdf_ref->usingCoreFont && in_array($v, $this->mpdf_ref->available_unifonts)) ||
2655 ($this->mpdf_ref->usingCoreFont && in_array($v, array('courier', 'times', 'helvetica', 'arial'))) ||
2656 in_array($v, array('sjis', 'uhc', 'big5', 'gb')) || isset($this->svg_font[$v][$svgfontstyle])) { // mPDF 6
2657 $current_style['font-family'] = $v;
2658 $found = 1;
2659 break;
2660 }
2661 }
2662 if (!$found) {
2663 foreach ($aux_fontlist AS $f) {
2664 $fonttype = trim($f);
2665 $fonttype = preg_replace('/["\']*(.*?)["\']*/', '\\1', $fonttype);
2666 $fonttype = preg_replace('/ /', '', $fonttype);
2667 $v = strtolower(trim($fonttype));
2668 if (isset($this->mpdf_ref->fonttrans[$v]) && $this->mpdf_ref->fonttrans[$v]) {
2669 $v = $this->mpdf_ref->fonttrans[$v];
2670 }
2671 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) || isset($this->svg_font[$v][$svgfontstyle])) { // mPDF 6
2672 $current_style['font-family'] = $v;
2673 break;
2674 }
2675 }
2676 }
2677 }
2678 if (isset($critere_style['text-anchor']) && $critere_style['text-anchor'] != 'inherit') {
2679 $current_style['text-anchor'] = $critere_style['text-anchor'];
2680 }
2681
2682 // add current style to text style array (will remove it later after writing text to svg_string)
2683 array_push($this->txt_style, $current_style);
2684 }
2685
2686 //
2687 // fonction ajoutant un gradient
2688 function svgAddGradient($id, $array_gradient)
2689 {
2690
2691 $this->svg_gradient[$id] = $array_gradient;
2692 }
2693
2694 //
2695 // Ajoute une couleur dans le gradient correspondant
2696 //
2697 // function ecrivant dans le svgstring
2698 function svgWriteString($content)
2699 {
2700
2701 $this->svg_string .= $content;
2702 }
2703
2704 // analise le svg et renvoie aux fonctions precedente our le traitement
2705 function ImageSVG($data)
2706 {
2707 // Try to clean up the start of the file
2708 // removing DOCTYPE fails with this:
2709 /*
2710 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd"
2711 [
2712 <!ELEMENT Paragraph (#PCDATA)>
2713 ]>
2714 */
2715 //$data = preg_replace('/<!DOCTYPE.*? >/is', '', $data);
2716 //$data = preg_replace('/<\?xml.*? >/is', '', $data);
2717
2718 $data = preg_replace('/^.*?<svg([> ])/is', '<svg\\1', $data); // mPDF 5.7.4
2719
2720 $data = preg_replace('/<!--.*?-->/is', '', $data); // mPDF 5.7.4
2721 // Converts < to &lt; when not a tag
2722 $data = preg_replace('/<([^!?\/a-zA-Z_:])/i', '&lt;\\1', $data); // mPDF 5.7.4
2723
2724 if (_SVG_AUTOFONT) {
2725 $data = $this->markScriptToLang($data);
2726 }
2727
2728 $this->svg_info = array();
2729 $last_gradid = ''; // mPDF 6
2730 $last_svg_fontid = ''; // mPDF 6
2731 $last_svg_fontdefw = ''; // mPDF 6
2732 $last_svg_fontstyle = ''; // mPDF 6
2733
2734 if (preg_match('/<!ENTITY/si', $data)) {
2735 // Get User-defined entities
2736 preg_match_all('/<!ENTITY\s+([a-z]+)\s+\"(.*?)\">/si', $data, $ent);
2737 // Replace entities
2738 for ($i = 0; $i < count($ent[0]); $i++) {
2739 $data = preg_replace('/&' . preg_quote($ent[1][$i], '/') . ';/is', $ent[2][$i], $data);
2740 }
2741 }
2742
2743 if (preg_match('/xlink:href\s*=/si', $data)) {
2744 // GRADIENTS
2745 // Get links
2746 preg_match_all('/(<(linearGradient|radialgradient)[^>]*)xlink:href\s*=\s*["\']#(.*?)["\'](.*?)\/>/si', $data, $links);
2747 if (count($links[0])) {
2748 $links[5] = array();
2749 }
2750 // Delete links from data - keeping in $links
2751 for ($i = 0; $i < count($links[0]); $i++) {
2752 $links[5][$i] = 'tmpLink' . RAND(100000, 9999999);
2753 $data = preg_replace('/' . preg_quote($links[0][$i], '/') . '/is', '<MYLINKS' . $links[5][$i] . '>', $data);
2754 }
2755 // Get targets
2756 preg_match_all('/<(linearGradient|radialgradient)([^>]*)id\s*=\s*["\'](.*?)["\'](.*?)>(.*?)<\/(linearGradient|radialgradient)>/si', $data, $m);
2757 $targets = array();
2758 $stops = array();
2759 // keeping in $targets
2760 for ($i = 0; $i < count($m[0]); $i++) {
2761 $stops[$m[3][$i]] = $m[5][$i];
2762 }
2763 // Add back links this time as targets (gradients)
2764 for ($i = 0; $i < count($links[0]); $i++) {
2765 $def = $links[1][$i] . ' ' . $links[4][$i] . '>' . $stops[$links[3][$i]] . '</' . $links[2][$i] . '>';
2766 $data = preg_replace('/<MYLINKS' . $links[5][$i] . '>/is', $def, $data);
2767 }
2768
2769 // mPDF 5.7.4
2770 // <TREF>
2771 preg_match_all('/<tref ([^>]*)xlink:href\s*=\s*["\']#([^>]*?)["\']([^>]*)\/>/si', $data, $links);
2772 for ($i = 0; $i < count($links[0]); $i++) {
2773
2774 // Get the item to use from defs
2775 $insert = '';
2776 if (preg_match('/<text [^>]*id\s*=\s*["\']' . $links[2][$i] . '["\'][^>]*>(.*?)<\/text>/si', $data, $m)) {
2777 $insert = $m[1];
2778 }
2779 if ($insert) {
2780 $data = preg_replace('/' . preg_quote($links[0][$i], '/') . '/is', $insert, $data);
2781 }
2782 }
2783
2784 // mPDF 5.7.2
2785 // <USE>
2786 preg_match_all('/<use ([^>]*)xlink:href\s*=\s*["\']#([^>]*?)["\']([^>]*)\/>/si', $data, $links);
2787 for ($i = 0; $i < count($links[0]); $i++) {
2788
2789 // Get the item to use from defs
2790 $insert = '';
2791 if (preg_match('/<([a-zA-Z]*) [^>]*id\s*=\s*["\']' . $links[2][$i] . '["\'][^>]*\/>/si', $data, $m)) {
2792 $insert = $m[0];
2793 }
2794 if (!$insert && preg_match('/<([a-zA-Z]*) [^>]*id\s*=\s*["\']' . $links[2][$i] . '["\']/si', $data, $m)) {
2795
2796 if (preg_match('/<' . $m[1] . '[^>]*id\s*=\s*["\']' . $links[2][$i] . '["\'][^>]*>.*?<\/' . $m[1] . '>/si', $data, $m)) {
2797 $insert = $m[0];
2798 }
2799 }
2800
2801 if ($insert) {
2802
2803 $inners = $links[1][$i] . ' ' . $links[3][$i];
2804 // Change x,y coords to translate()
2805 if (preg_match('/y\s*=\s*["\']([^>]*?)["\']/', $inners, $m)) {
2806 $y = $m[1];
2807 } else {
2808 $y = 0;
2809 }
2810 if (preg_match('/x\s*=\s*["\']([^>]*?)["\']/', $inners, $m)) {
2811 $x = $m[1];
2812 } else {
2813 $x = 0;
2814 }
2815 if ($x || $y) {
2816 $inners = preg_replace('/(y|x)\s*=\s*["\']([^>]*?)["\']/', '', $inners);
2817 if (preg_match('/transform\s*=\s*["\']([^>]*?)["\']/', $inners, $m)) {
2818 if (preg_match('/translate\(\s*([0-9\.]+)\s*,\s*([0-9\.]+)\s*\)/', $m[1], $mm)) {
2819 $transform = $m[1]; // transform="...."
2820 $x += $mm[1];
2821 $y += $mm[2];
2822 $transform = preg_replace('/' . preg_quote($mm[0], '/') . '/', '', $transform);
2823 $transform = 'transform="' . $transform . ' translate(' . $x . ', ' . $y . ')"';
2824 $inners = preg_replace('/' . preg_quote($m[0], '/') . '/is', $transform, $inners);
2825 } else {
2826 $inners = preg_replace('/' . preg_quote($m[0], '/') . '/is', 'transform="' . $m[1] . ' translate(' . $x . ', ' . $y . ')"', $inners);
2827 }
2828 } else {
2829 $inners .= ' transform="translate(' . $x . ', ' . $y . ')"';
2830 }
2831 }
2832 }
2833 $replacement = '<g ' . $inners . '>' . $insert . '</g>';
2834 $data = preg_replace('/' . preg_quote($links[0][$i], '/') . '/is', $replacement, $data);
2835 }
2836 preg_match_all('/<use ([^>]*)xlink:href\s*=\s*["\']#([^>]*?)["\']([^>]*)>\s*<\/use>/si', $data, $links);
2837 for ($i = 0; $i < count($links[0]); $i++) {
2838
2839 // Get the item to use from defs
2840 $insert = '';
2841 if (preg_match('/<([a-zA-Z]*) [^>]*id\s*=\s*["\']' . $links[2][$i] . '["\'][^>]*\/>/si', $data, $m)) {
2842 $insert = $m[0];
2843 }
2844 if (!$insert && preg_match('/<([a-zA-Z]*) [^>]*id\s*=\s*["\']' . $links[2][$i] . '["\']/si', $data, $m)) {
2845
2846 if (preg_match('/<' . $m[1] . '[^>]*id\s*=\s*["\']' . $links[2][$i] . '["\'][^>]*>.*?<\/' . $m[1] . '>/si', $data, $m)) {
2847 $insert = $m[0];
2848 }
2849 }
2850
2851 if ($insert) {
2852
2853 $inners = $links[1][$i] . ' ' . $links[3][$i];
2854 // Change x,y coords to translate()
2855 if (preg_match('/y\s*=\s*["\']([^>]*?)["\']/', $inners, $m)) {
2856 $y = $m[1];
2857 } else {
2858 $y = 0;
2859 }
2860 if (preg_match('/x\s*=\s*["\']([^>]*?)["\']/', $inners, $m)) {
2861 $x = $m[1];
2862 } else {
2863 $x = 0;
2864 }
2865 if ($x || $y) {
2866 $inners = preg_replace('/(y|x)\s*=\s*["\']([^>]*?)["\']/', '', $inners);
2867 if (preg_match('/transform\s*=\s*["\']([^>]*?)["\']/', $inners, $m)) {
2868 if (preg_match('/translate\(\s*([0-9\.]+)\s*,\s*([0-9\.]+)\s*\)/', $m[1], $mm)) {
2869 $transform = $m[1]; // transform="...."
2870 $x += $mm[1];
2871 $y += $mm[2];
2872 $transform = preg_replace('/' . preg_quote($mm[0], '/') . '/', '', $transform);
2873 $transform = 'transform="' . $transform . ' translate(' . $x . ', ' . $y . ')"';
2874 $inners = preg_replace('/' . preg_quote($m[0], '/') . '/is', $transform, $inners);
2875 } else {
2876 $inners = preg_replace('/' . preg_quote($m[0], '/') . '/is', 'transform="' . $m[1] . ' translate(' . $x . ', ' . $y . ')"', $inners);
2877 }
2878 } else {
2879 $inners .= ' transform="translate(' . $x . ', ' . $y . ')"';
2880 }
2881 }
2882 $replacement = '<g ' . $inners . '>' . $insert . '</g>';
2883 $data = preg_replace('/' . preg_quote($links[0][$i], '/') . '/is', $replacement, $data);
2884 }
2885 }
2886 }
2887
2888 // Removes <pattern>
2889 $data = preg_replace('/<pattern.*?<\/pattern>/is', '', $data);
2890 // Removes <marker>
2891 $data = preg_replace('/<marker.*?<\/marker>/is', '', $data);
2892
2893 $this->svg_info['data'] = $data;
2894
2895 $this->svg_string = '';
2896
2897 //
2898 // chargement unique des fonctions
2899 if (!function_exists("xml_svg2pdf_start")) {
2900
2901 function xml_svg2pdf_start($parser, $name, $attribs)
2902 {
2903 //
2904 // definition
2905 global $svg_class, $last_gradid, $last_svg_fontid, $last_svg_fontdefw, $last_svg_fontstyle; // mPDF 6
2906 // mPDF 6
2907 if (strtolower($name) == 'font') {
2908 $last_svg_fontid = '';
2909 if (isset($attribs['horiz-adv-x']) && $attribs['horiz-adv-x']) {
2910 $last_svg_fontdefw = $attribs['horiz-adv-x'];
2911 }
2912 return;
2913 }
2914 // mPDF 6
2915 else if (strtolower($name) == 'font-face') {
2916 $last_svg_fontstyle = 'R';
2917 $last_svg_fontstyle .= (isset($attribs['font-weight']) && $attribs['font-weight'] == 'bold') ? 'B' : '';
2918 $last_svg_fontstyle .= (isset($attribs['font-style']) && $attribs['font-style'] == 'italic') ? 'I' : '';
2919 $last_svg_fontstyle .= (isset($attribs['font-variant']) && $attribs['font-variant'] == 'small-caps') ? 'S' : '';
2920
2921 if (isset($attribs['font-family']) && $attribs['font-family']) {
2922 $tmp_svg_font = array(
2923 'units-per-em' => (isset($attribs['units-per-em']) ? $attribs['units-per-em'] : ''),
2924 'd' => '',
2925 'glyphs' => array()
2926 );
2927 $last_svg_fontid = strtolower($attribs['font-family']);
2928 if ($last_svg_fontdefw) {
2929 $tmp_svg_font['horiz-adv-x'] = $last_svg_fontdefw;
2930 } else {
2931 $tmp_svg_font['horiz-adv-x'] = 500;
2932 }
2933 $svg_class->svg_font[$last_svg_fontid][$last_svg_fontstyle] = $tmp_svg_font;
2934 }
2935 return;
2936 }
2937 // mPDF 6
2938 else if (strtolower($name) == 'missing-glyph') {
2939 if ($last_svg_fontid && isset($attribs['horiz-adv-x'])) {
2940 $svg_class->svg_font[$last_svg_fontid][$last_svg_fontstyle]['horiz-adv-x'] = (isset($attribs['horiz-adv-x']) ? $attribs['horiz-adv-x'] : '');
2941 $svg_class->svg_font[$last_svg_fontid][$last_svg_fontstyle]['d'] = (isset($attribs['d']) ? $attribs['d'] : '');
2942 }
2943 return;
2944 }
2945 // mPDF 6
2946 else if (strtolower($name) == 'glyph') {
2947 if ($last_svg_fontid && isset($attribs['unicode'])) {
2948 $svg_class->svg_font[$last_svg_fontid][$last_svg_fontstyle]['glyphs'][$attribs['unicode']] = array(
2949 'horiz-adv-x' => (isset($attribs['horiz-adv-x']) ? $attribs['horiz-adv-x'] : $last_svg_fontdefw),
2950 'd' => (isset($attribs['d']) ? $attribs['d'] : ''),
2951 );
2952 }
2953 return;
2954 }
2955 // mPDF 5.7.2
2956 else if (strtolower($name) == 'lineargradient') {
2957 $tmp_gradient = array(
2958 'type' => 'linear',
2959 'transform' => (isset($attribs['gradientTransform']) ? $attribs['gradientTransform'] : ''),
2960 'units' => (isset($attribs['gradientUnits']) ? $attribs['gradientUnits'] : ''),
2961 'spread' => (isset($attribs['spreadMethod']) ? $attribs['spreadMethod'] : ''),
2962 'color' => array()
2963 );
2964 if (isset($attribs['x1']))
2965 $tmp_gradient['info']['x1'] = $attribs['x1'];
2966 if (isset($attribs['y1']))
2967 $tmp_gradient['info']['y1'] = $attribs['y1'];
2968 if (isset($attribs['x2']))
2969 $tmp_gradient['info']['x2'] = $attribs['x2'];
2970 if (isset($attribs['y2']))
2971 $tmp_gradient['info']['y2'] = $attribs['y2'];
2972 $last_gradid = $attribs['id'];
2973 $svg_class->svgAddGradient($attribs['id'], $tmp_gradient);
2974 return;
2975 }
2976 else if (strtolower($name) == 'radialgradient') {
2977 $tmp_gradient = array(
2978 'type' => 'radial',
2979 'transform' => (isset($attribs['gradientTransform']) ? $attribs['gradientTransform'] : ''),
2980 'units' => (isset($attribs['gradientUnits']) ? $attribs['gradientUnits'] : ''),
2981 'spread' => (isset($attribs['spreadMethod']) ? $attribs['spreadMethod'] : ''),
2982 'color' => array()
2983 );
2984 if (isset($attribs['cx']))
2985 $tmp_gradient['info']['x0'] = $attribs['cx'];
2986 if (isset($attribs['cy']))
2987 $tmp_gradient['info']['y0'] = $attribs['cy'];
2988 if (isset($attribs['fx']))
2989 $tmp_gradient['info']['x1'] = $attribs['fx'];
2990 if (isset($attribs['fy']))
2991 $tmp_gradient['info']['y1'] = $attribs['fy'];
2992 if (isset($attribs['r']))
2993 $tmp_gradient['info']['r'] = $attribs['r'];
2994 $last_gradid = $attribs['id'];
2995 $svg_class->svgAddGradient($attribs['id'], $tmp_gradient);
2996 return;
2997 }
2998 else if (strtolower($name) == 'stop') {
2999 if (!$last_gradid)
3000 return;
3001 $color = '#000000';
3002 if (isset($attribs['style']) AND preg_match('/stop-color:\s*([^;]*)/i', $attribs['style'], $m)) {
3003 $color = trim($m[1]);
3004 } else if (isset($attribs['stop-color']) && $attribs['stop-color']) {
3005 $color = $attribs['stop-color'];
3006 }
3007 $col = $svg_class->mpdf_ref->ConvertColor($color);
3008 if (!$col) {
3009 $col = $svg_class->mpdf_ref->ConvertColor('#000000');
3010 } // In case "transparent" or "inherit" returned
3011 if ($col[0] == 3 || $col[0] == 5) { // RGB
3012 $color_final = sprintf('%.3F %.3F %.3F', ord($col[1]) / 255, ord($col[2]) / 255, ord($col[3]) / 255);
3013 $svg_class->svg_gradient[$last_gradid]['colorspace'] = 'RGB';
3014 } else if ($col[0] == 4 || $col[0] == 6) { // CMYK
3015 $color_final = sprintf('%.3F %.3F %.3F %.3F', ord($col[1]) / 100, ord($col[2]) / 100, ord($col[3]) / 100, ord($col[4]) / 100);
3016 $svg_class->svg_gradient[$last_gradid]['colorspace'] = 'CMYK';
3017 } else if ($col[0] == 1) { // Grayscale
3018 $color_final = sprintf('%.3F', ord($col[1]) / 255);
3019 $svg_class->svg_gradient[$last_gradid]['colorspace'] = 'Gray';
3020 }
3021
3022 $stop_opacity = 1;
3023 if (isset($attribs['style']) AND preg_match('/stop-opacity:\s*([0-9.]*)/i', $attribs['style'], $m)) {
3024 $stop_opacity = $m[1];
3025 } else if (isset($attribs['stop-opacity'])) {
3026 $stop_opacity = $attribs['stop-opacity'];
3027 } else if ($col[0] == 5) { // RGBa
3028 $stop_opacity = ord($col[4] / 100);
3029 } else if ($col[0] == 6) { // CMYKa
3030 $stop_opacity = ord($col[5] / 100);
3031 }
3032
3033 $tmp_color = array(
3034 'color' => $color_final,
3035 'offset' => (isset($attribs['offset']) ? $attribs['offset'] : ''),
3036 'opacity' => $stop_opacity
3037 );
3038 array_push($svg_class->svg_gradient[$last_gradid]['color'], $tmp_color);
3039 return;
3040 }
3041 if ($svg_class->inDefs) {
3042 return;
3043 }
3044
3045 $svg_class->xbase = 0;
3046 $svg_class->ybase = 0;
3047 switch (strtolower($name)) {
3048
3049 // Don't output stuff inside <defs>
3050 case 'defs':
3051 $svg_class->inDefs = true;
3052 return;
3053
3054 case 'svg':
3055 $svg_class->svgOffset($attribs);
3056 break;
3057
3058 case 'path':
3059 $path = $attribs['d'];
3060 preg_match_all('/([MZLHVCSQTAmzlhvcsqta])([eE ,\-.\d]+)*/', $path, $commands, PREG_SET_ORDER);
3061 $path_cmd = '';
3062 $svg_class->subPathInit = true;
3063 $svg_class->pathBBox = array(999999, 999999, -999999, -999999);
3064 foreach ($commands as $c) {
3065 if ((isset($c) && count($c) == 3) || (isset($c[2]) && $c[2] == '')) {
3066 list($tmp, $command, $arguments) = $c;
3067 } else {
3068 list($tmp, $command) = $c;
3069 $arguments = '';
3070 }
3071
3072 $path_cmd .= $svg_class->svgPath($command, $arguments);
3073 }
3074 if ($svg_class->pathBBox[2] == -1999998) {
3075 $svg_class->pathBBox[2] = 100;
3076 }
3077 if ($svg_class->pathBBox[3] == -1999998) {
3078 $svg_class->pathBBox[3] = 100;
3079 }
3080 if ($svg_class->pathBBox[0] == 999999) {
3081 $svg_class->pathBBox[0] = 0;
3082 }
3083 if ($svg_class->pathBBox[1] == 999999) {
3084 $svg_class->pathBBox[1] = 0;
3085 }
3086 $critere_style = $attribs;
3087 unset($critere_style['d']);
3088 $path_style = $svg_class->svgDefineStyle($critere_style);
3089 break;
3090
3091 case 'rect':
3092 if (!isset($attribs['x'])) {
3093 $attribs['x'] = 0;
3094 }
3095 if (!isset($attribs['y'])) {
3096 $attribs['y'] = 0;
3097 }
3098 if (!isset($attribs['rx'])) {
3099 $attribs['rx'] = 0;
3100 }
3101 if (!isset($attribs['ry'])) {
3102 $attribs['ry'] = 0;
3103 }
3104 $arguments = array();
3105 if (isset($attribs['x']))
3106 $arguments['x'] = $attribs['x'];
3107 if (isset($attribs['y']))
3108 $arguments['y'] = $attribs['y'];
3109 if (isset($attribs['width']))
3110 $arguments['w'] = $attribs['width'];
3111 if (isset($attribs['height']))
3112 $arguments['h'] = $attribs['height'];
3113 if (isset($attribs['rx']))
3114 $arguments['rx'] = $attribs['rx'];
3115 if (isset($attribs['ry']))
3116 $arguments['ry'] = $attribs['ry'];
3117 $path_cmd = $svg_class->svgRect($arguments);
3118 $critere_style = $attribs;
3119 unset($critere_style['x'], $critere_style['y'], $critere_style['rx'], $critere_style['ry'], $critere_style['height'], $critere_style['width']);
3120 $path_style = $svg_class->svgDefineStyle($critere_style);
3121 break;
3122
3123 case 'circle':
3124 if (!isset($attribs['cx'])) {
3125 $attribs['cx'] = 0;
3126 }
3127 if (!isset($attribs['cy'])) {
3128 $attribs['cy'] = 0;
3129 }
3130 $arguments = array();
3131 if (isset($attribs['cx']))
3132 $arguments['cx'] = $attribs['cx'];
3133 if (isset($attribs['cy']))
3134 $arguments['cy'] = $attribs['cy'];
3135 if (isset($attribs['r']))
3136 $arguments['rx'] = $attribs['r'];
3137 if (isset($attribs['r']))
3138 $arguments['ry'] = $attribs['r'];
3139 $path_cmd = $svg_class->svgEllipse($arguments);
3140 $critere_style = $attribs;
3141 unset($critere_style['cx'], $critere_style['cy'], $critere_style['r']);
3142 $path_style = $svg_class->svgDefineStyle($critere_style);
3143 break;
3144
3145 case 'ellipse':
3146 if (!isset($attribs['cx'])) {
3147 $attribs['cx'] = 0;
3148 }
3149 if (!isset($attribs['cy'])) {
3150 $attribs['cy'] = 0;
3151 }
3152 $arguments = array();
3153 if (isset($attribs['cx']))
3154 $arguments['cx'] = $attribs['cx'];
3155 if (isset($attribs['cy']))
3156 $arguments['cy'] = $attribs['cy'];
3157 if (isset($attribs['rx']))
3158 $arguments['rx'] = $attribs['rx'];
3159 if (isset($attribs['ry']))
3160 $arguments['ry'] = $attribs['ry'];
3161 $path_cmd = $svg_class->svgEllipse($arguments);
3162 $critere_style = $attribs;
3163 unset($critere_style['cx'], $critere_style['cy'], $critere_style['rx'], $critere_style['ry']);
3164 $path_style = $svg_class->svgDefineStyle($critere_style);
3165 break;
3166
3167 case 'line':
3168 $arguments = array();
3169 $arguments[0] = (isset($attribs['x1']) ? $attribs['x1'] : '');
3170 $arguments[1] = (isset($attribs['y1']) ? $attribs['y1'] : '');
3171 $arguments[2] = (isset($attribs['x2']) ? $attribs['x2'] : '');
3172 $arguments[3] = (isset($attribs['y2']) ? $attribs['y2'] : '');
3173 $path_cmd = $svg_class->svgPolyline($arguments, false);
3174 $critere_style = $attribs;
3175 unset($critere_style['x1'], $critere_style['y1'], $critere_style['x2'], $critere_style['y2']);
3176 $path_style = $svg_class->svgDefineStyle($critere_style);
3177 break;
3178
3179 case 'polyline':
3180 $path = $attribs['points'];
3181 preg_match_all('/[0-9\-\.]*/', $path, $tmp, PREG_SET_ORDER);
3182 $arguments = array();
3183 for ($i = 0; $i < count($tmp); $i++) {
3184 if ($tmp[$i][0] != '') {
3185 array_push($arguments, $tmp[$i][0]);
3186 }
3187 }
3188 $path_cmd = $svg_class->svgPolyline($arguments);
3189 $critere_style = $attribs;
3190 unset($critere_style['points']);
3191 $path_style = $svg_class->svgDefineStyle($critere_style);
3192 break;
3193
3194 case 'polygon':
3195 $path = $attribs['points'];
3196 preg_match_all('/([\-]*[0-9\.]+)/', $path, $tmp);
3197 $arguments = array();
3198 for ($i = 0; $i < count($tmp[0]); $i++) {
3199 if ($tmp[0][$i] != '') {
3200 array_push($arguments, $tmp[0][$i]);
3201 }
3202 }
3203 $path_cmd = $svg_class->svgPolygon($arguments);
3204 // definition du style de la forme:
3205 $critere_style = $attribs;
3206 unset($critere_style['points']);
3207 $path_style = $svg_class->svgDefineStyle($critere_style);
3208 break;
3209
3210 // mPDF 5.7.4 Embedded image
3211 case 'image':
3212 if (isset($attribs['xlink:href']) && $attribs['xlink:href']) {
3213 $svg_class->svgImage($attribs);
3214 }
3215 break;
3216
3217
3218 case 'a':
3219 if (isset($attribs['xlink:href'])) {
3220 unset($attribs['xlink:href']); // this should be a hyperlink
3221 // not handled like a xlink:href in other elements
3222 } // then continue like a <g>
3223 case 'g':
3224 $array_style = $svg_class->svgDefineStyle($attribs);
3225 if (!empty($array_style['transformations'])) {
3226 // If in the middle of <text> element, add to textoutput, else WriteString
3227 if ($svg_class->intext) {
3228 $svg_class->textoutput .= ' q ' . $array_style['transformations'];
3229 } // mPDF 5.7.4
3230 else {
3231 $svg_class->svgWriteString(' q ' . $array_style['transformations']);
3232 }
3233 }
3234 array_push($svg_class->svg_style, $array_style);
3235
3236 $svg_class->svgDefineTxtStyle($attribs);
3237
3238 break;
3239
3240 case 'text':
3241 $svg_class->textlength = 0; // mPDF 5.7.4
3242 $svg_class->texttotallength = 0; // mPDF 5.7.4
3243 $svg_class->textoutput = ''; // mPDF 5.7.4
3244 $svg_class->textanchor = 'start'; // mPDF 5.7.4
3245 $svg_class->textXorigin = 0; // mPDF 5.7.4
3246 $svg_class->textYorigin = 0; // mPDF 5.7.4
3247
3248 $svg_class->intext = true; // mPDF 5.7.4
3249
3250 $styl = '';
3251 if (_SVG_CLASSES && isset($attribs['class']) && $attribs['class']) {
3252 $classes = preg_split('/\s+/', trim($attribs['class']));
3253 foreach ($classes AS $class) {
3254 if (isset($svg_class->mpdf_ref->cssmgr->CSS['CLASS>>' . strtoupper($class)])) {
3255 $c = $svg_class->mpdf_ref->cssmgr->CSS['CLASS>>' . strtoupper($class)];
3256 foreach ($c AS $prop => $val) {
3257 $styl .= strtolower($prop) . ':' . $val . ';';
3258 }
3259 }
3260 }
3261 }
3262
3263 if (_SVG_AUTOFONT && isset($attribs['lang']) && $attribs['lang']) {
3264 if (!$svg_class->mpdf_ref->usingCoreFont) {
3265 if ($attribs['lang'] != $svg_class->mpdf_ref->default_lang) {
3266 list ($coreSuitable, $mpdf_unifont) = GetLangOpts($attribs['lang'], $svg_class->mpdf_ref->useAdobeCJK, $svg_class->mpdf_ref->fontdata);
3267 if ($mpdf_unifont) {
3268 $styl .= 'font-family:' . $mpdf_unifont . ';';
3269 }
3270 }
3271 }
3272 }
3273
3274 if ($styl) {
3275 if (isset($attribs['style'])) {
3276 $attribs['style'] = $styl . $attribs['style'];
3277 } else {
3278 $attribs['style'] = $styl;
3279 }
3280 }
3281
3282 $array_style = $svg_class->svgDefineStyle($attribs);
3283 if (!empty($array_style['transformations'])) {
3284 $svg_class->textoutput .= ' q ' . $array_style['transformations']; // mPDF 5.7.4
3285 }
3286 array_push($svg_class->svg_style, $array_style);
3287
3288 $svg_class->txt_data = array();
3289 $x = isset($attribs['x']) ? $svg_class->ConvertSVGSizePixels($attribs['x'], 'x') : 0; // mPDF 5.7.4
3290 $y = isset($attribs['y']) ? $svg_class->ConvertSVGSizePixels($attribs['y'], 'y') : 0; // mPDF 5.7.4
3291 $x += isset($attribs['dx']) ? $svg_class->ConvertSVGSizePixels($attribs['dx'], 'x') : 0; // mPDF 5.7.4
3292 $y += isset($attribs['dy']) ? $svg_class->ConvertSVGSizePixels($attribs['dy'], 'y') : 0; // mPDF 5.7.4
3293
3294 $svg_class->txt_data[0] = $x; // mPDF 5.7.4
3295 $svg_class->txt_data[1] = $y; // mPDF 5.7.4
3296 $critere_style = $attribs;
3297 unset($critere_style['x'], $critere_style['y']);
3298 $svg_class->svgDefineTxtStyle($critere_style);
3299
3300 $svg_class->textanchor = $svg_class->txt_style[count($svg_class->txt_style) - 1]['text-anchor']; // mPDF 5.7.4
3301 $svg_class->textXorigin = $svg_class->txt_data[0]; // mPDF 5.7.4
3302 $svg_class->textYorigin = $svg_class->txt_data[1]; // mPDF 5.7.4
3303 $svg_class->textjuststarted = true; // mPDF 5.7.4
3304
3305 break;
3306
3307 // mPDF 5.7.4
3308 case 'tspan':
3309
3310 // OUTPUT CHUNK(s) UP To NOW (svgText updates $svg_class->textlength)
3311 $p_cmd = $svg_class->svgText();
3312 $svg_class->textoutput .= $p_cmd;
3313 $tmp = count($svg_class->svg_style) - 1;
3314 $current_style = $svg_class->svg_style[$tmp];
3315
3316 $styl = '';
3317 if (_SVG_CLASSES && isset($attribs['class']) && $attribs['class']) {
3318 $classes = preg_split('/\s+/', trim($attribs['class']));
3319 foreach ($classes AS $class) {
3320 if (isset($svg_class->mpdf_ref->cssmgr->CSS['CLASS>>' . strtoupper($class)])) {
3321 $c = $svg_class->mpdf_ref->cssmgr->CSS['CLASS>>' . strtoupper($class)];
3322 foreach ($c AS $prop => $val) {
3323 $styl .= strtolower($prop) . ':' . $val . ';';
3324 }
3325 }
3326 }
3327 }
3328
3329 if (_SVG_AUTOFONT && isset($attribs['lang']) && $attribs['lang']) {
3330 if (!$svg_class->mpdf_ref->usingCoreFont) {
3331 if ($attribs['lang'] != $svg_class->mpdf_ref->default_lang) {
3332 list ($coreSuitable, $mpdf_unifont) = GetLangOpts($attribs['lang'], $svg_class->mpdf_ref->useAdobeCJK, $svg_class->mpdf_ref->fontdata);
3333 if ($mpdf_unifont) {
3334 $styl .= 'font-family:' . $mpdf_unifont . ';';
3335 }
3336 }
3337 }
3338 }
3339
3340 if ($styl) {
3341 if (isset($attribs['style'])) {
3342 $attribs['style'] = $styl . $attribs['style'];
3343 } else {
3344 $attribs['style'] = $styl;
3345 }
3346 }
3347
3348 $array_style = $svg_class->svgDefineStyle($attribs);
3349
3350 $svg_class->txt_data = array();
3351
3352
3353 // If absolute position adjustment (x or y), creates new block of text for text-alignment
3354 if (isset($attribs['x']) || isset($attribs['y'])) {
3355 // If text-anchor middle|end, adjust
3356 if ($svg_class->textanchor == 'end') {
3357 $tx = -$svg_class->texttotallength;
3358 } else if ($svg_class->textanchor == 'middle') {
3359 $tx = -$svg_class->texttotallength / 2;
3360 } else {
3361 $tx = 0;
3362 }
3363 while (preg_match('/mPDF-AXS\((.*?)\)/', $svg_class->textoutput, $m)) {
3364 if ($tx) {
3365 $txk = $m[1] + ($tx * $svg_class->kp);
3366 $svg_class->textoutput = preg_replace('/mPDF-AXS\((.*?)\)/', sprintf('%.4F', $txk), $svg_class->textoutput, 1);
3367 } else {
3368 $svg_class->textoutput = preg_replace('/mPDF-AXS\((.*?)\)/', '\\1', $svg_class->textoutput, 1);
3369 }
3370 }
3371
3372 $svg_class->svgWriteString($svg_class->textoutput);
3373
3374 $svg_class->textXorigin += $svg_class->textlength;
3375 $currentX = $svg_class->textXorigin;
3376 $currentY = $svg_class->textYorigin;
3377 $svg_class->textlength = 0;
3378 $svg_class->texttotallength = 0;
3379 $svg_class->textoutput = '';
3380
3381 $x = isset($attribs['x']) ? $svg_class->ConvertSVGSizePixels($attribs['x'], 'x') : $currentX;
3382 $y = isset($attribs['y']) ? $svg_class->ConvertSVGSizePixels($attribs['y'], 'y') : $currentY;
3383
3384 $svg_class->txt_data[0] = $x;
3385 $svg_class->txt_data[1] = $y;
3386 $critere_style = $attribs;
3387 unset($critere_style['x'], $critere_style['y']);
3388 $svg_class->svgDefineTxtStyle($critere_style);
3389
3390 $svg_class->textanchor = $svg_class->txt_style[count($svg_class->txt_style) - 1]['text-anchor'];
3391 $svg_class->textXorigin = $x;
3392 $svg_class->textYorigin = $y;
3393 } else {
3394
3395 $svg_class->textXorigin += $svg_class->textlength;
3396 $currentX = $svg_class->textXorigin;
3397 $currentY = $svg_class->textYorigin;
3398
3399 $currentX += isset($attribs['dx']) ? $svg_class->ConvertSVGSizePixels($attribs['dx'], 'x') : 0;
3400 $currentY += isset($attribs['dy']) ? $svg_class->ConvertSVGSizePixels($attribs['dy'], 'y') : 0;
3401
3402 $svg_class->txt_data[0] = $currentX;
3403 $svg_class->txt_data[1] = $currentY;
3404 $critere_style = $attribs;
3405 unset($critere_style['x'], $critere_style['y']);
3406 $svg_class->svgDefineTxtStyle($critere_style);
3407 $svg_class->textXorigin = $currentX;
3408 $svg_class->textYorigin = $currentY;
3409 }
3410
3411 if (!empty($array_style['transformations'])) {
3412 $svg_class->textoutput .= ' q ' . $array_style['transformations'];
3413 }
3414 array_push($svg_class->svg_style, $array_style);
3415
3416 break;
3417 }
3418
3419 //
3420 //insertion des path et du style dans le flux de donné general.
3421 if (isset($path_cmd) && $path_cmd) {
3422 // mPDF 5.0
3423 list($prestyle, $poststyle) = $svg_class->svgStyle($path_style, $attribs, strtolower($name));
3424 if (isset($path_style['transformations']) && $path_style['transformations']) { // transformation on an element
3425 $svg_class->svgWriteString(" q " . $path_style['transformations'] . $prestyle . $path_cmd . $poststyle . " Q\n");
3426 } else {
3427 $svg_class->svgWriteString(" q " . $prestyle . $path_cmd . $poststyle . " Q\n"); // mPDF 5.7.4
3428 }
3429 }
3430 }
3431
3432 function characterData($parser, $data)
3433 {
3434 global $svg_class;
3435 if ($svg_class->inDefs) {
3436 return;
3437 } // mPDF 5.7.2
3438 if (isset($svg_class->txt_data[2])) {
3439 $svg_class->txt_data[2] .= $data;
3440 } else {
3441 $svg_class->txt_data[2] = $data;
3442 $svg_class->txt_data[0] = $svg_class->textXorigin;
3443 $svg_class->txt_data[1] = $svg_class->textYorigin;
3444 }
3445 }
3446
3447 function xml_svg2pdf_end($parser, $name)
3448 {
3449 global $svg_class;
3450 // mPDF 5.7.2
3451 // Don't output stuff inside <defs>
3452 if ($name == 'defs') {
3453 $svg_class->inDefs = false;
3454 return;
3455 }
3456 if ($svg_class->inDefs) {
3457 return;
3458 }
3459 switch ($name) {
3460
3461 case "g":
3462 case "a":
3463 if ($svg_class->intext) {
3464 $p_cmd = $svg_class->svgText();
3465 $svg_class->textoutput .= $p_cmd;
3466 }
3467
3468 $tmp = count($svg_class->svg_style) - 1;
3469 $current_style = $svg_class->svg_style[$tmp];
3470 if (!empty($current_style['transformations'])) {
3471 // If in the middle of <text> element, add to textoutput, else WriteString
3472 if ($svg_class->intext) {
3473 $svg_class->textoutput .= " Q\n";
3474 } // mPDF 5.7.4
3475 else {
3476 $svg_class->svgWriteString(" Q\n");
3477 }
3478 }
3479 array_pop($svg_class->svg_style);
3480 array_pop($svg_class->txt_style);
3481 if ($svg_class->intext) {
3482 $svg_class->textXorigin += $svg_class->textlength;
3483 $svg_class->textlength = 0;
3484 }
3485
3486 break;
3487 case 'font':
3488 $last_svg_fontdefw = '';
3489 break;
3490 case 'font-face':
3491 $last_svg_fontid = '';
3492 $last_svg_fontstyle = '';
3493 break;
3494 case 'radialgradient':
3495 case 'lineargradient':
3496 $last_gradid = '';
3497 break;
3498 case "text":
3499 $svg_class->txt_data[2] = rtrim($svg_class->txt_data[2]); // mPDF 5.7.4
3500 $path_cmd = $svg_class->svgText();
3501 $svg_class->textoutput .= $path_cmd; // mPDF 5.7.4
3502 $tmp = count($svg_class->svg_style) - 1;
3503 $current_style = $svg_class->svg_style[$tmp];
3504 if (!empty($current_style['transformations'])) {
3505 $svg_class->textoutput .= " Q\n"; // mPDF 5.7.4
3506 }
3507 array_pop($svg_class->svg_style);
3508 array_pop($svg_class->txt_style); // mPDF 5.7.4
3509 // mPDF 5.7.4
3510 // If text-anchor middle|end, adjust
3511 if ($svg_class->textanchor == 'end') {
3512 $tx = -$svg_class->texttotallength;
3513 } else if ($svg_class->textanchor == 'middle') {
3514 $tx = -$svg_class->texttotallength / 2;
3515 } else {
3516 $tx = 0;
3517 }
3518 while (preg_match('/mPDF-AXS\((.*?)\)/', $svg_class->textoutput, $m)) {
3519 if ($tx) {
3520 $txk = $m[1] + ($tx * $svg_class->kp);
3521 $svg_class->textoutput = preg_replace('/mPDF-AXS\((.*?)\)/', sprintf('%.4F', $txk), $svg_class->textoutput, 1);
3522 } else {
3523 $svg_class->textoutput = preg_replace('/mPDF-AXS\((.*?)\)/', '\\1', $svg_class->textoutput, 1);
3524 }
3525 }
3526
3527 $svg_class->svgWriteString($svg_class->textoutput);
3528 $svg_class->textlength = 0;
3529 $svg_class->texttotallength = 0;
3530 $svg_class->textoutput = '';
3531 $svg_class->intext = false; // mPDF 5.7.4
3532
3533 break;
3534 // mPDF 5.7.4
3535 case "tspan":
3536 $p_cmd = $svg_class->svgText();
3537 $svg_class->textoutput .= $p_cmd;
3538 $tmp = count($svg_class->svg_style) - 1;
3539 $current_style = $svg_class->svg_style[$tmp];
3540 if ($current_style['transformations']) {
3541 $svg_class->textoutput .= " Q\n";
3542 }
3543 array_pop($svg_class->svg_style);
3544 array_pop($svg_class->txt_style);
3545
3546 $svg_class->textXorigin += $svg_class->textlength;
3547 $svg_class->textlength = 0;
3548
3549 break;
3550 }
3551 }
3552
3553 }
3554
3555 $svg2pdf_xml = '';
3556 global $svg_class;
3557 $svg_class = $this;
3558 // Don't output stuff inside <defs>
3559 $svg_class->inDefs = false;
3560 $svg2pdf_xml_parser = xml_parser_create("utf-8");
3561 xml_parser_set_option($svg2pdf_xml_parser, XML_OPTION_CASE_FOLDING, false);
3562 xml_set_element_handler($svg2pdf_xml_parser, "xml_svg2pdf_start", "xml_svg2pdf_end");
3563 xml_set_character_data_handler($svg2pdf_xml_parser, "characterData");
3564 xml_parse($svg2pdf_xml_parser, $data);
3565 if ($this->svg_error) {
3566 return false;
3567 } else {
3568 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);
3569 }
3570 }
3571
3572 // AUTOFONT =========================
3573 function markScriptToLang($html)
3574 {
3575 if ($this->mpdf_ref->onlyCoreFonts) {
3576 return $html;
3577 }
3578 if (empty($this->script2lang)) {
3579 if (!empty($this->mpdf_ref->script2lang)) {
3580 $this->script2lang = $this->mpdf_ref->script2lang;
3581 $this->viet = $this->mpdf_ref->viet;
3582 $this->pashto = $this->mpdf_ref->pashto;
3583 $this->urdu = $this->mpdf_ref->urdu;
3584 $this->persian = $this->mpdf_ref->persian;
3585 $this->sindhi = $this->mpdf_ref->sindhi;
3586 } else {
3587 include(_MPDF_PATH . 'config_script2lang.php');
3588 }
3589 }
3590
3591 $n = '';
3592 $a = preg_split('/<(.*?)>/ms', $html, -1, PREG_SPLIT_DELIM_CAPTURE);
3593 foreach ($a as $i => $e) {
3594 if ($i % 2 == 0) {
3595 $e = strcode2utf($e);
3596 $e = $this->mpdf_ref->lesser_entity_decode($e);
3597
3598 $earr = $this->mpdf_ref->UTF8StringToArray($e, false);
3599
3600 $scriptblock = 0;
3601 $scriptblocks = array();
3602 $scriptblocks[0] = 0;
3603 $chardata = array();
3604 $subchunk = 0;
3605 $charctr = 0;
3606 foreach ($earr as $char) {
3607 $ucd_record = UCDN::get_ucd_record($char);
3608 $sbl = $ucd_record[6];
3609
3610 if ($sbl && $sbl != 40 && $sbl != 102) {
3611 if ($scriptblock == 0) {
3612 $scriptblock = $sbl;
3613 $scriptblocks[$subchunk] = $scriptblock;
3614 } else if ($scriptblock > 0 && $scriptblock != $sbl) {
3615 // NEW (non-common) Script encountered in this chunk.
3616 // Start a new subchunk
3617 $subchunk++;
3618 $scriptblock = $sbl;
3619 $charctr = 0;
3620 $scriptblocks[$subchunk] = $scriptblock;
3621 }
3622 }
3623
3624 $chardata[$subchunk][$charctr]['script'] = $sbl;
3625 $chardata[$subchunk][$charctr]['uni'] = $char;
3626 $charctr++;
3627 }
3628
3629 // If scriptblock[x] = common & non-baseScript
3630 // and scriptblock[x+1] = baseScript
3631 // Move common script from end of x to start of x+1
3632 for ($sch = 0; $sch < $subchunk; $sch++) {
3633 if ($scriptblocks[$sch] > 0 && $scriptblocks[$sch] != $this->mpdf_ref->baseScript && $scriptblocks[$sch + 1] == $this->mpdf_ref->baseScript) {
3634 $end = count($chardata[$sch]) - 1;
3635 while ($chardata[$sch][$end]['script'] == 0 && $end > 1) { // common script
3636 $tmp = array_pop($chardata[$sch]);
3637 array_unshift($chardata[$sch + 1], $tmp);
3638 $end--;
3639 }
3640 }
3641 }
3642
3643 $o = '';
3644 for ($sch = 0; $sch <= $subchunk; $sch++) {
3645 if (isset($chardata[$sch])) {
3646 $s = '';
3647 for ($j = 0; $j < count($chardata[$sch]); $j++) {
3648 $s.=code2utf($chardata[$sch][$j]['uni']);
3649 }
3650 // ZZZ99 Undo lesser_entity_decode as above - but only for <>&
3651 $s = str_replace("&", "&amp;", $s);
3652 $s = str_replace("<", "&lt;", $s);
3653 $s = str_replace(">", "&gt;", $s);
3654
3655 if (substr($a[$i - 1], 0, 5) != '<text' && substr($a[$i - 1], 0, 5) != '<tspa') {
3656 continue;
3657 } // <tspan> or <text> only
3658
3659 $lang = '';
3660 // Check Vietnamese if Latin script - even if Basescript
3661 if ($scriptblocks[$sch] == UCDN::SCRIPT_LATIN && $this->mpdf_ref->autoVietnamese && preg_match("/([" . $this->viet . "])/u", $s)) {
3662 $lang = "vi";
3663 }
3664 // Check Arabic for different languages if Arabic script - even if Basescript
3665 else if ($scriptblocks[$sch] == UCDN::SCRIPT_ARABIC && $this->mpdf_ref->autoArabic) {
3666 if (preg_match("/[" . $this->sindhi . "]/u", $s)) {
3667 $lang = "sd";
3668 } else if (preg_match("/[" . $this->urdu . "]/u", $s)) {
3669 $lang = "ur";
3670 } else if (preg_match("/[" . $this->pashto . "]/u", $s)) {
3671 $lang = "ps";
3672 } else if (preg_match("/[" . $this->persian . "]/u", $s)) {
3673 $lang = "fa";
3674 } else if ($this->mpdf_ref->baseScript != UCDN::SCRIPT_ARABIC && isset($this->script2lang[$scriptblocks[$sch]])) {
3675 $lang = "'.$this->script2lang[$scriptblocks[$sch]].'";
3676 }
3677 }
3678 // Identify Script block if not Basescript, and mark up as language
3679 else if ($scriptblocks[$sch] > 0 && $scriptblocks[$sch] != $this->mpdf_ref->baseScript && isset($this->script2lang[$scriptblocks[$sch]])) {
3680 $lang = $this->script2lang[$scriptblocks[$sch]];
3681 }
3682 if ($lang) {
3683 $o .= '<tspan lang="' . $lang . '">' . $s . '</tspan>';
3684 } else {
3685 $o .= $s;
3686 }
3687 }
3688 }
3689
3690 $a[$i] = $o;
3691 } else {
3692 $a[$i] = '<' . $e . '>';
3693 }
3694 }
3695 $n = implode('', $a);
3696 return $n;
3697 }
3698
3699 }
3700
3701 // END OF CLASS
3702 // END OF CLASS
3703 // END OF CLASS
3704
3705
3706 function calc_bezier_bbox($start, $c)
3707 {
3708 $P0 = array($start[0], $start[1]);
3709 $P1 = array($c[0], $c[1]);
3710 $P2 = array($c[2], $c[3]);
3711 $P3 = array($c[4], $c[5]);
3712 $bounds = array();
3713 $bounds[0][] = $P0[0];
3714 $bounds[1][] = $P0[1];
3715 $bounds[0][] = $P3[0];
3716 $bounds[1][] = $P3[1];
3717 for ($i = 0; $i <= 1; $i++) {
3718 $b = 6 * $P0[$i] - 12 * $P1[$i] + 6 * $P2[$i];
3719 $a = -3 * $P0[$i] + 9 * $P1[$i] - 9 * $P2[$i] + 3 * $P3[$i];
3720 $c = 3 * $P1[$i] - 3 * $P0[$i];
3721 if ($a == 0) {
3722 if ($b == 0) {
3723 continue;
3724 }
3725 $t = -$c / $b;
3726 if ($t > 0 && $t < 1) {
3727 $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]);
3728 }
3729 continue;
3730 }
3731 $b2ac = pow($b, 2) - 4 * $c * $a;
3732 if ($b2ac < 0) {
3733 continue;
3734 }
3735 $t1 = (-$b + sqrt($b2ac)) / (2 * $a);
3736 if ($t1 > 0 && $t1 < 1) {
3737 $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]);
3738 }
3739 $t2 = (-$b - sqrt($b2ac)) / (2 * $a);
3740 if ($t2 > 0 && $t2 < 1) {
3741 $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]);
3742 }
3743 }
3744 $x = min($bounds[0]);
3745 $x2 = max($bounds[0]);
3746 $y = min($bounds[1]);
3747 $y2 = max($bounds[1]);
3748 return array($x, $y, $x2, $y2);
3749 }
3750
3751 function _testIntersectCircle($cx, $cy, $cr)
3752 {
3753 // Tests whether a circle fully encloses a rectangle 0,0,1,1
3754 // to see if any further radial gradients need adding (SVG)
3755 // If centre of circle is inside 0,0,1,1 square
3756 if ($cx >= 0 && $cx <= 1 && $cy >= 0 && $cy <= 1) {
3757 $maxd = 1.5;
3758 }
3759 // distance to four corners
3760 else {
3761 $d1 = sqrt(pow(($cy - 0), 2) + pow(($cx - 0), 2));
3762 $d2 = sqrt(pow(($cy - 1), 2) + pow(($cx - 0), 2));
3763 $d3 = sqrt(pow(($cy - 0), 2) + pow(($cx - 1), 2));
3764 $d4 = sqrt(pow(($cy - 1), 2) + pow(($cx - 1), 2));
3765 $maxd = max($d1, $d2, $d3, $d4);
3766 }
3767 if ($cr < $maxd) {
3768 return true;
3769 } else {
3770 return false;
3771 }
3772 }
3773
3774 function _testIntersect($x1, $y1, $x2, $y2, $x3, $y3, $x4, $y4)
3775 {
3776 // Tests whether line (x1, y1) and (x2, y2) [a gradient axis (perpendicular)]
3777 // intersects with a specific line segment (x3, y3) and (x4, y4)
3778 $a1 = $y2 - $y1;
3779 $b1 = $x1 - $x2;
3780 $c1 = $a1 * $x1 + $b1 * $y1;
3781 $a2 = $y4 - $y3;
3782 $b2 = $x3 - $x4;
3783 $c2 = $a2 * $x3 + $b2 * $y3;
3784 $det = $a1 * $b2 - $a2 * $b1;
3785 if ($det == 0) { //Lines are parallel
3786 return false;
3787 } else {
3788 $x = ($b2 * $c1 - $b1 * $c2) / $det;
3789 $y = ($a1 * $c2 - $a2 * $c1) / $det;
3790 if ($x >= $x3 && $x <= $x4 && $y >= $y3 && $y <= $y4) {
3791 return true;
3792 }
3793 }
3794 return false;
3795 }
3796