]>
git.immae.eu Git - github/wallabag/wallabag.git/blob - inc/3rdparty/libraries/mpdf/classes/svg.php
2 // svg class modified for mPDF version 4.4.003 by Ian Back: based on -
4 // sylvain briand (syb@godisaduck.com), modified by rick trevino (rtrevino1@yahoo.com)
5 // http://www.godisaduck.com/svg2pdf_with_fpdf
6 // http://rhodopsin.blogspot.com
8 // cette class etendue est open source, toute modification devra cependant etre repertoriée~
11 // NB UNITS - Works in pixels as main units - converting to PDF units when outputing to PDF string
12 // and on returning size
16 var $svg_gradient; // array - contient les infos sur les gradient fill du svg classé par id du svg
17 var $svg_shadinglist; // array - contient les ids des objet shading
18 var $svg_info; // array contenant les infos du svg voulue par l'utilisateur
19 var $svg_attribs; // array - holds all attributes of root <svg> tag
20 var $svg_style; // array contenant les style de groupes du svg
21 var $svg_string; // String contenant le tracage du svg en lui même.
22 var $txt_data; // array - holds string info to write txt to image
23 var $txt_style; // array - current text style
25 var $xbase; // mPDF 4.4.003
26 var $ybase; // mPDF 4.4.003
27 var $svg_error; // mPDF 4.4.003
28 var $subPathInit; // mPDF 4.4.003
29 var $spxstart; // mPDF 4.4.003
30 var $spystart; // mPDF 4.4.003
31 var $kp; // mPDF 4.4.003 convert pixels to PDF units
32 var $pathBBox; // mPDF 5.0.039
35 $this->svg_gradient
= array();
36 $this->svg_shadinglist
= array();
37 $this->txt_data
= array();
38 $this->svg_string
= '';
39 $this->svg_info
= array();
40 $this->svg_attribs
= array();
43 $this->svg_error
= false;
44 $this->subPathInit
= false; // mPDF 4.4.003
45 $this->dashesUsed
= false; // mPDF 5.0
46 $this->mpdf_ref
=& $mpdf;
48 $this->kp
= 72 / $mpdf->img_dpi
; // mPDF 4.4.003 constant To convert pixels to pts/PDF units
49 $this->kf
= 1; // mPDF 5.0.039 constant To convert font size if re-mapped
50 $this->pathBBox
= array(); // mPDF 5.0.039
52 $this->svg_style
= array(
54 'fill' => 'black', // mPDF 4.4.008
55 'fill-opacity' => 1, // remplissage opaque par defaut
56 'fill-rule' => 'nonzero', // mode de remplissage par defaut
57 'stroke' => 'none', // pas de trait par defaut
58 'stroke-linecap' => 'butt', // style de langle par defaut
59 'stroke-linejoin' => 'miter', //
60 'stroke-miterlimit' => 4, // limite de langle par defaut
61 'stroke-opacity' => 1, // trait opaque par defaut
62 'stroke-width' => 1, // mPDF 4.4.011
63 'stroke-dasharray' => 0, // mPDF 4.4.003
64 'stroke-dashoffset' => 0, // mPDF 4.4.003
65 'color' => '' // mPDF 4.4.005
69 $this->txt_style
= array(
71 'fill' => 'black', // pas de remplissage par defaut
72 'font-family' => $mpdf->default_font
,
73 'font-size' => $mpdf->default_font_size
, // ****** this is pts
74 'font-weight' => 'normal', // normal | bold
75 'font-style' => 'normal', // italic | normal
76 'text-anchor' => 'start', // alignment: start, middle, end
78 'fill-opacity' => 1, // remplissage opaque par defaut
79 'fill-rule' => 'nonzero', // mode de remplissage par defaut
80 'stroke' => 'none', // pas de trait par defaut
81 'stroke-opacity' => 1, // trait opaque par defaut
82 'stroke-width' => 1, // mPDF 4.4.011
83 'color' => '' // mPDF 4.4.005
91 function svgGradient($gradient_info, $attribs, $element){
92 $n = count($this->mpdf_ref
->gradients
)+
1;
94 // Get bounding dimensions of element
99 if ($element=='rect') {
100 $w = $attribs['width'];
101 $h = $attribs['height'];
102 $x_offset = $attribs['x'];
103 $y_offset = $attribs['y'];
105 else if ($element=='ellipse') {
106 $w = $attribs['rx']*2;
107 $h = $attribs['ry']*2;
108 $x_offset = $attribs['cx']-$attribs['rx'];
109 $y_offset = $attribs['cy']-$attribs['ry'];
111 else if ($element=='circle') {
112 $w = $attribs['r']*2;
113 $h = $attribs['r']*2;
114 $x_offset = $attribs['cx']-$attribs['r'];
115 $y_offset = $attribs['cy']-$attribs['r'];
117 else if ($element=='polygon') {
118 $pts = preg_split('/[ ,]+/', trim($attribs['points']));
121 for ($i=0;$i<count($pts); $i++
) {
122 if ($i %
2 == 0) { // x values
123 $minl = min($minl,$pts[$i]);
124 $maxr = max($maxr,$pts[$i]);
127 $mint = min($mint,$pts[$i]);
128 $maxb = max($maxb,$pts[$i]);
136 else if ($element=='path') {
138 if (is_array($this->pathBBox
) && $this->pathBBox
[2]>0) {
139 $w = $this->pathBBox
[2];
140 $h = $this->pathBBox
[3];
141 $x_offset = $this->pathBBox
[0];
142 $y_offset = $this->pathBBox
[1];
145 preg_match_all('/([a-z]|[A-Z])([ ,\-.\d]+)*/', $attribs['d'], $commands, PREG_SET_ORDER
);
148 foreach($commands as $c){
150 list($tmp, $cmd, $arg) = $c;
151 if ($cmd=='M' || $cmd=='L' || $cmd=='C' || $cmd=='S' || $cmd=='Q' || $cmd=='T') {
152 $pts = preg_split('/[ ,]+/', trim($arg));
153 for ($i=0;$i<count($pts); $i++
) {
154 if ($i %
2 == 0) { // x values
155 $minl = min($minl,$pts[$i]);
156 $maxr = max($maxr,$pts[$i]);
159 $mint = min($mint,$pts[$i]);
160 $maxb = max($maxb,$pts[$i]);
164 if ($cmd=='H') { // sets new x
165 $minl = min($minl,$arg);
166 $maxr = max($maxr,$arg);
168 if ($cmd=='V') { // sets new y
169 $mint = min($mint,$arg);
170 $maxb = max($maxb,$arg);
180 if (!$w || $w==-999999) { $w
= 100; }
181 if (!$h || $h==-999999) { $h
= 100; }
182 if ($x_offset==999999) { $x_offset
= 0; }
183 if ($y_offset==999999) { $y_offset
= 0; }
187 $transformations = '';
188 if (isset($gradient_info['transform'])){
189 preg_match_all('/(matrix|translate|scale|rotate|skewX|skewY)\((.*?)\)/is',$gradient_info['transform'],$m);
191 for($i=0; $i<count($m[0]); $i++
) {
192 $c = strtolower($m[1][$i]);
193 $v = trim($m[2][$i]);
194 $vv = preg_split('/[ ,]+/',$v);
195 if ($c=='matrix' && count($vv)==6) {
197 // Note angle of rotation is reversed (from SVG to PDF), so vv[1] and vv[2] are negated
198 // cf svgDefineStyle()
199 $transformations .= sprintf(' %.3F %.3F %.3F %.3F %.3F %.3F cm ', $vv[0], -$vv[1], -$vv[2], $vv[3], $vv[4]*$this->kp
, -$vv[5]*$this->kp
);
201 else if ($c=='translate' && count($vv)) {
203 if (count($vv)==2) { $t_y
= -$vv
[1]; }
206 $transformations .= sprintf(' 1 0 0 1 %.3F %.3F cm ', $tm[4]*$this->kp
, $tm[5]*$this->kp
);
208 else if ($c=='scale' && count($vv)) {
209 if (count($vv)==2) { $s_y
= $vv
[1]; }
210 else { $s_y
= $vv
[0]; }
213 $transformations .= sprintf(' %.3F 0 0 %.3F 0 0 cm ', $tm[0], $tm[3]);
215 else if ($c=='rotate' && count($vv)) {
216 $tm[0] = cos(deg2rad(-$vv[0]));
217 $tm[1] = sin(deg2rad(-$vv[0]));
221 $transformations .= sprintf(' 1 0 0 1 %.3F %.3F cm ', $vv[1]*$this->kp
, -$vv[2]*$this->kp
);
223 $transformations .= sprintf(' %.3F %.3F %.3F %.3F 0 0 cm ', $tm[0], $tm[1], $tm[2], $tm[3]);
225 $transformations .= sprintf(' 1 0 0 1 %.3F %.3F cm ', -$vv[1]*$this->kp
, $vv[2]*$this->kp
);
228 else if ($c=='skewx' && count($vv)) {
229 $tm[2] = tan(deg2rad(-$vv[0]));
230 $transformations .= sprintf(' 1 0 %.3F 1 0 0 cm ', $tm[2]);
232 else if ($c=='skewy' && count($vv)) {
233 $tm[1] = tan(deg2rad(-$vv[0]));
234 $transformations .= sprintf(' 1 %.3F 0 1 0 0 cm ', $tm[1]);
245 if (isset($gradient_info['units']) && strtolower($gradient_info['units'])=='userspaceonuse') {
246 if ($transformations) { $
return .= $transformations
; }
249 $spread = 'P'; // pad
250 if (isset($gradient_info['spread'])) {
251 if (strtolower($gradient_info['spread'])=='reflect') { $spread
= 'F'; } // reflect
252 else if (strtolower($gradient_info['spread'])=='repeat') { $spread
= 'R'; } // repeat
256 for ($i=0; $i<(count($gradient_info['color'])); $i++
) {
257 if (stristr($gradient_info['color'][$i]['offset'], '%')!== false) { $gradient_info
['color'][$i
]['offset'] = ($gradient_info
['color'][$i
]['offset']+
0)/100; }
258 if (stristr($gradient_info['color'][($i+
1)]['offset'], '%')!== false) { $gradient_info
['color'][($i+
1)]['offset'] = ($gradient_info
['color'][($i+
1)]['offset']+
0)/100; }
259 if ($gradient_info['color'][$i]['offset']<0) { $gradient_info
['color'][$i
]['offset'] = 0; }
260 if ($gradient_info['color'][$i]['offset']>1) { $gradient_info
['color'][$i
]['offset'] = 1; }
262 if ($gradient_info['color'][$i]['offset']<$gradient_info['color'][($i-1)]['offset']) {
263 $gradient_info['color'][$i]['offset']=$gradient_info['color'][($i-1)]['offset'];
268 if ($gradient_info['color'][0]['offset']>0) {
269 array_unshift($gradient_info['color'], $gradient_info['color'][0]);
270 $gradient_info['color'][0]['offset'] = 0;
272 $ns = count($gradient_info['color']);
273 if ($gradient_info['color'][($ns-1)]['offset']<1) {
274 $gradient_info['color'][] = $gradient_info['color'][($ns-1)];
275 $gradient_info['color'][($ns)]['offset'] = 1;
277 $ns = count($gradient_info['color']);
282 if ($gradient_info['type'] == 'linear'){
284 if (isset($gradient_info['units']) && strtolower($gradient_info['units'])=='userspaceonuse') {
285 if (isset($gradient_info['info']['x1'])) { $gradient_info
['info']['x1'] = ($gradient_info
['info']['x1']-$x_offset
) / $w
; }
286 if (isset($gradient_info['info']['y1'])) { $gradient_info
['info']['y1'] = ($gradient_info
['info']['y1']-$y_offset
) / $h
; }
287 if (isset($gradient_info['info']['x2'])) { $gradient_info
['info']['x2'] = ($gradient_info
['info']['x2']-$x_offset
) / $w
; }
288 if (isset($gradient_info['info']['y2'])) { $gradient_info
['info']['y2'] = ($gradient_info
['info']['y2']-$y_offset
) / $h
; }
290 if (isset($gradient_info['info']['x1'])) { $x1
= $gradient_info
['info']['x1']; }
292 if (isset($gradient_info['info']['y1'])) { $y1
= $gradient_info
['info']['y1']; }
294 if (isset($gradient_info['info']['x2'])) { $x2
= $gradient_info
['info']['x2']; }
296 if (isset($gradient_info['info']['y2'])) { $y2
= $gradient_info
['info']['y2']; }
299 if (stristr($x1, '%')!== false) { $x1
= ($x1+
0)/100; }
300 if (stristr($x2, '%')!== false) { $x2
= ($x2+
0)/100; }
301 if (stristr($y1, '%')!== false) { $y1
= ($y1+
0)/100; }
302 if (stristr($y2, '%')!== false) { $y2
= ($y2+
0)/100; }
311 if (isset($gradient_info['units']) && strtolower($gradient_info['units'])=='userspaceonuse') {
312 $angle = rad2deg(atan2(($gradient_info['info']['y2']-$gradient_info['info']['y1']), ($gradient_info['info']['x2']-$gradient_info['info']['x1'])));
313 if ($angle < 0) { $angle +
= 360; }
314 else if ($angle > 360) { $angle
-= 360; }
315 if ($angle!=0 && $angle!=360 && $angle!=90 && $angle!=180 && $angle!=270) {
319 $usew = $useh = $bboxw;
324 $usew = $useh = $bboxh;
329 $d = -$useh; // height
330 $e = $usex; // x- offset
331 $f = -$usey; // -y-offset
333 $return .= sprintf('%.3F 0 0 %.3F %.3F %.3F cm ', $a*$this->kp
, $d*$this->kp
, $e*$this->kp
, $f*$this->kp
);
336 if (isset($gradient_info['units']) && strtolower($gradient_info['units'])=='objectboundingbox') {
337 if ($transformations) { $
return .= $transformations
; }
344 if ($spread=='R' || $spread=='F') { // Repeat / Reflect
346 for($i=0;$i<$ns;$i++
) {
347 $offs[$i] = $gradient_info['color'][$i]['offset'];
353 for($i=0;$i<$ns;$i++
) {
354 if ($spread=='F' && ($gp %
2) == 1) { // Reflect
355 $gradient_info['color'][(($ns*$gp)+
$i)] = $gradient_info['color'][(($ns*($gp-1))+
($ns-$i-1))];
356 $tmp = $gp+
(1-$offs[($ns-$i-1)]) ;
357 $gradient_info['color'][(($ns*$gp)+
$i)]['offset'] = $tmp;
360 $gradient_info['color'][(($ns*$gp)+
$i)] = $gradient_info['color'][$i];
361 $tmp = $gp+
$offs[$i] ;
362 $gradient_info['color'][(($ns*$gp)+
$i)]['offset'] = $tmp;
364 // IF STILL INSIDE BOX OR STILL VALID
365 // Point on axis to test
366 $px1 = $x1 +
($x2-$x1)*$tmp;
367 $py1 = $y1 +
($y2-$y1)*$tmp;
368 // Get perpendicular axis
369 $alpha = atan2($y2-$y1, $x2-$x1);
370 $alpha +
= M_PI
/2; // rotate 90 degrees
371 // Get arbitrary point to define line perpendicular to axis
372 $px2 = $px1+
cos($alpha);
373 $py2 = $py1+
sin($alpha);
375 $res1 = _testIntersect($px1, $py1, $px2, $py2, 0, 0, 0, 1); // $x=0 vert axis
376 $res2 = _testIntersect($px1, $py1, $px2, $py2, 1, 0, 1, 1); // $x=1 vert axis
377 $res3 = _testIntersect($px1, $py1, $px2, $py2, 0, 0, 1, 0); // $y=0 horiz axis
378 $res4 = _testIntersect($px1, $py1, $px2, $py2, 0, 1, 1, 1); // $y=1 horiz axis
379 if (!$res1 && !$res2 && !$res3 && !$res4) { $inside
= false; }
388 for($i=0;$i<$ns;$i++
) {
389 if ($spread=='F') { // Reflect
390 $newarr[$i] = $gradient_info['color'][($ns-$i-1)];
391 if (($gp %
2) == 1) {
392 $tmp = -$gp+
(1-$offs[($ns-$i-1)]);
393 $newarr[$i]['offset'] = $tmp;
396 $tmp = -$gp+
$offs[$i];
397 $newarr[$i]['offset'] = $tmp;
401 $newarr[$i] = $gradient_info['color'][$i];
402 $tmp = -$gp+
$offs[$i];
403 $newarr[$i]['offset'] = $tmp;
406 // IF STILL INSIDE BOX OR STILL VALID
407 // Point on axis to test
408 $px1 = $x1 +
($x2-$x1)*$tmp;
409 $py1 = $y1 +
($y2-$y1)*$tmp;
410 // Get perpendicular axis
411 $alpha = atan2($y2-$y1, $x2-$x1);
412 $alpha +
= M_PI
/2; // rotate 90 degrees
413 // Get arbitrary point to define line perpendicular to axis
414 $px2 = $px1+
cos($alpha);
415 $py2 = $py1+
sin($alpha);
417 $res1 = _testIntersect($px1, $py1, $px2, $py2, 0, 0, 0, 1); // $x=0 vert axis
418 $res2 = _testIntersect($px1, $py1, $px2, $py2, 1, 0, 1, 1); // $x=1 vert axis
419 $res3 = _testIntersect($px1, $py1, $px2, $py2, 0, 0, 1, 0); // $y=0 horiz axis
420 $res4 = _testIntersect($px1, $py1, $px2, $py2, 0, 1, 1, 1); // $y=1 horiz axis
421 if (!$res1 && !$res2 && !$res3 && !$res4) { $inside
= false; }
423 for($i=($ns-1);$i>=0;$i--) {
424 if (isset($newarr[$i]['offset'])) array_unshift($gradient_info['color'], $newarr[$i]);
429 // mPDF 4.4.007 Gradient STOPs
430 $stops = count($gradient_info['color']);
431 if ($stops < 2) { return ''; }
434 $range = $gradient_info['color'][count($gradient_info['color'])-1]['offset']-$gradient_info['color'][0]['offset'];
435 $min = $gradient_info['color'][0]['offset'];
437 for ($i=0; $i<($stops); $i++
) {
439 if (!$gradient_info['color'][$i]['color']) {
440 if ($gradient_info['colorspace']=='RGB') $gradient_info['color'][$i]['color'] = '0 0 0';
441 else if ($gradient_info['colorspace']=='Gray') $gradient_info['color'][$i]['color'] = '0';
442 else if ($gradient_info['colorspace']=='CMYK') $gradient_info['color'][$i]['color'] = '1 1 1 1';
444 $offset = ($gradient_info['color'][$i]['offset'] - $min)/$range;
445 $this->mpdf_ref
->gradients
[$n]['stops'][] = array(
446 'col' => $gradient_info['color'][$i]['color'],
447 'opacity' => $gradient_info['color'][$i]['opacity'],
448 'offset' => $offset);
449 if ($gradient_info['color'][$i]['opacity']<1) { $trans
= true; }
451 $grx1 = $x1 +
($x2-$x1)*$gradient_info['color'][0]['offset'];
452 $gry1 = $y1 +
($y2-$y1)*$gradient_info['color'][0]['offset'];
453 $grx2 = $x1 +
($x2-$x1)*$gradient_info['color'][count($gradient_info['color'])-1]['offset'];
454 $gry2 = $y1 +
($y2-$y1)*$gradient_info['color'][count($gradient_info['color'])-1]['offset'];
456 $this->mpdf_ref
->gradients
[$n]['coords']=array($grx1, $gry1, $grx2, $gry2);
458 $this->mpdf_ref
->gradients
[$n]['colorspace'] = $gradient_info['colorspace']; // mPDF 5.0.051
460 $this->mpdf_ref
->gradients
[$n]['type'] = 2;
461 $this->mpdf_ref
->gradients
[$n]['fo'] = true;
463 $this->mpdf_ref
->gradients
[$n]['extend']=array('true','true');
465 $this->mpdf_ref
->gradients
[$n]['trans'] = true;
466 $return .= ' /TGS'.($n).' gs ';
468 $return .= ' /Sh'.($n).' sh ';
471 else if ($gradient_info['type'] == 'radial'){
473 if (isset($gradient_info['units']) && strtolower($gradient_info['units'])=='userspaceonuse') {
474 if ($w > $h) { $h
= $w
; }
476 if (isset($gradient_info['info']['x0'])) { $gradient_info
['info']['x0'] = ($gradient_info
['info']['x0']-$x_offset
) / $w
; }
477 if (isset($gradient_info['info']['y0'])) { $gradient_info
['info']['y0'] = ($gradient_info
['info']['y0']-$y_offset
) / $h
; }
478 if (isset($gradient_info['info']['x1'])) { $gradient_info
['info']['x1'] = ($gradient_info
['info']['x1']-$x_offset
) / $w
; }
479 if (isset($gradient_info['info']['y1'])) { $gradient_info
['info']['y1'] = ($gradient_info
['info']['y1']-$y_offset
) / $h
; }
480 if (isset($gradient_info['info']['r'])) { $gradient_info
['info']['rx'] = $gradient_info
['info']['r'] / $w
; }
481 if (isset($gradient_info['info']['r'])) { $gradient_info
['info']['ry'] = $gradient_info
['info']['r'] / $h
; }
484 if ($gradient_info['info']['x0'] || $gradient_info['info']['x0']===0) { $x0
= $gradient_info
['info']['x0']; }
486 if ($gradient_info['info']['y0'] || $gradient_info['info']['y0']===0) { $y0
= $gradient_info
['info']['y0']; }
488 if ($gradient_info['info']['rx'] || $gradient_info['info']['rx']===0) { $rx
= $gradient_info
['info']['rx']; }
489 else if ($gradient_info['info']['r'] || $gradient_info['info']['r']===0) { $rx
= $gradient_info
['info']['r']; }
491 if ($gradient_info['info']['ry'] || $gradient_info['info']['ry']===0) { $ry
= $gradient_info
['info']['ry']; }
492 else if ($gradient_info['info']['r'] || $gradient_info['info']['r']===0) { $ry
= $gradient_info
['info']['r']; }
494 if ($gradient_info['info']['x1'] || $gradient_info['info']['x1']===0) { $x1
= $gradient_info
['info']['x1']; }
496 if ($gradient_info['info']['y1'] || $gradient_info['info']['y1']===0) { $y1
= $gradient_info
['info']['y1']; }
499 if (stristr($x1, '%')!== false) { $x1
= ($x1+
0)/100; }
500 if (stristr($x0, '%')!== false) { $x0
= ($x0+
0)/100; }
501 if (stristr($y1, '%')!== false) { $y1
= ($y1+
0)/100; }
502 if (stristr($y0, '%')!== false) { $y0
= ($y0+
0)/100; }
503 if (stristr($rx, '%')!== false) { $rx
= ($rx+
0)/100; }
504 if (stristr($ry, '%')!== false) { $ry
= ($ry+
0)/100; }
513 if (isset($gradient_info['units']) && strtolower($gradient_info['units'])=='userspaceonuse') {
514 $angle = rad2deg(atan2(($gradient_info['info']['y0']-$gradient_info['info']['y1']), ($gradient_info['info']['x0']-$gradient_info['info']['x1'])));
515 if ($angle < 0) { $angle +
= 360; }
516 else if ($angle > 360) { $angle
-= 360; }
517 if ($angle!=0 && $angle!=360 && $angle!=90 && $angle!=180 && $angle!=270) {
523 $usew = $useh = $bboxw;
530 $usew = $useh = $bboxh;
535 $d = -$useh; // height
536 $e = $usex; // x- offset
537 $f = -$usey; // -y-offset
542 $return .= sprintf('%.3F 0 0 %.3F %.3F %.3F cm ', $a*$this->kp
, $d*$this->kp
, $e*$this->kp
, $f*$this->kp
);
545 if (isset($gradient_info['units']) && strtolower($gradient_info['units'])=='objectboundingbox') {
546 if ($transformations) { $
return .= $transformations
; }
549 // x1 and y1 (fx, fy) should be inside the circle defined by x0 y0 and r else error in mPDF
550 while (pow(($x1-$x0),2) +
pow(($y1 - $y0),2) >= pow($r,2)) { $r +
= 0.05; }
553 if ($spread=='R' || $spread=='F') { // Repeat / Reflect
555 for($i=0;$i<$ns;$i++
) {
556 $offs[$i] = $gradient_info['color'][$i]['offset'];
562 for($i=0;$i<$ns;$i++
) {
563 if ($spread=='F' && ($gp %
2) == 1) { // Reflect
564 $gradient_info['color'][(($ns*$gp)+
$i)] = $gradient_info['color'][(($ns*($gp-1))+
($ns-$i-1))];
565 $tmp = $gp+
(1-$offs[($ns-$i-1)]) ;
566 $gradient_info['color'][(($ns*$gp)+
$i)]['offset'] = $tmp;
569 $gradient_info['color'][(($ns*$gp)+
$i)] = $gradient_info['color'][$i];
570 $tmp = $gp+
$offs[$i] ;
571 $gradient_info['color'][(($ns*$gp)+
$i)]['offset'] = $tmp;
573 // IF STILL INSIDE BOX OR STILL VALID
574 // TEST IF circle (perimeter) intersects with
576 // Point on axis to test
577 $px = $x1 +
($x0-$x1)*$tmp;
578 $py = $y1 +
($y0-$y1)*$tmp;
580 $res = _testIntersectCircle($px, $py, $pr);
581 if (!$res) { $inside
= false; }
586 // mPDF 4.4.007 Gradient STOPs
587 $stops = count($gradient_info['color']);
588 if ($stops < 2) { return ''; }
591 $range = $gradient_info['color'][count($gradient_info['color'])-1]['offset']-$gradient_info['color'][0]['offset'];
592 $min = $gradient_info['color'][0]['offset'];
594 for ($i=0; $i<($stops); $i++
) {
596 if (!$gradient_info['color'][$i]['color']) {
597 if ($gradient_info['colorspace']=='RGB') $gradient_info['color'][$i]['color'] = '0 0 0';
598 else if ($gradient_info['colorspace']=='Gray') $gradient_info['color'][$i]['color'] = '0';
599 else if ($gradient_info['colorspace']=='CMYK') $gradient_info['color'][$i]['color'] = '1 1 1 1';
601 $offset = ($gradient_info['color'][$i]['offset'] - $min)/$range;
602 $this->mpdf_ref
->gradients
[$n]['stops'][] = array(
603 'col' => $gradient_info['color'][$i]['color'],
604 'opacity' => $gradient_info['color'][$i]['opacity'],
605 'offset' => $offset);
606 if ($gradient_info['color'][$i]['opacity']<1) { $trans
= true; }
608 $grx1 = $x1 +
($x0-$x1)*$gradient_info['color'][0]['offset'];
609 $gry1 = $y1 +
($y0-$y1)*$gradient_info['color'][0]['offset'];
610 $grx2 = $x1 +
($x0-$x1)*$gradient_info['color'][count($gradient_info['color'])-1]['offset'];
611 $gry2 = $y1 +
($y0-$y1)*$gradient_info['color'][count($gradient_info['color'])-1]['offset'];
612 $grir = $r*$gradient_info['color'][0]['offset'];
613 $grr = $r*$gradient_info['color'][count($gradient_info['color'])-1]['offset'];
615 $this->mpdf_ref
->gradients
[$n]['coords']=array($grx1, $gry1, $grx2, $gry2, abs($grr), abs($grir) );
617 $grx1 = $x1 +
($x0-$x1)*$first_stop;
618 $gry1 = $y1 +
($y0-$y1)*$first_stop;
619 $grx2 = $x1 +
($x0-$x1)*$last_stop;
620 $gry2 = $y1 +
($y0-$y1)*$last_stop;
621 $grir = $r*$first_stop;
622 $grr = $r*$last_stop;
623 $this->mpdf_ref
->gradients
[$n]['colorspace'] = $gradient_info['colorspace']; // mPDF 5.0.051
625 $this->mpdf_ref
->gradients
[$n]['type'] = 3;
626 $this->mpdf_ref
->gradients
[$n]['fo'] = true;
628 $this->mpdf_ref
->gradients
[$n]['extend']=array('true','true');
630 $this->mpdf_ref
->gradients
[$n]['trans'] = true;
631 $return .= ' /TGS'.($n).' gs ';
633 $return .= ' /Sh'.($n).' sh ';
643 function svgOffset ($attribs){
644 // save all <svg> tag attributes
645 $this->svg_attribs
= $attribs;
646 if(isset($this->svg_attribs
['viewBox'])) {
647 $vb = preg_split('/\s+/is', trim($this->svg_attribs
['viewBox']));
649 $this->svg_info
['x'] = $vb[0];
650 $this->svg_info
['y'] = $vb[1];
651 $this->svg_info
['w'] = $vb[2];
652 $this->svg_info
['h'] = $vb[3];
653 // return; // mPDF 5.0.005
657 $svg_w = $this->mpdf_ref
->ConvertSize($attribs['width']); // mm (interprets numbers as pixels)
658 $svg_h = $this->mpdf_ref
->ConvertSize($attribs['height']); // mm
662 if ($this->svg_info
['w']) { // if 'w' set by viewBox
663 if ($svg_w) { // if width also set, use these values to determine to set size of "pixel"
664 $this->kp
*= ($svg_w/0.2645) / $this->svg_info
['w'];
665 $this->kf
= ($svg_w/0.2645) / $this->svg_info
['w']; // mPDF 5.0.039
668 $this->kp
*= ($svg_h/0.2645) / $this->svg_info
['h'];
669 $this->kf
= ($svg_h/0.2645) / $this->svg_info
['h']; // mPDF 5.0.039
675 // Added to handle file without height or width specified
676 if (!$svg_w && !$svg_h) { $svg_w
= $svg_h
= $this
->mpdf_ref
->blk
[$this
->mpdf_ref
->blklvl
]['inner_width'] ; } // DEFAULT
677 if (!$svg_w) { $svg_w
= $svg_h
; }
678 if (!$svg_h) { $svg_h
= $svg_w
; }
680 $this->svg_info
['x'] = 0;
681 $this->svg_info
['y'] = 0;
682 $this->svg_info
['w'] = $svg_w/0.2645; // mm->pixels
683 $this->svg_info
['h'] = $svg_h/0.2645; // mm->pixels
689 // check if points are within svg, if not, set to max
690 function svg_overflow($x,$y)
694 if(isset($this->svg_attribs
['overflow']))
696 if($this->svg_attribs
['overflow'] == 'hidden')
698 // Not sure if this is supposed to strip off units, but since I dont use any I will omlt this step
699 $svg_w = preg_replace("/([0-9\.]*)(.*)/i","$1",$this->svg_attribs['width']);
700 $svg_h = preg_replace("/([0-9\
.]*)(.*)/i
","$1",$this->svg_attribs
['height']);
702 // $xmax = floor($this->svg_attribs['width']);
703 $xmax = floor($svg_w);
705 // $ymax = floor(($this->svg_attribs['height'] * -1));
706 $ymax = floor(($svg_h * -1));
709 if($x > $xmax) $x2 = $xmax; // right edge
710 if($x < $xmin) $x2 = $xmin; // left edge
711 if($y < $ymax) $y2 = $ymax; // bottom
712 if($y > $ymin) $y2 = $ymin; // top
718 return array( 'x' => $x2, 'y' => $y2);
723 function svgDefineStyle($critere_style){
725 $tmp = count($this->svg_style
)-1;
726 $current_style = $this->svg_style
[$tmp];
728 unset($current_style['transformations']);
731 $transformations = '';
732 if (isset($critere_style['transform'])){
733 preg_match_all('/(matrix|translate|scale|rotate|skewX|skewY)\((.*?)\)/is',$critere_style['transform'],$m);
735 for($i=0; $i<count($m[0]); $i++
) {
736 $c = strtolower($m[1][$i]);
737 $v = trim($m[2][$i]);
738 $vv = preg_split('/[ ,]+/',$v);
739 if ($c=='matrix' && count($vv)==6) {
741 // Note angle of rotation is reversed (from SVG to PDF), so vv[1] and vv[2] are negated
742 $transformations .= sprintf(' %.3F %.3F %.3F %.3F %.3F %.3F cm ', $vv[0], -$vv[1], -$vv[2], $vv[3], $vv[4]*$this->kp
, -$vv[5]*$this->kp
);
745 // The long way of doing this??
746 // need to reverse angle of rotation from SVG to PDF
747 $sx=sqrt(pow($vv[0],2)+pow($vv[2],2));
748 if ($vv[0] < 0) { $sx *= -1; } // change sign
749 $sy=sqrt(pow($vv[1],2)+pow($vv[3],2));
750 if ($vv[3] < 0) { $sy *= -1; } // change sign
753 $t=atan2($vv[1],$vv[3]);
754 $t=atan2(-$vv[2],$vv[0]); // Should be the same value or skew has been applied
762 $mc = -$sx * sin($t);
765 // $transformations .= sprintf(' %.3F %.3F %.3F %.3F %.3F %.3F cm ', $ma, $mb, $mc, $md, $vv[4]*$this->kp, -$vv[5]*$this->kp);
769 else if ($c=='translate' && count($vv)) {
771 if (count($vv)==2) { $t_y
= -$vv
[1]; }
774 $transformations .= sprintf(' 1 0 0 1 %.3F %.3F cm ', $tm[4]*$this->kp
, $tm[5]*$this->kp
);
776 else if ($c=='scale' && count($vv)) {
777 if (count($vv)==2) { $s_y
= $vv
[1]; }
778 else { $s_y
= $vv
[0]; }
781 $transformations .= sprintf(' %.3F 0 0 %.3F 0 0 cm ', $tm[0], $tm[3]);
783 else if ($c=='rotate' && count($vv)) {
784 $tm[0] = cos(deg2rad(-$vv[0]));
785 $tm[1] = sin(deg2rad(-$vv[0]));
789 $transformations .= sprintf(' 1 0 0 1 %.3F %.3F cm ', $vv[1]*$this->kp
, -$vv[2]*$this->kp
);
791 $transformations .= sprintf(' %.3F %.3F %.3F %.3F 0 0 cm ', $tm[0], $tm[1], $tm[2], $tm[3]);
793 $transformations .= sprintf(' 1 0 0 1 %.3F %.3F cm ', -$vv[1]*$this->kp
, $vv[2]*$this->kp
);
796 else if ($c=='skewx' && count($vv)) {
797 $tm[2] = tan(deg2rad(-$vv[0]));
798 $transformations .= sprintf(' 1 0 %.3F 1 0 0 cm ', $tm[2]);
800 else if ($c=='skewy' && count($vv)) {
801 $tm[1] = tan(deg2rad(-$vv[0]));
802 $transformations .= sprintf(' 1 %.3F 0 1 0 0 cm ', $tm[1]);
807 $current_style['transformations'] = $transformations;
810 if (isset($critere_style['style'])){
811 if (preg_match('/fill:\s*rgb\((\d+),\s*(\d+),\s*(\d+)\)/i',$critere_style['style'], $m)) { // mPDF 5.7.2
812 $current_style['fill'] = '#'.str_pad(dechex($m[1]), 2, "0", STR_PAD_LEFT
).str_pad(dechex($m[2]), 2, "0", STR_PAD_LEFT
).str_pad(dechex($m[3]), 2, "0", STR_PAD_LEFT
);
814 else { $tmp = preg_replace("/(.*)fill:\s*([a-z0-9#_()]*|none)(.*)/i","$2",$critere_style['style']); // mPDF 4.4.003
815 if ($tmp != $critere_style['style']){ $current_style['fill'] = $tmp; }
819 if (preg_match("/[^
-]opacity
:\s
*([a
-z0
-9.]*|none
)/i
",$critere_style['style'], $m) ||
820 preg_match("/^opacity
:\s
*([a
-z0
-9.]*|none
)/i
",$critere_style['style'], $m)) {
821 $current_style['fill-opacity'] = $m[1];
822 $current_style['stroke-opacity'] = $m[1];
825 $tmp = preg_replace("/(.*)fill
-opacity
:\s
*([a
-z0
-9.]*|none
)(.*)/i
","$2",$critere_style['style']);
826 if ($tmp != $critere_style['style']){ $current_style
['fill-opacity'] = $tmp
;}
828 $tmp = preg_replace("/(.*)fill-rule:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']);
829 if ($tmp != $critere_style['style']){ $current_style['fill-rule'] = $tmp;}
831 if (preg_match('/stroke:\s*rgb\((\d+),\s*(\d+),\s*(\d+)\)/',$critere_style['style'], $m)) {
832 $current_style['stroke'] = '#'.str_pad(dechex($m[1]), 2, "0", STR_PAD_LEFT).str_pad(dechex($m[2]), 2, "0", STR_PAD_LEFT).str_pad(dechex($m[3]), 2, "0", STR_PAD_LEFT);
834 else { $tmp = preg_replace("/(.*)stroke
:\s
*([a
-z0
-9#]*|none)(.*)/i","$2",$critere_style['style']);
835 if ($tmp != $critere_style['style']){ $current_style
['stroke'] = $tmp
; }
838 $tmp = preg_replace("/(.*)stroke-linecap:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']);
839 if ($tmp != $critere_style['style']){ $current_style['stroke-linecap'] = $tmp;}
841 $tmp = preg_replace("/(.*)stroke
-linejoin
:\s
*([a
-z0
-9#]*|none)(.*)/i","$2",$critere_style['style']);
842 if ($tmp != $critere_style['style']){ $current_style
['stroke-linejoin'] = $tmp
;}
844 $tmp = preg_replace("/(.*)stroke-miterlimit:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']);
845 if ($tmp != $critere_style['style']){ $current_style['stroke-miterlimit'] = $tmp;}
847 $tmp = preg_replace("/(.*)stroke
-opacity
:\s
*([a
-z0
-9.]*|none
)(.*)/i
","$2",$critere_style['style']);
848 if ($tmp != $critere_style['style']){ $current_style
['stroke-opacity'] = $tmp
; }
850 $tmp = preg_replace("/(.*)stroke-width:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']);
851 if ($tmp != $critere_style['style']){ $current_style['stroke-width'] = $tmp;}
854 $tmp = preg_replace("/(.*)stroke
-dasharray
:\s
*([a
-z0
-9., ]*|none
)(.*)/i
","$2",$critere_style['style']);
855 if ($tmp != $critere_style['style']){ $current_style
['stroke-dasharray'] = $tmp
;}
858 $tmp = preg_replace("/(.*)stroke-dashoffset:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']);
859 if ($tmp != $critere_style['style']){ $current_style['stroke-dashoffset'] = $tmp;}
863 if(isset($critere_style['opacity'])){
864 $current_style['fill-opacity'] = $critere_style['opacity'];
865 $current_style['stroke-opacity'] = $critere_style['opacity'];
868 if(isset($critere_style['fill'])){
869 $current_style['fill'] = $critere_style['fill'];
872 if(isset($critere_style['fill-opacity'])){
873 $current_style['fill-opacity'] = $critere_style['fill-opacity'];
876 if(isset($critere_style['fill-rule'])){
877 $current_style['fill-rule'] = $critere_style['fill-rule'];
880 if(isset($critere_style['stroke'])){
881 $current_style['stroke'] = $critere_style['stroke'];
884 if(isset($critere_style['stroke-linecap'])){
885 $current_style['stroke-linecap'] = $critere_style['stroke-linecap'];
888 if(isset($critere_style['stroke-linejoin'])){
889 $current_style['stroke-linejoin'] = $critere_style['stroke-linejoin'];
892 if(isset($critere_style['stroke-miterlimit'])){
893 $current_style['stroke-miterlimit'] = $critere_style['stroke-miterlimit'];
896 if(isset($critere_style['stroke-opacity'])){
897 $current_style['stroke-opacity'] = $critere_style['stroke-opacity'];
900 if(isset($critere_style['stroke-width'])){
901 $current_style['stroke-width'] = $critere_style['stroke-width'];
905 if(isset($critere_style['stroke-dasharray'])){
906 $current_style['stroke-dasharray'] = $critere_style['stroke-dasharray'];
908 if(isset($critere_style['stroke-dashoffset'])){
909 $current_style['stroke-dashoffset'] = $critere_style['stroke-dashoffset'];
912 // mPDF 4.4.005 Used as indirect setting for currentColor
913 if(isset($critere_style['color']) && $critere_style['color'] != 'inherit'){
914 $current_style['color'] = $critere_style['color'];
917 return $current_style;
922 // Cette fonction ecrit le style dans le stream svg.
923 function svgStyle($critere_style, $attribs, $element){
925 if (substr_count($critere_style['fill'],'url')>0 && $element != 'line'){
928 $id_gradient = preg_replace("/url\
(#([\w_]*)\)/i","$1",$critere_style['fill']);
929 if ($id_gradient != $critere_style['fill']) {
930 if (isset($this->svg_gradient
[$id_gradient])) {
931 $fill_gradient = $this->svgGradient($this->svg_gradient
[$id_gradient], $attribs, $element);
932 if ($fill_gradient) { // mPDF 4.4.003
941 // mPDF 4.4.005 Used as indirect setting for currentColor
942 else if (strtolower($critere_style['fill']) == 'currentcolor' && $element != 'line'){
943 $col = $this->mpdf_ref
->ConvertColor($critere_style['color']);
947 if ($col{0}==5) { $critere_style
['fill-opacity'] = ord($col
{4}/100); } // RGBa
948 if ($col{0}==6) { $critere_style
['fill-opacity'] = ord($col
{5}/100); } // CMYKa
949 $path_style .= $this->mpdf_ref
->SetFColor($col, true).' '; // mPDF 5.0.051
953 else if ($critere_style['fill'] != 'none' && $element != 'line'){
954 $col = $this->mpdf_ref
->ConvertColor($critere_style['fill']);
958 if ($col{0}==5) { $critere_style
['fill-opacity'] = ord($col
{4}/100); } // RGBa
959 if ($col{0}==6) { $critere_style
['fill-opacity'] = ord($col
{5}/100); } // CMYKa
960 $path_style .= $this->mpdf_ref
->SetFColor($col, true).' '; // mPDF 5.0.051
966 if (substr_count($critere_style['stroke'],'url')>0){
968 // Cannot put a gradient on a "stroke" in PDF?
969 $id_gradient = preg_replace("/url\(#([\w_]*)\)/i","$1",$critere_style['stroke']);
970 if ($id_gradient != $critere_style['stroke']) {
971 if (isset($this->svg_gradient[$id_gradient])) {
972 $fill_gradient = $this->svgGradient($this->svg_gradient[$id_gradient], $attribs, $element);
973 if ($fill_gradient) {
982 // mPDF 4.4.005 Used as indirect setting for currentColor
983 else if (strtolower($critere_style['stroke']) == 'currentcolor'){
984 $col = $this->mpdf_ref
->ConvertColor($critere_style['color']);
988 if ($col{0}==5) { $critere_style
['stroke-opacity'] = ord($col
{4}/100); } // RGBa
989 if ($col{0}==6) { $critere_style
['stroke-opacity'] = ord($col
{5}/100); } // CMYKa
990 $path_style .= $this->mpdf_ref
->SetDColor($col, true).' '; // mPDF 5.0.051
992 $lw = $this->ConvertSVGSizePixels($critere_style['stroke-width']);
993 $path_style .= sprintf('%.3F w ',$lw*$this->kp
);
996 else if ($critere_style['stroke'] != 'none'){
997 $col = $this->mpdf_ref
->ConvertColor($critere_style['stroke']);
1001 if ($col{0}==5) { $critere_style
['stroke-opacity'] = ord($col
{4}/100); } // RGBa
1002 if ($col{0}==6) { $critere_style
['stroke-opacity'] = ord($col
{5}/100); } // CMYKa
1003 $path_style .= $this->mpdf_ref
->SetDColor($col, true).' '; // mPDF 5.0.051
1005 $lw = $this->ConvertSVGSizePixels($critere_style['stroke-width']); // mPDF 4.4.003
1006 $path_style .= sprintf('%.3F w ',$lw*$this->kp
);
1011 if ($critere_style['stroke'] != 'none'){
1012 if ($critere_style['stroke-linejoin'] == 'miter'){
1013 $path_style .= ' 0 j ';
1015 else if ($critere_style['stroke-linejoin'] == 'round'){
1016 $path_style .= ' 1 j ';
1018 else if ($critere_style['stroke-linejoin'] == 'bevel'){
1019 $path_style .= ' 2 j ';
1022 if ($critere_style['stroke-linecap'] == 'butt'){
1023 $path_style .= ' 0 J ';
1025 else if ($critere_style['stroke-linecap'] == 'round'){
1026 $path_style .= ' 1 J ';
1028 else if ($critere_style['stroke-linecap'] == 'square'){
1029 $path_style .= ' 2 J ';
1032 if (isset($critere_style['stroke-miterlimit'])){
1033 if ($critere_style['stroke-miterlimit'] == 'none'){
1035 else if (preg_match('/^[\d.]+$/',$critere_style['stroke-miterlimit'])) {
1036 $path_style .= sprintf('%.2F M ',$critere_style['stroke-miterlimit']);
1040 if (isset($critere_style['stroke-dasharray'])){
1042 $d = preg_split('/[ ,]/',$critere_style['stroke-dasharray']);
1043 if (count($d) == 1 && $d[0]==0) {
1044 $path_style .= '[] 0 d ';
1047 if (count($d) %
2 == 1) { $d
= array_merge($d
, $d
); } // 5, 3, 1 => 5,3,1,5,3,1 OR 3 => 3,3
1049 for($i=0; $i<count($d); $i+
=2) {
1050 $arr .= sprintf('%.3F %.3F ', $d[$i]*$this->kp
, $d[$i+
1]*$this->kp
);
1052 if (isset($critere_style['stroke-dashoffset'])){ $off
= $critere_style
['stroke-dashoffset'] +
0; }
1053 $path_style .= sprintf('[%s] %.3F d ', $arr, $off*$this->kp
);
1059 if ($critere_style['fill-rule']=='evenodd') { $fr
= '*'; }
1063 if (isset($critere_style['fill-opacity'])) {
1065 if ($critere_style['fill-opacity'] == 0) { $opacity
= 0; }
1066 else if ($critere_style['fill-opacity'] > 1) { $opacity
= 1; }
1067 else if ($critere_style['fill-opacity'] > 0) { $opacity
= $critere_style
['fill-opacity']; }
1068 else if ($critere_style['fill-opacity'] < 0) { $opacity
= 0; }
1069 $gs = $this->mpdf_ref
->AddExtGState(array('ca'=>$opacity, 'BM'=>'/Normal'));
1070 $this->mpdf_ref
->extgstates
[$gs]['fo'] = true; // mPDF 5.0.039
1071 $path_style .= sprintf(' /GS%d gs ', $gs);
1075 if (isset($critere_style['stroke-opacity'])) {
1077 if ($critere_style['stroke-opacity'] == 0) { $opacity
= 0; }
1078 else if ($critere_style['stroke-opacity'] > 1) { $opacity
= 1; }
1079 else if ($critere_style['stroke-opacity'] > 0) { $opacity
= $critere_style
['stroke-opacity']; }
1080 else if ($critere_style['stroke-opacity'] < 0) { $opacity
= 0; }
1081 $gs = $this->mpdf_ref
->AddExtGState(array('CA'=>$opacity, 'BM'=>'/Normal'));
1082 $this->mpdf_ref
->extgstates
[$gs]['fo'] = true; // mPDF 5.0.039
1083 $path_style .= sprintf(' /GS%d gs ', $gs);
1104 $prestyle = $path_style.' ';
1105 $poststyle = $w.' '. $op.$fr.' '.$fill_gradient."\n";
1106 return array($prestyle,$poststyle);
1111 // fonction retracant les <path />
1112 function svgPath($command, $arguments){
1114 $newsubpath = false; // mPDF 4.4.003
1116 $minl = $this->pathBBox
[0];
1117 $mint = $this->pathBBox
[1];
1118 $maxr = $this->pathBBox
[2]+
$this->pathBBox
[0];
1119 $maxb = $this->pathBBox
[3]+
$this->pathBBox
[1];
1121 $start = array($this->xbase
, -$this->ybase
);
1124 preg_match_all('/[\-^]?[\d.]+(e[\-]?[\d]+){0,1}/i', $arguments, $a, PREG_SET_ORDER
);
1126 // if the command is a capital letter, the coords go absolute, otherwise relative
1127 if(strtolower($command) == $command) $relative = true;
1128 else $relative = false;
1131 $ile_argumentow = count($a);
1133 // each command may have different needs for arguments [1 to 8]
1135 switch(strtolower($command)){
1137 for($i = 0; $i<$ile_argumentow; $i+
=2){
1141 $pdfx = ($this->xbase +
$x);
1142 $pdfy = ($this->ybase
- $y);
1144 $this->ybase +
= -$y;
1152 $pdf_pt = $this->svg_overflow($pdfx,$pdfy);
1154 $minl = min($minl,$pdf_pt['x']);
1155 $maxr = max($maxr,$pdf_pt['x']);
1156 $mint = min($mint,-$pdf_pt['y']);
1157 $maxb = max($maxb,-$pdf_pt['y']);
1158 if($i == 0) $path_cmd .= sprintf('%.3F %.3F m ', $pdf_pt['x']*$this->kp
, $pdf_pt['y']*$this->kp
);
1159 else $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x']*$this->kp
, $pdf_pt['y']*$this->kp
);
1160 // mPDF 4.4.003 Save start points of subpath
1161 if ($this->subPathInit
) {
1162 $this->spxstart
= $this->xbase
;
1163 $this->spystart
= $this->ybase
;
1164 $this->subPathInit
= false;
1168 case 'l': // a simple line
1169 for($i = 0; $i<$ile_argumentow; $i+
=2){
1173 $pdfx = ($this->xbase +
$x);
1174 $pdfy = ($this->ybase
- $y);
1176 $this->ybase +
= -$y;
1184 $pdf_pt = $this->svg_overflow($pdfx,$pdfy);
1186 $minl = min($minl,$pdf_pt['x']);
1187 $maxr = max($maxr,$pdf_pt['x']);
1188 $mint = min($mint,-$pdf_pt['y']);
1189 $maxb = max($maxb,-$pdf_pt['y']);
1190 $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x']*$this->kp
, $pdf_pt['y']*$this->kp
);
1193 case 'h': // a very simple horizontal line
1194 for($i = 0; $i<$ile_argumentow; $i++
){
1198 $pdfx = ($this->xbase +
$x) ;
1199 $pdfy = ($this->ybase
- $y) ;
1201 $this->ybase +
= -$y;
1210 $pdf_pt = $this->svg_overflow($pdfx,$pdfy);
1212 $minl = min($minl,$pdf_pt['x']);
1213 $maxr = max($maxr,$pdf_pt['x']);
1214 $mint = min($mint,-$pdf_pt['y']);
1215 $maxb = max($maxb,-$pdf_pt['y']);
1216 $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x']*$this->kp
, $pdf_pt['y']*$this->kp
);
1219 case 'v': // the simplest line, vertical
1220 for($i = 0; $i<$ile_argumentow; $i++
){
1224 $pdfx = ($this->xbase +
$x);
1225 $pdfy = ($this->ybase
- $y);
1227 $this->ybase +
= -$y;
1236 $pdf_pt = $this->svg_overflow($pdfx,$pdfy);
1238 $minl = min($minl,$pdf_pt['x']);
1239 $maxr = max($maxr,$pdf_pt['x']);
1240 $mint = min($mint,-$pdf_pt['y']);
1241 $maxb = max($maxb,-$pdf_pt['y']);
1242 $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x']*$this->kp
, $pdf_pt['y']*$this->kp
);
1245 case 's': // bezier with first vertex equal first control
1247 if (!($this->lastcommand
== 'C' || $this->lastcommand
== 'c' || $this->lastcommand
== 'S' || $this->lastcommand
== 's')) {
1248 $this->lastcontrolpoints
= array(0,0);
1250 for($i = 0; $i<$ile_argumentow; $i +
= 4){
1251 $x1 = $this->lastcontrolpoints
[0];
1252 $y1 = $this->lastcontrolpoints
[1];
1254 $y2 = ($a[$i+
1][0]);
1258 $pdfx1 = ($this->xbase +
$x1);
1259 $pdfy1 = ($this->ybase
- $y1);
1260 $pdfx2 = ($this->xbase +
$x2);
1261 $pdfy2 = ($this->ybase
- $y2);
1262 $pdfx = ($this->xbase +
$x);
1263 $pdfy = ($this->ybase
- $y);
1265 $this->ybase +
= -$y;
1268 $pdfx1 = $this->xbase +
$x1;
1269 $pdfy1 = $this->ybase
-$y1;
1277 $this->lastcontrolpoints
= array(($pdfx-$pdfx2),-($pdfy-$pdfy2)); // mPDF 4.4.003 always relative
1279 $pdf_pt = $this->svg_overflow($pdfx,$pdfy);
1282 $curves = array($pdfx1,-$pdfy1,$pdfx2,-$pdfy2,$pdfx,-$pdfy);
1283 $bx = calc_bezier_bbox($start, $curves);
1284 $minl = min($minl,$bx[0]);
1285 $maxr = max($maxr,$bx[2]);
1286 $mint = min($mint,$bx[1]);
1287 $maxb = max($maxb,$bx[3]);
1289 if( ($pdf_pt['x'] != $pdfx) || ($pdf_pt['y'] != $pdfy) )
1291 $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x']*$this->kp
, $pdf_pt['y']*$this->kp
);
1295 $path_cmd .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', $pdfx1*$this->kp
, $pdfy1*$this->kp
, $pdfx2*$this->kp
, $pdfy2*$this->kp
, $pdfx*$this->kp
, $pdfy*$this->kp
);
1300 case 'c': // bezier with second vertex equal second control
1301 for($i = 0; $i<$ile_argumentow; $i +
= 6){
1303 $y1 = ($a[$i+
1][0]);
1304 $x2 = ($a[$i+
2][0]);
1305 $y2 = ($a[$i+
3][0]);
1311 $pdfx1 = ($this->xbase +
$x1);
1312 $pdfy1 = ($this->ybase
- $y1);
1313 $pdfx2 = ($this->xbase +
$x2);
1314 $pdfy2 = ($this->ybase
- $y2);
1315 $pdfx = ($this->xbase +
$x);
1316 $pdfy = ($this->ybase
- $y);
1318 $this->ybase +
= -$y;
1330 $this->lastcontrolpoints
= array(($pdfx-$pdfx2),-($pdfy-$pdfy2)); // mPDF 4.4.003 always relative
1331 // $pdf_pt2 = $this->svg_overflow($pdfx2,$pdfy2);
1332 // $pdf_pt1 = $this->svg_overflow($pdfx1,$pdfy1);
1333 $pdf_pt = $this->svg_overflow($pdfx,$pdfy);
1336 $curves = array($pdfx1,-$pdfy1,$pdfx2,-$pdfy2,$pdfx,-$pdfy);
1337 $bx = calc_bezier_bbox($start, $curves);
1338 $minl = min($minl,$bx[0]);
1339 $maxr = max($maxr,$bx[2]);
1340 $mint = min($mint,$bx[1]);
1341 $maxb = max($maxb,$bx[3]);
1343 if( ($pdf_pt['x'] != $pdfx) || ($pdf_pt['y'] != $pdfy) )
1345 $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x']*$this->kp
, $pdf_pt['y']*$this->kp
);
1349 $path_cmd .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', $pdfx1*$this->kp
, $pdfy1*$this->kp
, $pdfx2*$this->kp
, $pdfy2*$this->kp
, $pdfx*$this->kp
, $pdfy*$this->kp
);
1355 case 'q': // bezier quadratic avec point de control
1356 for($i = 0; $i<$ile_argumentow; $i +
= 4){
1358 $y1 = ($a[$i+
1][0]);
1362 $pdfx = ($this->xbase +
$x);
1363 $pdfy = ($this->ybase
- $y);
1365 $pdfx1 = ($this->xbase +
($x1*2/3));
1366 $pdfy1 = ($this->ybase
- ($y1*2/3));
1368 $pdfx2 = $pdfx1 +
1/3 *($x);
1369 $pdfy2 = $pdfy1 +
1/3 *(-$y) ;
1372 $this->ybase +
= -$y;
1378 $pdfx1 = ($this->xbase+
(($x1-$this->xbase
)*2/3));
1379 $pdfy1 = ($this->ybase
-(($y1+
$this->ybase
)*2/3));
1381 $pdfx2 = ($x+
(($x1-$x)*2/3));
1382 $pdfy2 = (-$y-(($y1-$y)*2/3));
1385 $pdfx2 = $pdfx1 +
1/3 *($x - $this->xbase
);
1386 $pdfy2 = $pdfy1 +
1/3 *(-$y - $this->ybase
) ;
1391 $this->lastcontrolpoints
= array(($pdfx-$pdfx2),-($pdfy-$pdfy2)); // mPDF 4.4.003 always relative
1393 $pdf_pt = $this->svg_overflow($pdfx,$pdfy);
1396 $curves = array($pdfx1,-$pdfy1,$pdfx2,-$pdfy2,$pdfx,-$pdfy);
1397 $bx = calc_bezier_bbox($start, $curves);
1398 $minl = min($minl,$bx[0]);
1399 $maxr = max($maxr,$bx[2]);
1400 $mint = min($mint,$bx[1]);
1401 $maxb = max($maxb,$bx[3]);
1403 if( ($pdf_pt['x'] != $pdfx) || ($pdf_pt['y'] != $pdfy) )
1405 $path_cmd .= sprintf('%.3F %.3F l ', $pdf_pt['x']*$this->kp
, $pdf_pt['y']*$this->kp
);
1409 $path_cmd .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', $pdfx1*$this->kp
, $pdfy1*$this->kp
, $pdfx2*$this->kp
, $pdfy2*$this->kp
, $pdfx*$this->kp
, $pdfy*$this->kp
);
1413 case 't': // bezier quadratic avec point de control simetrique a lancien point de control
1415 if (!($this->lastcommand
== 'Q' || $this->lastcommand
== 'q' || $this->lastcommand
== 'T' || $this->lastcommand
== 't')) {
1416 $this->lastcontrolpoints
= array(0,0);
1418 for($i = 0; $i<$ile_argumentow; $i +
= 2){
1422 $x1 = $this->lastcontrolpoints
[0];
1423 $y1 = $this->lastcontrolpoints
[1];
1426 $pdfx = ($this->xbase +
$x);
1427 $pdfy = ($this->ybase
- $y);
1429 $pdfx1 = ($this->xbase +
($x1)); // mPDF 4.4.003
1430 $pdfy1 = ($this->ybase
- ($y1)); // mPDF 4.4.003
1432 $pdfx2 = $pdfx1 +
1/3 *($x);
1433 $pdfy2 = $pdfy1 +
1/3 *(-$y) ;
1436 $this->ybase +
= -$y;
1442 $pdfx1 = ($this->xbase +
($x1)); // mPDF 4.4.003
1443 $pdfy1 = ($this->ybase
- ($y1)); // mPDF 4.4.003
1445 $pdfx2 = $pdfx1 +
1/3 *($x - $this->xbase
);
1446 $pdfy2 = $pdfy1 +
1/3 *(-$y - $this->ybase
) ;
1452 $this->lastcontrolpoints
= array(($pdfx-$pdfx2),-($pdfy-$pdfy2)); // mPDF 4.4.003 always relative
1455 $curves = array($pdfx1,-$pdfy1,$pdfx2,-$pdfy2,$pdfx,-$pdfy);
1456 $bx = calc_bezier_bbox($start, $curves);
1457 $minl = min($minl,$bx[0]);
1458 $maxr = max($maxr,$bx[2]);
1459 $mint = min($mint,$bx[1]);
1460 $maxb = max($maxb,$bx[3]);
1462 $path_cmd .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', $pdfx1*$this->kp
, $pdfy1*$this->kp
, $pdfx2*$this->kp
, $pdfy2*$this->kp
, $pdfx*$this->kp
, $pdfy*$this->kp
);
1466 case 'a': // Elliptical arc
1467 for($i = 0; $i<$ile_argumentow; $i +
= 7){
1469 $ry = ($a[$i+
1][0]);
1470 $angle = ($a[$i+
2][0]); //x-axis-rotation
1471 $largeArcFlag = ($a[$i+
3][0]);
1472 $sweepFlag = ($a[$i+
4][0]);
1473 $x2 = ($a[$i+
5][0]);
1474 $y2 = ($a[$i+
6][0]);
1476 $y1 = -$this->ybase
;
1478 $x2 = $this->xbase +
$x2;
1479 $y2 = -$this->ybase +
$y2;
1480 $this->xbase +
= ($a[$i+
5][0]);
1481 $this->ybase +
= -($a[$i+
6][0]);
1485 $this->ybase
= -$y2;
1487 // mPDF 5.0.039 // mPDF 5.0.040
1488 list($pcmd, $bounds) = $this->Arcto($x1, $y1, $x2, $y2, $rx, $ry, $angle, $largeArcFlag, $sweepFlag);
1489 $minl = min($minl,$x2,min($bounds[0]));
1490 $maxr = max($maxr,$x2,max($bounds[0]));
1491 $mint = min($mint,$y2,min($bounds[1]));
1492 $maxb = max($maxb,$y2,max($bounds[1]));
1500 $this->subPathInit
= true;
1502 $this->xbase
= $this->spxstart
;
1503 $this->ybase
= $this->spystart
;
1509 if (!$newsubpath) { $this
->subPathInit
= false; } // mPDF 4.4.003
1510 $this->lastcommand
= $command;
1512 $this->pathBBox
[0] = $minl;
1513 $this->pathBBox
[1] = $mint;
1514 $this->pathBBox
[2] = $maxr - $this->pathBBox
[0];
1515 $this->pathBBox
[3] = $maxb - $this->pathBBox
[1];
1520 function Arcto($x1, $y1, $x2, $y2, $rx, $ry, $angle, $largeArcFlag, $sweepFlag) {
1523 $bounds = array(0=>array($x1,$x2),1=>array($y1,$y2));
1524 // 1. Treat out-of-range parameters as described in
1525 // http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
1526 // If the endpoints (x1, y1) and (x2, y2) are identical, then this
1527 // is equivalent to omitting the elliptical arc segment entirely
1528 if ($x1 == $x2 && $y1 == $y2) return array('', $bounds); // mPD 5.0.040
1530 // If rX = 0 or rY = 0 then this arc is treated as a straight line
1531 // segment (a "lineto") joining the endpoints.
1532 if ($rx == 0.0 || $ry == 0.0) {
1533 // return array(Lineto(x2, y2), $bounds); // mPD 5.0.040
1536 // If rX or rY have negative signs, these are dropped; the absolute
1537 // value is used instead.
1538 if ($rx<0.0) $rx = -$rx;
1539 if ($ry<0.0) $ry = -$ry;
1541 // 2. convert to center parameterization as shown in
1542 // http://www.w3.org/TR/SVG/implnote.html
1543 $sinPhi = sin(deg2rad($angle));
1544 $cosPhi = cos(deg2rad($angle));
1546 $x1dash = $cosPhi * ($x1-$x2)/2.0 +
$sinPhi * ($y1-$y2)/2.0;
1547 $y1dash = -$sinPhi * ($x1-$x2)/2.0 +
$cosPhi * ($y1-$y2)/2.0;
1550 $numerator = $rx*$rx*$ry*$ry - $rx*$rx*$y1dash*$y1dash - $ry*$ry*$x1dash*$x1dash;
1552 if ($numerator < 0.0) {
1553 // If rX , rY and are such that there is no solution (basically,
1554 // the ellipse is not big enough to reach from (x1, y1) to (x2,
1555 // y2)) then the ellipse is scaled up uniformly until there is
1556 // exactly one solution (until the ellipse is just big enough).
1558 // -> find factor s, such that numerator' with rx'=s*rx and
1559 // ry'=s*ry becomes 0 :
1560 $s = sqrt(1.0 - $numerator/($rx*$rx*$ry*$ry));
1568 $root = ($largeArcFlag == $sweepFlag ? -1.0 : 1.0) * sqrt( $numerator/($rx*$rx*$y1dash*$y1dash+
$ry*$ry*$x1dash*$x1dash) );
1571 $cxdash = $root*$rx*$y1dash/$ry;
1572 $cydash = -$root*$ry*$x1dash/$rx;
1574 $cx = $cosPhi * $cxdash - $sinPhi * $cydash +
($x1+
$x2)/2.0;
1575 $cy = $sinPhi * $cxdash +
$cosPhi * $cydash +
($y1+
$y2)/2.0;
1578 $theta1 = $this->CalcVectorAngle(1.0, 0.0, ($x1dash-$cxdash)/$rx, ($y1dash-$cydash)/$ry);
1579 $dtheta = $this->CalcVectorAngle(($x1dash-$cxdash)/$rx, ($y1dash-$cydash)/$ry, (-$x1dash-$cxdash)/$rx, (-$y1dash-$cydash)/$ry);
1580 if (!$sweepFlag && $dtheta>0)
1581 $dtheta -= 2.0*M_PI
;
1582 else if ($sweepFlag && $dtheta<0)
1583 $dtheta +
= 2.0*M_PI
;
1585 // 3. convert into cubic bezier segments <= 90deg
1586 $segments = ceil(abs($dtheta/(M_PI
/2.0)));
1587 $delta = $dtheta/$segments;
1588 $t = 8.0/3.0 * sin($delta/4.0) * sin($delta/4.0) / sin($delta/2.0);
1590 for ($i = 0; $i < $segments; $i++
) {
1591 $cosTheta1 = cos($theta1);
1592 $sinTheta1 = sin($theta1);
1593 $theta2 = $theta1 +
$delta;
1594 $cosTheta2 = cos($theta2);
1595 $sinTheta2 = sin($theta2);
1597 // a) calculate endpoint of the segment:
1598 $xe = $cosPhi * $rx*$cosTheta2 - $sinPhi * $ry*$sinTheta2 +
$cx;
1599 $ye = $sinPhi * $rx*$cosTheta2 +
$cosPhi * $ry*$sinTheta2 +
$cy;
1601 // b) calculate gradients at start/end points of segment:
1602 $dx1 = $t * ( - $cosPhi * $rx*$sinTheta1 - $sinPhi * $ry*$cosTheta1);
1603 $dy1 = $t * ( - $sinPhi * $rx*$sinTheta1 +
$cosPhi * $ry*$cosTheta1);
1605 $dxe = $t * ( $cosPhi * $rx*$sinTheta2 +
$sinPhi * $ry*$cosTheta2);
1606 $dye = $t * ( $sinPhi * $rx*$sinTheta2 - $cosPhi * $ry*$cosTheta2);
1608 // c) draw the cubic bezier:
1609 $coords[$i] = array(($x1+
$dx1), ($y1+
$dy1), ($xe+
$dxe), ($ye+
$dye), $xe, $ye);
1617 foreach($coords AS $c) {
1624 $path .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', $cpx1*$this->kp
, -$cpy1*$this->kp
, $cpx2*$this->kp
, -$cpy2*$this->kp
, $x2*$this->kp
, -$y2*$this->kp
) ."\n";
1627 $bounds[0][] = $c[4];
1628 $bounds[1][] = $c[5];
1630 return array($path, $bounds); // mPD 5.0.040
1634 function CalcVectorAngle($ux, $uy, $vx, $vy) {
1635 $ta = atan2($uy, $ux);
1636 $tb = atan2($vy, $vx);
1639 return (6.28318530718 - ($ta-$tb));
1644 function ConvertSVGSizePixels($size=5,$maxsize='x'){
1645 // maxsize in pixels (user units) or 'y' or 'x'
1646 // e.g. $w = $this->ConvertSVGSizePixels($arguments['w'],$this->svg_info['w']*(25.4/$this->mpdf_ref->dpi));
1647 // usefontsize - setfalse for e.g. margins - will ignore fontsize for % values
1648 // Depends of maxsize value to make % work properly. Usually maxsize == pagewidth
1649 // For text $maxsize = Fontsize
1650 // Setting e.g. margin % will use maxsize (pagewidth) and em will use fontsize
1652 if ($maxsize == 'y') { $maxsize
= $this
->svg_info
['h']; }
1653 else if ($maxsize == 'x') { $maxsize
= $this
->svg_info
['w']; }
1654 $maxsize *= (25.4/$this->mpdf_ref
->dpi
); // convert pixels to mm
1655 $fontsize=$this->mpdf_ref
->FontSize
;
1657 $size = $this->mpdf_ref
->ConvertSize($size,$maxsize,$fontsize,false) * 1/(25.4/$this->mpdf_ref
->dpi
);
1662 function ConvertSVGSizePts($size=5){
1663 // usefontsize - setfalse for e.g. margins - will ignore fontsize for % values
1664 // Depends of maxsize value to make % work properly. Usually maxsize == pagewidth
1665 // For text $maxsize = Fontsize
1666 // Setting e.g. margin % will use maxsize (pagewidth) and em will use fontsize
1667 $maxsize=$this->mpdf_ref
->FontSize
;
1669 $size = $this->mpdf_ref
->ConvertSize($size,$maxsize,false,true) * 72/25.4;
1675 // fonction retracant les <rect />
1676 function svgRect($arguments){
1678 if ($arguments['h']==0 || $arguments['w']==0) { return ''; } // mPDF 4.4.003
1680 $x = $this->ConvertSVGSizePixels($arguments['x'],'x'); // mPDF 4.4.003
1681 $y = $this->ConvertSVGSizePixels($arguments['y'],'y'); // mPDF 4.4.003
1682 $h = $this->ConvertSVGSizePixels($arguments['h'],'y'); // mPDF 4.4.003
1683 $w = $this->ConvertSVGSizePixels($arguments['w'],'x'); // mPDF 4.4.003
1684 $rx = $this->ConvertSVGSizePixels($arguments['rx'],'x'); // mPDF 4.4.003
1685 $ry = $this->ConvertSVGSizePixels($arguments['ry'],'y'); // mPDF 4.4.003
1687 if ($rx > $w/2) { $rx
= $w
/2; } // mPDF 4.4.003
1688 if ($ry > $h/2) { $ry
= $h
/2; } // mPDF 4.4.003
1690 if ($rx>0 and $ry == 0){$ry
= $rx
;}
1691 if ($ry>0 and $rx == 0){$rx
= $ry
;}
1693 if ($rx == 0 and $ry == 0){
1694 // trace un rectangle sans angle arrondit
1695 $path_cmd = sprintf('%.3F %.3F m ', ($x*$this->kp
), -($y*$this->kp
));
1696 $path_cmd .= sprintf('%.3F %.3F l ', (($x+
$w)*$this->kp
), -($y*$this->kp
));
1697 $path_cmd .= sprintf('%.3F %.3F l ', (($x+
$w)*$this->kp
), -(($y+
$h)*$this->kp
));
1698 $path_cmd .= sprintf('%.3F %.3F l ', ($x)*$this->kp
, -(($y+
$h)*$this->kp
));
1699 $path_cmd .= sprintf('%.3F %.3F l h ', ($x*$this->kp
), -($y*$this->kp
));
1704 // trace un rectangle avec les arrondit
1705 // les points de controle du bezier sont deduis grace a la constante kappa
1706 $kappa = 4*(sqrt(2)-1)/3;
1711 $path_cmd = sprintf('%.3F %.3F m ', ($x+
$rx)*$this->kp
, -$y*$this->kp
);
1712 $path_cmd .= sprintf('%.3F %.3F l ', ($x+
($w-$rx))*$this->kp
, -$y*$this->kp
);
1713 $path_cmd .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', ($x+
($w-$rx+
$kx))*$this->kp
, -$y*$this->kp
, ($x+
$w)*$this->kp
, (-$y+
(-$ry+
$ky))*$this->kp
, ($x+
$w)*$this->kp
, (-$y+
(-$ry))*$this->kp
);
1714 $path_cmd .= sprintf('%.3F %.3F l ', ($x+
$w)*$this->kp
, (-$y+
(-$h+
$ry))*$this->kp
);
1715 $path_cmd .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', ($x+
$w)*$this->kp
, (-$y+
(-$h-$ky+
$ry))*$this->kp
, ($x+
($w-$rx+
$kx))*$this->kp
, (-$y+
(-$h))*$this->kp
, ($x+
($w-$rx))*$this->kp
, (-$y+
(-$h))*$this->kp
);
1717 $path_cmd .= sprintf('%.3F %.3F l ', ($x+
$rx)*$this->kp
, (-$y+
(-$h))*$this->kp
);
1718 $path_cmd .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', ($x+
($rx-$kx))*$this->kp
, (-$y+
(-$h))*$this->kp
, $x*$this->kp
, (-$y+
(-$h-$ky+
$ry))*$this->kp
, $x*$this->kp
, (-$y+
(-$h+
$ry))*$this->kp
);
1719 $path_cmd .= sprintf('%.3F %.3F l ', $x*$this->kp
, (-$y+
(-$ry))*$this->kp
);
1720 $path_cmd .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c h ', $x*$this->kp
, (-$y+
(-$ry+
$ky))*$this->kp
, ($x+
($rx-$kx))*$this->kp
, -$y*$this->kp
, ($x+
$rx)*$this->kp
, -$y*$this->kp
);
1728 // fonction retracant les <ellipse /> et <circle />
1729 // le cercle est tracé grave a 4 bezier cubic, les poitn de controles
1730 // sont deduis grace a la constante kappa * rayon
1731 function svgEllipse($arguments){
1732 if ($arguments['rx']==0 || $arguments['ry']==0) { return ''; } // mPDF 4.4.003
1734 $kappa = 4*(sqrt(2)-1)/3;
1736 $cx = $this->ConvertSVGSizePixels($arguments['cx'],'x'); // mPDF 4.4.003
1737 $cy = $this->ConvertSVGSizePixels($arguments['cy'],'y'); // mPDF 4.4.003
1738 $rx = $this->ConvertSVGSizePixels($arguments['rx'],'x'); // mPDF 4.4.003
1739 $ry = $this->ConvertSVGSizePixels($arguments['ry'],'y'); // mPDF 4.4.003
1753 $path_cmd = sprintf('%.3F %.3F m ', $x1*$this->kp
, $y1*$this->kp
);
1754 $path_cmd .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', ($x1+
($rx*$kappa))*$this->kp
, $y1*$this->kp
, $x2*$this->kp
, ($y2+
($ry*$kappa))*$this->kp
, $x2*$this->kp
, $y2*$this->kp
);
1755 $path_cmd .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', $x2*$this->kp
, ($y2-($ry*$kappa))*$this->kp
, ($x3+
($rx*$kappa))*$this->kp
, $y3*$this->kp
, $x3*$this->kp
, $y3*$this->kp
);
1756 $path_cmd .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', ($x3-($rx*$kappa))*$this->kp
, $y3*$this->kp
, $x4*$this->kp
, ($y4-($ry*$kappa))*$this->kp
, $x4*$this->kp
, $y4*$this->kp
);
1757 $path_cmd .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', $x4*$this->kp
, ($y4+
($ry*$kappa))*$this->kp
, ($x1-($rx*$kappa))*$this->kp
, $y1*$this->kp
, $x1*$this->kp
, $y1*$this->kp
);
1765 // fonction retracant les <polyline /> et les <line />
1766 function svgPolyline($arguments,$ispolyline=true){
1768 $xbase = $arguments[0] ;
1769 $ybase = - $arguments[1] ;
1772 if ($arguments[0]==$arguments[2] && $arguments[1]==$arguments[3]) { return ''; } // mPDF 4.4.003 Zero length line
1773 $xbase = $this->ConvertSVGSizePixels($arguments[0],'x'); // mPDF 4.4.003
1774 $ybase = - $this->ConvertSVGSizePixels($arguments[1],'y'); // mPDF 4.4.003
1776 $path_cmd = sprintf('%.3F %.3F m ', $xbase*$this->kp
, $ybase*$this->kp
);
1777 for ($i = 2; $i<count($arguments);$i +
= 2) {
1779 $tmp_x = $arguments[$i] ;
1780 $tmp_y = - $arguments[($i+
1)] ;
1783 $tmp_x = $this->ConvertSVGSizePixels($arguments[$i],'x') ; // mPDF 4.4.003
1784 $tmp_y = - $this->ConvertSVGSizePixels($arguments[($i+
1)],'y') ; // mPDF 4.4.003
1786 $path_cmd .= sprintf('%.3F %.3F l ', $tmp_x*$this->kp
, $tmp_y*$this->kp
);
1789 // $path_cmd .= 'h '; // ?? In error - don't close subpath here
1795 // fonction retracant les <polygone />
1796 function svgPolygon($arguments){
1797 $xbase = $arguments[0] ;
1798 $ybase = - $arguments[1] ;
1799 $path_cmd = sprintf('%.3F %.3F m ', $xbase*$this->kp
, $ybase*$this->kp
);
1800 for ($i = 2; $i<count($arguments);$i +
= 2) {
1801 $tmp_x = $arguments[$i] ;
1802 $tmp_y = - $arguments[($i+
1)] ;
1804 $path_cmd .= sprintf('%.3F %.3F l ', $tmp_x*$this->kp
, $tmp_y*$this->kp
);
1807 $path_cmd .= sprintf('%.3F %.3F l ', $xbase*$this->kp
, $ybase*$this->kp
);
1814 // write string to image
1815 function svgText() {
1816 // $tmp = count($this->txt_style)-1;
1817 $current_style = array_pop($this->txt_style
);
1820 if(isset($this->txt_data
[2]))
1823 $style .= ($current_style['font-weight'] == 'bold')?'B':'';
1824 $style .= ($current_style['font-style'] == 'italic')?'I':'';
1825 $size = $current_style['font-size']*$this->kf
; // mPDF 5.0.039
1828 $current_style['font-family'] = $this->mpdf_ref
->SetFont($current_style['font-family'],$style,$size,false);
1829 $this->mpdf_ref
->CurrentFont
['fo'] = true; // mPDF 5.0.039
1835 if (isset($current_style['fill-opacity'])) {
1836 if ($current_style['fill-opacity'] == 0) { $opacity
= 0; }
1837 else if ($current_style['fill-opacity'] > 1) { $opacity
= 1; }
1838 else if ($current_style['fill-opacity'] > 0) { $opacity
= $current_style
['fill-opacity']; }
1839 else if ($current_style['fill-opacity'] < 0) { $opacity
= 0; }
1841 $gs = $this->mpdf_ref
->AddExtGState(array('ca'=>$opacity, 'BM'=>'/Normal'));
1842 $this->mpdf_ref
->extgstates
[$gs]['fo'] = true; // mPDF 5.0.039
1843 $opacitystr = sprintf(' /GS%d gs ', $gs);
1847 if (isset($current_style['fill']) && $current_style['fill']!='none') {
1848 $col = $this->mpdf_ref
->ConvertColor($current_style['fill']);
1850 $fillstr = $this->mpdf_ref
->SetFColor($col, true);
1851 $render = "0"; // Fill (only)
1854 if (isset($current_style['stroke-width']) && $current_style['stroke-width']>0 && $current_style['stroke']!='none') {
1855 $scol = $this->mpdf_ref
->ConvertColor($current_style['stroke']);
1857 $strokestr .= $this->mpdf_ref
->SetDColor($scol, true).' '; // mPDF 5.0.051
1859 $linewidth = $this->ConvertSVGSizePixels($current_style['stroke-width']);
1860 if ($linewidth > 0) {
1861 $strokestr .= sprintf('%.3F w 1 J 1 j ',$linewidth*$this->kp
);
1862 if ($render == -1) { $render
= "1"; } // stroke only
1863 else { $render
= "2"; } // fill and stroke
1866 if ($render == -1) { return ''; }
1868 $x = $this->ConvertSVGSizePixels($this->txt_data
[0],'x'); // mPDF 4.4.003
1869 $y = $this->ConvertSVGSizePixels($this->txt_data
[1],'y'); // mPDF 4.4.003
1870 $txt = $this->txt_data
[2];
1873 $txt = preg_replace('/\f/','',$txt);
1874 $txt = preg_replace('/\r/','',$txt);
1875 $txt = preg_replace('/\n/',' ',$txt);
1876 $txt = preg_replace('/\t/',' ',$txt);
1877 $txt = preg_replace("/[ ]+/u",' ',$txt);
1881 $txt = $this->mpdf_ref
->purify_utf8_text($txt);
1882 if ($this->mpdf_ref
->text_input_as_HTML
) {
1883 $txt = $this->mpdf_ref
->all_entities_to_utf8($txt);
1887 if ($this->mpdf_ref
->usingCoreFont
) { $txt
= mb_convert_encoding($txt
,$this
->mpdf_ref
->mb_enc
,'UTF-8'); }
1888 if (preg_match("/([".$this->mpdf_ref
->pregRTLchars
."])/u", $txt)) { $this
->mpdf_ref
->biDirectional
= true; } // mPDF 4.4.003
1890 $this->mpdf_ref
->magic_reverse_dir($txt, true, 'ltr'); // mPDF 5.0.054
1891 $this->mpdf_ref
->ConvertIndic($txt);
1894 if ($current_style['text-anchor']=='middle') {
1895 $tw = $this->mpdf_ref
->GetStringWidth($txt)*_MPDFK
/2; // mPDF 4.4.003 // mPDF 5.4.09
1897 else if ($current_style['text-anchor']=='end') {
1898 $tw = $this->mpdf_ref
->GetStringWidth($txt)*_MPDFK
; // mPDF 4.4.003 // mPDF 5.4.09
1902 if (!$this->mpdf_ref
->usingCoreFont
) {
1903 $this->mpdf_ref
->UTF8StringToArray($txt); // mPDF 5.0 adds chars to subset list
1904 $txt= $this->mpdf_ref
->UTF8ToUTF16BE($txt, false);
1906 $txt='('.$this->mpdf_ref
->_escape($txt).')';
1907 $this->mpdf_ref
->CurrentFont
['used']= true;
1909 $pdfx = $x - $tw/$this->kp
; // mPDF 4.4.009
1915 $path_cmd = sprintf('q BT /F%d %.3F Tf %s %.3F %.3F Td %s Tr %s %s %s Tj ET Q ',$this->mpdf_ref
->CurrentFont
['i'], $this->mpdf_ref
->FontSizePt
, $opacitystr, $pdfx*$this->kp
,$pdfy*$this->kp
,$render,$fillstr,$strokestr,$txt)."\n";
1916 unset($this->txt_data
[0], $this->txt_data
[1],$this->txt_data
[2]);
1918 if (isset($current_style['font-size-parent'])) {
1919 $this->mpdf_ref
->SetFontSize($current_style['font-size-parent']);
1930 function svgDefineTxtStyle($critere_style)
1932 // get copy of current/default txt style, and modify it with supplied attributes
1933 $tmp = count($this->txt_style
)-1;
1934 $current_style = $this->txt_style
[$tmp];
1935 if (isset($critere_style['style'])){
1936 if (preg_match('/fill:\s*rgb\((\d+),\s*(\d+),\s*(\d+)\)/',$critere_style['style'], $m)) {
1937 $current_style['fill'] = '#'.str_pad(dechex($m[1]), 2, "0", STR_PAD_LEFT
).str_pad(dechex($m[2]), 2, "0", STR_PAD_LEFT
).str_pad(dechex($m[3]), 2, "0", STR_PAD_LEFT
);
1939 else { $tmp = preg_replace("/(.*)fill:\s*([a-z0-9#_()]*|none)(.*)/i","$2",$critere_style['style']);
1940 if ($tmp != $critere_style['style']){ $current_style['fill'] = $tmp; }
1943 $tmp = preg_replace("/(.*)fill
-opacity
:\s
*([a
-z0
-9.]*|none
)(.*)/i
","$2",$critere_style['style']);
1944 if ($tmp != $critere_style['style']){ $current_style
['fill-opacity'] = $tmp
;}
1946 $tmp = preg_replace("/(.*)fill-rule:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']);
1947 if ($tmp != $critere_style['style']){ $current_style['fill-rule'] = $tmp;}
1949 if (preg_match('/stroke:\s*rgb\((\d+),\s*(\d+),\s*(\d+)\)/',$critere_style['style'], $m)) {
1950 $current_style['stroke'] = '#'.str_pad(dechex($m[1]), 2, "0", STR_PAD_LEFT).str_pad(dechex($m[2]), 2, "0", STR_PAD_LEFT).str_pad(dechex($m[3]), 2, "0", STR_PAD_LEFT);
1952 else { $tmp = preg_replace("/(.*)stroke
:\s
*([a
-z0
-9#]*|none)(.*)/i","$2",$critere_style['style']);
1953 if ($tmp != $critere_style['style']){ $current_style
['stroke'] = $tmp
; }
1956 $tmp = preg_replace("/(.*)stroke-linecap:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']);
1957 if ($tmp != $critere_style['style']){ $current_style['stroke-linecap'] = $tmp;}
1959 $tmp = preg_replace("/(.*)stroke
-linejoin
:\s
*([a
-z0
-9#]*|none)(.*)/i","$2",$critere_style['style']);
1960 if ($tmp != $critere_style['style']){ $current_style
['stroke-linejoin'] = $tmp
;}
1962 $tmp = preg_replace("/(.*)stroke-miterlimit:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']);
1963 if ($tmp != $critere_style['style']){ $current_style['stroke-miterlimit'] = $tmp;}
1965 $tmp = preg_replace("/(.*)stroke
-opacity
:\s
*([a
-z0
-9.]*|none
)(.*)/i
","$2",$critere_style['style']);
1966 if ($tmp != $critere_style['style']){ $current_style
['stroke-opacity'] = $tmp
; }
1968 $tmp = preg_replace("/(.*)stroke-width:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']);
1969 if ($tmp != $critere_style['style']){ $current_style['stroke-width'] = $tmp;}
1971 $tmp = preg_replace("/(.*)stroke
-dasharray
:\s
*([a
-z0
-9., ]*|none
)(.*)/i
","$2",$critere_style['style']);
1972 if ($tmp != $critere_style['style']){ $current_style
['stroke-dasharray'] = $tmp
;}
1974 $tmp = preg_replace("/(.*)stroke-dashoffset:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']);
1975 if ($tmp != $critere_style['style']){ $current_style['stroke-dashoffset'] = $tmp;}
1978 $tmp = preg_replace("/(.*)font
-family
:\s
*([a
-z0
-9.\"' ,\-]*|none)(.*)/i","$2",$critere_style['style
']);
1979 if ($tmp != $critere_style['style
']){ $critere_style['font-family'] = $tmp;}
1981 $tmp = preg_replace("/(.*)font-size:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style
']);
1982 if ($tmp != $critere_style['style
']){ $critere_style['font-size'] = $tmp;}
1984 $tmp = preg_replace("/(.*)font-weight:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style
']);
1985 if ($tmp != $critere_style['style
']){ $critere_style['font-weight'] = $tmp;}
1987 $tmp = preg_replace("/(.*)font-style:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style
']);
1988 if ($tmp != $critere_style['style
']){ $critere_style['font-style'] = $tmp;}
1992 if (isset($critere_style['font
'])){
1994 // [ [ <'font
-style
'> || <'font
-variant
'> || <'font
-weight
'> ]?<'font
-size
'> [ / <'line
-height
'> ]? <'font
-family
'> ]
1996 $tmp = preg_replace("/(.*)(italic|oblique)(.*)/i","$2",$critere_style['font
']);
1997 if ($tmp != $critere_style['font
']){
1998 if($tmp == 'oblique
'){
2001 $current_style['font
-style
'] = $tmp;
2003 $tmp = preg_replace("/(.*)(bold|bolder)(.*)/i","$2",$critere_style['font
']);
2004 if ($tmp != $critere_style['font
']){
2005 if($tmp == 'bolder
'){
2008 $current_style['font
-weight
'] = $tmp;
2011 // select digits not followed by percent sign nor preceeded by forward slash
2012 $tmp = preg_replace("/(.*)\b(\d+)[\b|\/](.*)/i","$2",$critere_style['font
']);
2013 if ($tmp != $critere_style['font
']){
2014 $current_style['font
-size
'] = $this->ConvertSVGSizePts($tmp);
2015 $this->mpdf_ref->SetFont('','',$current_style['font
-size
'],false);
2020 if(isset($critere_style['fill
'])){
2021 $current_style['fill
'] = $critere_style['fill
'];
2023 if(isset($critere_style['stroke
'])){
2024 $current_style['stroke
'] = $critere_style['stroke
'];
2026 if(isset($critere_style['stroke
-width
'])){
2027 $current_style['stroke
-width
'] = $critere_style['stroke
-width
'];
2030 if(isset($critere_style['font
-style
'])){
2031 if(strtolower($critere_style['font
-style
']) == 'oblique
')
2033 $critere_style['font
-style
'] = 'italic
';
2035 $current_style['font
-style
'] = $critere_style['font
-style
'];
2038 if(isset($critere_style['font
-weight
'])){
2039 if(strtolower($critere_style['font
-weight
']) == 'bolder
')
2041 $critere_style['font
-weight
'] = 'bold
';
2043 $current_style['font
-weight
'] = $critere_style['font
-weight
'];
2046 if(isset($critere_style['font
-size
'])){
2048 if (strpos($critere_style['font
-size
'], '%
')!==false) {
2049 $current_style['font
-size
-parent
'] = $current_style['font
-size
'];
2051 $current_style['font
-size
'] = $this->ConvertSVGSizePts($critere_style['font
-size
']);
2052 $this->mpdf_ref->SetFont('','',$current_style['font
-size
'],false);
2055 if(isset($critere_style['font
-family
'])){
2056 $v = $critere_style['font
-family
'];
2057 $aux_fontlist = explode(",",$v);
2059 foreach($aux_fontlist AS $f) {
2060 $fonttype = trim($f);
2061 $fonttype = preg_replace('/["\']*(.*?)["\'
]*/
','\\
1',$fonttype);
2062 $fonttype = preg_replace('/ /','',$fonttype);
2063 $v = strtolower(trim($fonttype));
2064 if (isset($this->mpdf_ref->fonttrans[$v]) && $this->mpdf_ref->fonttrans[$v]) { $v = $this->mpdf_ref->fonttrans[$v]; }
2065 if ((!$this->mpdf_ref->usingCoreFont && in_array($v,$this->mpdf_ref->available_unifonts)) ||
2066 ($this->mpdf_ref->usingCoreFont && in_array($v,array('courier
','times
','helvetica
','arial
'))) ||
2067 in_array($v, array('sjis
','uhc
','big5
','gb
'))) {
2068 $current_style['font
-family
'] = $v;
2074 foreach($aux_fontlist AS $f) {
2075 $fonttype = trim($f);
2076 $fonttype = preg_replace('/["\']*(.*?)["\'
]*/
','\\
1',$fonttype);
2077 $fonttype = preg_replace('/ /','',$fonttype);
2078 $v = strtolower(trim($fonttype));
2079 if (isset($this->mpdf_ref->fonttrans[$v]) && $this->mpdf_ref->fonttrans[$v]) { $v = $this->mpdf_ref->fonttrans[$v]; }
2080 if (in_array($v,$this->mpdf_ref->sans_fonts) || in_array($v,$this->mpdf_ref->serif_fonts) || in_array($v,$this->mpdf_ref->mono_fonts) ) {
2081 $current_style['font
-family
'] = $v;
2088 if(isset($critere_style['text
-anchor
'])){
2089 $current_style['text
-anchor
'] = $critere_style['text
-anchor
'];
2092 // add current style to text style array (will remove it later after writing text to svg_string)
2093 array_push($this->txt_style,$current_style);
2099 // fonction ajoutant un gradient
2100 function svgAddGradient($id,$array_gradient){
2102 $this->svg_gradient[$id] = $array_gradient;
2106 // Ajoute une couleur dans le gradient correspondant
2109 // function ecrivant dans le svgstring
2110 function svgWriteString($content){
2112 $this->svg_string .= $content;
2118 // analise le svg et renvoie aux fonctions precedente our le traitement
2119 function ImageSVG($data){
2120 $this->svg_info = array();
2123 if (preg_match('/<!ENTITY
/si
',$data)) {
2124 // Get User-defined entities
2125 preg_match_all('/<!ENTITY\s+
([a
-z
]+
)\s+\"
(.*?)\">/si
',$data, $ent);
2127 for ($i=0; $i<count($ent[0]); $i++) {
2128 $data = preg_replace('/&'.preg_quote($ent[1][$i],'/').';/is
', $ent[2][$i], $data);
2133 if (preg_match('/xlink
:href
=/si
',$data)) {
2136 preg_match_all('/(<(linearGradient
|radialgradient
)[^
>]*)xlink
:href
=["\']#(.*?)["\'
](.*?)\
/>/si
',$data, $links);
2137 if (count($links[0])) { $links[5] = array(); }
2138 // Delete links from data - keeping in $links
2139 for ($i=0; $i<count($links[0]); $i++) {
2140 $links[5][$i] = 'tmpLink
'.RAND(100000,9999999);
2141 $data = preg_replace('/'.preg_quote($links[0][$i],'/').'/is
', '<MYLINKS
'.$links[5][$i].'>' , $data);
2144 preg_match_all('/<(linearGradient
|radialgradient
)([^
>]*)id
=["\'](.*?)["\'
](.*?)>(.*?)<\
/(linearGradient
|radialgradient
)>/si
',$data, $m);
2147 // keeping in $targets
2148 for ($i=0; $i<count($m[0]); $i++) {
2149 $stops[$m[3][$i]] = $m[5][$i];
2151 // Add back links this time as targets (gradients)
2152 for ($i=0; $i<count($links[0]); $i++) {
2153 $def = $links[1][$i] .' '.$links[4][$i].'>'. $stops[$links[3][$i]].'</'.$links[2][$i] .'>' ;
2154 $data = preg_replace('/<MYLINKS
'.$links[5][$i].'>/is
', $def , $data);
2159 preg_match_all('/<use ([^
>]*)xlink
:href
=["\']#([^>]*?)["\'
]([^
>]*)\
/>/si
',$data, $links);
2160 for ($i=0; $i<count($links[0]); $i++) {
2162 // Get the item to use from defs
2164 if (preg_match('/<([a
-zA
-Z
]*) [^
>]*id
=["\']'.$links[2][$i].'["\'
][^
>]*\
/>/si
',$data, $m)) {
2167 if (!$insert && preg_match('/<([a
-zA
-Z
]*) [^
>]*id
=["\']'.$links[2][$i].'["\'
]/si
',$data, $m)) {
2169 if (preg_match('/<'.$m[1].'[^
>]*id
=["\']'.$links[2][$i].'["\'
][^
>]*>.*?<\
/'.$m[1].'>/si
',$data, $m)) {
2176 $inners = $links[1][$i] . ' ' . $links[3][$i];
2177 // Change x,y coords to translate()
2178 if (preg_match('/y
=["\']([^>]*?)["\'
]/', $inners, $m)) { $y = $m[1]; }
2180 if (preg_match('/x
=["\']([^>]*?)["\'
]/', $inners, $m)) { $x = $m[1]; }
2183 $inners = preg_replace('/(y
|x
)=["\']([^>]*?)["\'
]/', '', $inners);
2184 if (preg_match('/transform
=["\']([^>]*?)["\'
]/', $inners, $m)) {
2185 if (preg_match('/translate\
(\s
*([0-9\
.]+
)\s
*,\s
*([0-9\
.]+
)\s
*\
)/', $m[1], $mm)) {
2186 $transform = $m[1]; // transform="...."
2189 $transform = preg_replace('/'.preg_quote($mm[0],'/').'/', '', $transform);
2190 $transform = 'transform
="'.$transform.' translate('.$x.', '.$y.')"';
2191 $inners = preg_replace('/'.preg_quote($m[0],'/').'/is
', $transform, $inners);
2194 $inners = preg_replace('/'.preg_quote($m[0],'/').'/is
', 'transform
="'.$m[1].' translate('.$x.', '.$y.')"', $inners);
2198 $inners .= ' transform
="translate('.$x.', '.$y.')"';
2202 $replacement = '<g
'.$inners.'>'.$insert.'</g
>';
2203 $data = preg_replace('/'.preg_quote($links[0][$i],'/').'/is
', $replacement, $data);
2205 preg_match_all('/<use ([^
>]*)xlink
:href
=["\']#([^>]*?)["\'
]([^
>]*)>\s
*<\
/use>/si
',$data, $links);
2206 for ($i=0; $i<count($links[0]); $i++) {
2208 // Get the item to use from defs
2210 if (preg_match('/<([a
-zA
-Z
]*) [^
>]*id
=["\']'.$links[2][$i].'["\'
][^
>]*\
/>/si
',$data, $m)) {
2213 if (!$insert && preg_match('/<([a
-zA
-Z
]*) [^
>]*id
=["\']'.$links[2][$i].'["\'
]/si
',$data, $m)) {
2215 if (preg_match('/<'.$m[1].'[^
>]*id
=["\']'.$links[2][$i].'["\'
][^
>]*>.*?<\
/'.$m[1].'>/si
',$data, $m)) {
2222 $inners = $links[1][$i] . ' ' . $links[3][$i];
2223 // Change x,y coords to translate()
2224 if (preg_match('/y
=["\']([^>]*?)["\'
]/', $inners, $m)) { $y = $m[1]; }
2226 if (preg_match('/x
=["\']([^>]*?)["\'
]/', $inners, $m)) { $x = $m[1]; }
2229 $inners = preg_replace('/(y
|x
)=["\']([^>]*?)["\'
]/', '', $inners);
2230 if (preg_match('/transform
=["\']([^>]*?)["\'
]/', $inners, $m)) {
2231 if (preg_match('/translate\
(\s
*([0-9\
.]+
)\s
*,\s
*([0-9\
.]+
)\s
*\
)/', $m[1], $mm)) {
2232 $transform = $m[1]; // transform="...."
2235 $transform = preg_replace('/'.preg_quote($mm[0],'/').'/', '', $transform);
2236 $transform = 'transform
="'.$transform.' translate('.$x.', '.$y.')"';
2237 $inners = preg_replace('/'.preg_quote($m[0],'/').'/is
', $transform, $inners);
2240 $inners = preg_replace('/'.preg_quote($m[0],'/').'/is
', 'transform
="'.$m[1].' translate('.$x.', '.$y.')"', $inners);
2244 $inners .= ' transform
="translate('.$x.', '.$y.')"';
2247 $replacement = '<g
'.$inners.'>'.$insert.'</g
>';
2248 $data = preg_replace('/'.preg_quote($links[0][$i],'/').'/is
', $replacement, $data);
2254 // Removes <pattern>
2255 $data = preg_replace('/<pattern
.*?<\
/pattern
>/is
', '', $data);
2257 $data = preg_replace('/<marker
.*?<\
/marker
>/is
', '', $data);
2259 $this->svg_info['data
'] = $data;
2261 $this->svg_string = '';
2264 // chargement unique des fonctions
2265 if(!function_exists("xml_svg2pdf_start")){
2267 function xml_svg2pdf_start($parser, $name, $attribs){
2270 global $svg_class, $last_gradid;
2273 if (strtolower($name) == 'lineargradient
'){
2274 $tmp_gradient = array(
2277 'x1
' => $attribs['x1
'],
2278 'y1
' => $attribs['y1
'],
2279 'x2
' => $attribs['x2
'],
2280 'y2
' => $attribs['y2
']
2282 'transform
' => $attribs['gradientTransform
'],
2283 'units
' => $attribs['gradientUnits
'],
2284 'spread
' => $attribs['spreadMethod
'],
2287 $last_gradid = $attribs['id
'];
2288 $svg_class->svgAddGradient($attribs['id
'],$tmp_gradient);
2291 else if (strtolower($name) == 'radialgradient
'){
2292 $tmp_gradient = array(
2295 'x0
' => $attribs['cx
'],
2296 'y0
' => $attribs['cy
'],
2297 'x1
' => $attribs['fx
'],
2298 'y1
' => $attribs['fy
'],
2299 'r
' => $attribs['r
']
2301 'transform
' => $attribs['gradientTransform
'],
2302 'units
' => $attribs['gradientUnits
'],
2303 'spread
' => $attribs['spreadMethod
'],
2306 $last_gradid = $attribs['id
'];
2307 $svg_class->svgAddGradient($attribs['id
'],$tmp_gradient);
2310 else if (strtolower($name) == 'stop
'){
2311 if (!$last_gradid) break;
2312 if (isset($attribs['style
']) AND preg_match('/stop
-color
:\s
*([^
;]*)/i
',$attribs['style
'],$m)) {
2313 $color = trim($m[1]);
2314 } else if (isset($attribs['stop
-color
'])) {
2315 $color = $attribs['stop
-color
'];
2317 $col = $svg_class->mpdf_ref->ConvertColor($color);
2319 if ($col{0}==3 || $col{0}==5) { // RGB
2320 $color_final = sprintf('%
.3F %
.3F %
.3F
',ord($col{1})/255,ord($col{2})/255,ord($col{3})/255);
2321 $svg_class->svg_gradient[$last_gradid]['colorspace
']='RGB
';
2323 else if ($col{0}==4 || $col{0}==6) { // CMYK
2324 $color_final = sprintf('%
.3F %
.3F %
.3F %
.3F
',ord($col{1})/100,ord($col{2})/100,ord($col{3})/100,ord($col{4})/100);
2325 $svg_class->svg_gradient[$last_gradid]['colorspace
']='CMYK
';
2327 else if ($col{0}==1) { // Grayscale
2328 $color_final = sprintf('%
.3F
',ord($col{1})/255);
2329 $svg_class->svg_gradient[$last_gradid]['colorspace
']='Gray
';
2333 if (isset($attribs['style
']) AND preg_match('/stop
-opacity
:\s
*([0-9.]*)/i
',$attribs['style
'],$m)) {
2334 $stop_opacity = $m[1];
2335 } else if (isset($attribs['stop
-opacity
'])) {
2336 $stop_opacity = $attribs['stop
-opacity
'];
2338 else if ($col{0}==5) { // RGBa
2339 $stop_opacity = ord($col{4}/100);
2341 else if ($col{0}==6) { // CMYKa
2342 $stop_opacity = ord($col{5}/100);
2346 'color
' => $color_final,
2347 'offset
' => $attribs['offset
'],
2348 'opacity
' => $stop_opacity
2350 array_push($svg_class->svg_gradient[$last_gradid]['color
'],$tmp_color);
2353 if ($svg_class->inDefs) { return; }
2355 $svg_class->xbase = 0;
2356 $svg_class->ybase = 0;
2357 switch (strtolower($name)){
2359 // mPDF 5.0.039 - Don't output stuff inside
<defs
>
2361 $svg_class->inDefs
= true;
2365 $svg_class->svgOffset($attribs);
2369 $path = $attribs['d'];
2371 preg_match_all('/([MZLHVCSQTAmzlhvcsqta])([eE ,\-.\d]+)*/', $path, $commands, PREG_SET_ORDER
);
2373 $svg_class->subPathInit
= true;
2375 $svg_class->pathBBox
= array(999999,999999,-999999,-999999);
2376 foreach($commands as $c){
2377 if(count($c)==3 || $c[2]==''){
2378 list($tmp, $command, $arguments) = $c;
2381 list($tmp, $command) = $c;
2385 $path_cmd .= $svg_class->svgPath($command, $arguments);
2388 if ($svg_class->pathBBox
[2]==-1999998) { $svg_class
->pathBBox
[2] = 100; }
2389 if ($svg_class->pathBBox
[3]==-1999998) { $svg_class
->pathBBox
[3] = 100; }
2390 if ($svg_class->pathBBox
[0]==999999) { $svg_class
->pathBBox
[0] = 0; }
2391 if ($svg_class->pathBBox
[1]==999999) { $svg_class
->pathBBox
[1] = 0; }
2392 $critere_style = $attribs;
2393 unset($critere_style['d']);
2394 $path_style = $svg_class->svgDefineStyle($critere_style);
2398 if (!isset($attribs['x'])) {$attribs
['x'] = 0;}
2399 if (!isset($attribs['y'])) {$attribs
['y'] = 0;}
2400 if (!isset($attribs['rx'])) {$attribs
['rx'] = 0;}
2401 if (!isset($attribs['ry'])) {$attribs
['ry'] = 0;}
2403 'x' => $attribs['x'],
2404 'y' => $attribs['y'],
2405 'w' => $attribs['width'],
2406 'h' => $attribs['height'],
2407 'rx' => $attribs['rx'],
2408 'ry' => $attribs['ry']
2410 $path_cmd = $svg_class->svgRect($arguments);
2411 $critere_style = $attribs;
2412 unset($critere_style['x'],$critere_style['y'],$critere_style['rx'],$critere_style['ry'],$critere_style['height'],$critere_style['width']);
2413 $path_style = $svg_class->svgDefineStyle($critere_style);
2417 if (!isset($attribs['cx'])) {$attribs
['cx'] = 0;}
2418 if (!isset($attribs['cy'])) {$attribs
['cy'] = 0;}
2420 'cx' => $attribs['cx'],
2421 'cy' => $attribs['cy'],
2422 'rx' => $attribs['r'],
2423 'ry' => $attribs['r']
2425 $path_cmd = $svg_class->svgEllipse($arguments);
2426 $critere_style = $attribs;
2427 unset($critere_style['cx'],$critere_style['cy'],$critere_style['r']);
2428 $path_style = $svg_class->svgDefineStyle($critere_style);
2432 if (!isset($attribs['cx'])) {$attribs
['cx'] = 0;}
2433 if (!isset($attribs['cy'])) {$attribs
['cy'] = 0;}
2435 'cx' => $attribs['cx'],
2436 'cy' => $attribs['cy'],
2437 'rx' => $attribs['rx'],
2438 'ry' => $attribs['ry']
2440 $path_cmd = $svg_class->svgEllipse($arguments);
2441 $critere_style = $attribs;
2442 unset($critere_style['cx'],$critere_style['cy'],$critere_style['rx'],$critere_style['ry']);
2443 $path_style = $svg_class->svgDefineStyle($critere_style);
2447 $arguments = array($attribs['x1'],$attribs['y1'],$attribs['x2'],$attribs['y2']);
2448 $path_cmd = $svg_class->svgPolyline($arguments,false); // mPDF 4.4.003
2449 $critere_style = $attribs;
2450 unset($critere_style['x1'],$critere_style['y1'],$critere_style['x2'],$critere_style['y2']);
2451 $path_style = $svg_class->svgDefineStyle($critere_style);
2455 $path = $attribs['points'];
2456 preg_match_all('/[0-9\-\.]*/',$path, $tmp, PREG_SET_ORDER
);
2457 $arguments = array();
2458 for ($i=0;$i<count($tmp);$i++
){
2459 if ($tmp[$i][0] !=''){
2460 array_push($arguments, $tmp[$i][0]);
2463 $path_cmd = $svg_class->svgPolyline($arguments);
2464 $critere_style = $attribs;
2465 unset($critere_style['points']);
2466 $path_style = $svg_class->svgDefineStyle($critere_style);
2470 $path = $attribs['points'];
2471 preg_match_all('/([\-]*[0-9\.]+)/',$path, $tmp);
2472 $arguments = array();
2473 for ($i=0;$i<count($tmp[0]);$i++
){
2474 if ($tmp[0][$i] !=''){
2475 array_push($arguments, $tmp[0][$i]);
2478 $path_cmd = $svg_class->svgPolygon($arguments);
2479 // definition du style de la forme:
2480 $critere_style = $attribs;
2481 unset($critere_style['points']);
2482 $path_style = $svg_class->svgDefineStyle($critere_style);
2486 if (isset($attribs['xlink:href'])) {
2487 unset($attribs['xlink:href']); // this should be a hyperlink
2488 // not handled like a xlink:href in other elements
2489 } // then continue like a <g>
2491 $array_style = $svg_class->svgDefineStyle($attribs);
2492 if ($array_style['transformations']) {
2493 $svg_class->svgWriteString(' q '.$array_style['transformations']);
2495 array_push($svg_class->svg_style
,$array_style);
2497 $svg_class->svgDefineTxtStyle($attribs); // mPDF 4.4.003
2502 $array_style = $svg_class->svgDefineStyle($attribs);
2503 if ($array_style['transformations']) {
2504 $svg_class->svgWriteString(' q '.$array_style['transformations']);
2506 array_push($svg_class->svg_style
,$array_style);
2508 $svg_class->txt_data
= array();
2509 $svg_class->txt_data
[0] = $attribs['x'];
2510 $svg_class->txt_data
[1] = $attribs['y'];
2511 $critere_style = $attribs;
2512 unset($critere_style['x'], $critere_style['y']);
2513 $svg_class->svgDefineTxtStyle($critere_style);
2518 //insertion des path et du style dans le flux de donné general.
2519 if (isset($path_cmd) && $path_cmd) { // mPDF 4.4.003
2521 list($prestyle,$poststyle) = $svg_class->svgStyle($path_style, $attribs, strtolower($name));
2522 if ($path_style['transformations']) { // transformation on an element
2523 $svg_class->svgWriteString(" q ".$path_style['transformations']. " $prestyle $path_cmd $poststyle" . " Q\n
");
2526 $svg_class->svgWriteString("$prestyle $path_cmd $poststyle\n");
2531 function characterData($parser, $data)
2534 if ($svg_class->inDefs) { return; } // mPDF 5.7.2
2535 if(isset($svg_class->txt_data[2])) {
2536 $svg_class->txt_data[2] .= $data;
2539 $svg_class->txt_data[2] = $data;
2544 function xml_svg2pdf_end($parser, $name){
2546 // Don't output stuff inside <defs>
2548 if ($name == 'defs') {
2549 $svg_class->inDefs = false;
2552 if ($svg_class->inDefs) { return; }
2557 $tmp = count($svg_class->svg_style)-1;
2558 $current_style = $svg_class->svg_style[$tmp];
2559 if ($current_style['transformations']) {
2560 $svg_class->svgWriteString(" Q\n
");
2562 array_pop($svg_class->svg_style);
2564 array_pop($svg_class->txt_style); // mPDF 4.4.003
2567 case 'radialgradient':
2568 case 'lineargradient':
2572 $path_cmd = $svg_class->svgText();
2573 // echo 'path >> '.$path_cmd."<br
><br
>";
2574 // echo "style
>> ".$get_style[1]."<br
><br
>";
2575 $svg_class->svgWriteString($path_cmd);
2577 $tmp = count($svg_class->svg_style)-1;
2578 $current_style = $svg_class->svg_style[$tmp];
2579 if ($current_style['transformations']) {
2580 $svg_class->svgWriteString(" Q\n
");
2582 array_pop($svg_class->svg_style);
2586 // mPDF 5.0.039 - Don't output stuff inside <defs>
2587 if ($name == 'defs') {
2588 $svg_class->inDefs = false;
2598 // mPDF 5.0.039 - Don't output stuff inside <defs>
2599 $svg_class->inDefs = false;
2600 $svg2pdf_xml_parser = xml_parser_create("utf
-8");
2601 xml_parser_set_option($svg2pdf_xml_parser, XML_OPTION_CASE_FOLDING, false);
2602 xml_set_element_handler($svg2pdf_xml_parser, "xml_svg2pdf_start
", "xml_svg2pdf_end
");
2603 xml_set_character_data_handler($svg2pdf_xml_parser, "characterData
");
2604 xml_parse($svg2pdf_xml_parser, $data);
2606 if ($this->svg_error) { return false; }
2608 return array('x'=>$this->svg_info['x']*$this->kp,'y'=>-$this->svg_info['y']*$this->kp,'w'=>$this->svg_info['w']*$this->kp,'h'=>-$this->svg_info['h']*$this->kp,'data'=>$svg_class->svg_string);
2619 function calc_bezier_bbox($start, $c) {
2620 $P0 = array($start[0],$start[1]);
2621 $P1 = array($c[0],$c[1]);
2622 $P2 = array($c[2],$c[3]);
2623 $P3 = array($c[4],$c[5]);
2625 $bounds[0][] = $P0[0];
2626 $bounds[1][] = $P0[1];
2627 $bounds[0][] = $P3[0];
2628 $bounds[1][] = $P3[1];
2629 for ($i=0;$i<=1;$i++) {
2630 $b = 6 * $P0[$i] - 12 * $P1[$i] + 6 * $P2[$i];
2631 $a = -3 * $P0[$i] + 9 * $P1[$i] - 9 * $P2[$i] + 3 * $P3[$i];
2632 $c = 3 * $P1[$i] - 3 * $P0[$i];
2634 if ($b == 0) { continue; }
2637 $bounds[$i][] = (pow((1-$t),3) * $P0[$i] + 3 * pow((1-$t),2) * $t * $P1[$i] + 3 * (1-$t) * pow($t,2) * $P2[$i] + pow($t,3) * $P3[$i]);
2641 $b2ac = pow($b, 2) - 4 * $c * $a;
2642 if ($b2ac < 0) { continue; }
2643 $t1 = (-$b + sqrt($b2ac))/(2 * $a);
2644 if ($t1>0 && $t1<1) {
2645 $bounds[$i][] = (pow((1-$t1),3) * $P0[$i] + 3 * pow((1-$t1),2) * $t1 * $P1[$i] + 3 * (1-$t1) * pow($t1,2) * $P2[$i] + pow($t1,3) * $P3[$i]);
2647 $t2 = (-$b - sqrt($b2ac))/(2 * $a);
2648 if ($t2>0 && $t2<1) {
2649 $bounds[$i][] = (pow((1-$t2),3) * $P0[$i] + 3 * pow((1-$t2),2) * $t2 * $P1[$i] + 3 * (1-$t2) * pow($t2,2) * $P2[$i] + pow($t2,3) * $P3[$i]);
2652 $x = min($bounds[0]);
2653 $x2 = max($bounds[0]);
2654 $y = min($bounds[1]);
2655 $y2 = max($bounds[1]);
2656 return array($x, $y, $x2, $y2);
2660 function _testIntersectCircle($cx, $cy, $cr) {
2661 // Tests whether a circle fully encloses a rectangle 0,0,1,1
2662 // to see if any further radial gradients need adding (SVG)
2663 // If centre of circle is inside 0,0,1,1 square
2664 if ($cx >= 0 && $cx <= 1 && $cy >= 0 && $cy <= 1) {
2667 // distance to four corners
2669 $d1 = sqrt(pow(($cy-0),2) + pow(($cx-0),2));
2670 $d2 = sqrt(pow(($cy-1),2) + pow(($cx-0),2));
2671 $d3 = sqrt(pow(($cy-0),2) + pow(($cx-1),2));
2672 $d4 = sqrt(pow(($cy-1),2) + pow(($cx-1),2));
2673 $maxd = max($d1,$d2,$d3,$d4);
2675 if ($cr < $maxd) { return true; }
2676 else { return false; }
2680 function _testIntersect($x1, $y1, $x2, $y2, $x3, $y3, $x4, $y4) {
2681 // Tests whether line (x1, y1) and (x2, y2) [a gradient axis (perpendicular)]
2682 // intersects with a specific line segment (x3, y3) and (x4, y4)
2685 $c1 = $a1*$x1+$b1*$y1;
2688 $c2 = $a2*$x3+$b2*$y3;
2689 $det = $a1*$b2 - $a2*$b1;
2690 if($det == 0){ //Lines are parallel
2694 $x = ($b2*$c1 - $b1*$c2)/$det;
2695 $y = ($a1*$c2 - $a2*$c1)/$det;
2696 if ($x >= $x3 && $x <= $x4 && $y >= $y3 && $y <= $y4) { return true; }