PageRenderTime 61ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/vendors/mpdf44/classes/svg.php

http://scp-soft.googlecode.com/
PHP | 1536 lines | 1178 code | 253 blank | 105 comment | 311 complexity | c967f7922067d633180f4a60ff35d2ae MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. // svg class modified for mPDF by Ian Back: based on -
  3. // svg2pdf fpdf class
  4. // sylvain briand (syb@godisaduck.com), modified by rick trevino (rtrevino1@yahoo.com)
  5. // http://www.godisaduck.com/svg2pdf_with_fpdf
  6. // http://rhodopsin.blogspot.com
  7. //
  8. // cette class etendue est open source, toute modification devra cependant etre repertoriée~
  9. class SVG {
  10. var $svg_gradient; // array - contient les infos sur les gradient fill du svg classé par id du svg
  11. var $svg_shadinglist; // array - contient les ids des objet shading
  12. var $svg_info; // array contenant les infos du svg voulue par l'utilisateur
  13. var $svg_attribs; // array - holds all attributes of root <svg> tag
  14. var $svg_style; // array contenant les style de groupes du svg
  15. var $svg_string; // String contenant le tracage du svg en lui m?me.
  16. var $txt_data; // array - holds string info to write txt to image
  17. var $txt_style; // array - current text style
  18. var $mpdf_ref;
  19. function SVG(&$mpdf){
  20. $this->svg_gradient = array();
  21. $this->svg_shadinglist = array();
  22. $this->txt_data = array();
  23. $this->svg_string = '';
  24. $this->svg_info = array();
  25. $this->svg_attribs = array();
  26. $this->mpdf_ref =& $mpdf;
  27. $this->svg_style = array(
  28. array(
  29. 'fill' => 'none', // pas de remplissage par defaut
  30. 'fill-opacity' => 1, // remplissage opaque par defaut
  31. 'fill-rule' => 'nonzero', // mode de remplissage par defaut
  32. 'stroke' => 'none', // pas de trait par defaut
  33. 'stroke-linecap' => 'butt', // style de langle par defaut
  34. 'stroke-linejoin' => 'miter', //
  35. 'stroke-miterlimit' => 4, // limite de langle par defaut
  36. 'stroke-opacity' => 1, // trait opaque par defaut
  37. 'stroke-width' => 0 // epaisseur du trait par defaut
  38. )
  39. );
  40. $this->txt_style = array(
  41. array(
  42. 'fill' => 'black', // pas de remplissage par defaut
  43. 'font-family' => $mpdf->default_font,
  44. 'font-size' => $mpdf->default_font_size, // ****** this is pts
  45. 'font-weight' => 'normal', // normal | bold
  46. 'font-style' => 'normal', // italic | normal
  47. 'text-anchor' => 'start' // alignment: start, middle, end
  48. )
  49. );
  50. }
  51. function svgGradient($gradient_info, $attribs, $element){
  52. $n = count($this->mpdf_ref->gradients)+1;
  53. // Get bounding dimensions of element
  54. $w = 100;
  55. $h = 100;
  56. $x_offset = 0;
  57. $y_offset = 0;
  58. if ($element=='rect') {
  59. $w = $attribs['width'];
  60. $h = $attribs['height'];
  61. $x_offset = $attribs['x'];
  62. $y_offset = $attribs['y'];
  63. }
  64. else if ($element=='ellipse') {
  65. $w = $attribs['rx']*2;
  66. $h = $attribs['ry']*2;
  67. $x_offset = $attribs['cx']-$attribs['rx'];
  68. $y_offset = $attribs['cy']-$attribs['ry'];
  69. }
  70. else if ($element=='circle') {
  71. $w = $attribs['r']*2;
  72. $h = $attribs['r']*2;
  73. $x_offset = $attribs['cx']-$attribs['r'];
  74. $y_offset = $attribs['cy']-$attribs['r'];
  75. }
  76. else if ($element=='polygon') {
  77. $pts = preg_split('/[ ,]+/', trim($attribs['points']));
  78. $maxr=$maxb=0;
  79. $minl=$mint=999999;
  80. for ($i=0;$i<count($pts); $i++) {
  81. if ($i % 2 == 0) { // x values
  82. $minl = min($minl,$pts[$i]);
  83. $maxr = max($maxr,$pts[$i]);
  84. }
  85. else { // y values
  86. $mint = min($mint,$pts[$i]);
  87. $maxb = max($maxb,$pts[$i]);
  88. }
  89. }
  90. $w = $maxr-$minl;
  91. $h = $maxb-$mint;
  92. $x_offset = $minl;
  93. $y_offset = $mint;
  94. }
  95. else if ($element=='path') {
  96. preg_match_all('/([a-z]|[A-Z])([ ,\-.\d]+)*/', $attribs['d'], $commands, PREG_SET_ORDER);
  97. $maxr=$maxb=0;
  98. $minl=$mint=999999;
  99. foreach($commands as $c){
  100. if(count($c)==3){
  101. list($tmp, $cmd, $arg) = $c;
  102. if ($cmd=='M' || $cmd=='L' || $cmd=='C' || $cmd=='S' || $cmd=='Q' || $cmd=='T') {
  103. $pts = preg_split('/[ ,]+/', trim($arg));
  104. for ($i=0;$i<count($pts); $i++) {
  105. if ($i % 2 == 0) { // x values
  106. $minl = min($minl,$pts[$i]);
  107. $maxr = max($maxr,$pts[$i]);
  108. }
  109. else { // y values
  110. $mint = min($mint,$pts[$i]);
  111. $maxb = max($maxb,$pts[$i]);
  112. }
  113. }
  114. }
  115. if ($cmd=='H') { // sets new x
  116. $minl = min($minl,$arg);
  117. $maxr = max($maxr,$arg);
  118. }
  119. if ($cmd=='V') { // sets new y
  120. $mint = min($mint,$arg);
  121. $maxb = max($maxb,$arg);
  122. }
  123. }
  124. }
  125. $w = $maxr-$minl;
  126. $h = $maxb-$mint;
  127. $x_offset = $minl;
  128. $y_offset = $mint;
  129. }
  130. if (!$w) { $w = 100; }
  131. if (!$h) { $h = 100; }
  132. if ($x_offset==999999) { $x_offset = 0; }
  133. if ($y_offset==999999) { $y_offset = 0; }
  134. $return = "";
  135. if ($gradient_info['type'] == 'linear'){
  136. $this->mpdf_ref->gradients[$n]['type'] = 2;
  137. if (isset($gradient_info['info']['x1'])) { $x1 = $gradient_info['info']['x1']; }
  138. else { $x1 = 0; }
  139. if (isset($gradient_info['info']['y1'])) { $y1 = $gradient_info['info']['y1']; }
  140. else { $y1 = 0; }
  141. if (isset($gradient_info['info']['x2'])) { $x2 = $gradient_info['info']['x2']; }
  142. else { $x2 = 1; }
  143. if (isset($gradient_info['info']['y2'])) { $y2 = $gradient_info['info']['y2']; }
  144. else { $y2 = 0; }
  145. if (stristr($x1, '%')!== false) { $x1 = ($x1+0)/100; }
  146. if (stristr($x2, '%')!== false) { $x2 = ($x2+0)/100; }
  147. if (stristr($y1, '%')!== false) { $y1 = ($y1+0)/100; }
  148. if (stristr($y2, '%')!== false) { $y2 = ($y2+0)/100; }
  149. $this->mpdf_ref->gradients[$n]['coords']=array($x1, $y1, $x2, $y2);
  150. $a = $w; // width
  151. $b = 0;
  152. $c = 0;
  153. $d = -$h; // height
  154. $e = $x_offset; // x- offset
  155. $f = -$y_offset; // -y-offset
  156. $return .= sprintf('%.3f %.3f %.3f %.3f %.3f %.3f cm ', $a, $b, $c, $d, $e, $f);
  157. $this->mpdf_ref->gradients[$n]['col1'] = $gradient_info['color'][0]['color'];
  158. $this->mpdf_ref->gradients[$n]['col2'] = $gradient_info['color'][(count($gradient_info['color'])-1)]['color'];
  159. }
  160. else if ($gradient_info['type'] == 'radial'){
  161. $this->mpdf_ref->gradients[$n]['type'] = 3;
  162. $a = $w; // width
  163. $b = 0;
  164. $c = 0;
  165. $d = -$h; // -height
  166. $e = $x_offset; // x- offset
  167. $f = -$y_offset; // -y-offset
  168. $return .= sprintf('%.3f %.3f %.3f %.3f %.3f %.3f cm ', $a, $b, $c, $d, $e, $f);
  169. if ($gradient_info['info']['x0'] || $gradient_info['info']['x0']===0) { $x0 = $gradient_info['info']['x0']; }
  170. else { $x0 = 0.5; }
  171. if ($gradient_info['info']['y0'] || $gradient_info['info']['y0']===0) { $y0 = $gradient_info['info']['y0']; }
  172. else { $y0 = 0.5; }
  173. if ($gradient_info['info']['r'] || $gradient_info['info']['r']===0) { $r = $gradient_info['info']['r']; }
  174. else { $r = 0.5; }
  175. if ($gradient_info['info']['x1'] || $gradient_info['info']['x1']===0) { $x1 = $gradient_info['info']['x1']; }
  176. else { $x1 = $x0; }
  177. if ($gradient_info['info']['y1'] || $gradient_info['info']['y1']===0) { $y1 = $gradient_info['info']['y1']; }
  178. else { $y1 = $y0; }
  179. if (stristr($x1, '%')!== false) { $x1 = ($x1+0)/100; }
  180. if (stristr($x0, '%')!== false) { $x0 = ($x0+0)/100; }
  181. if (stristr($y1, '%')!== false) { $y1 = ($y1+0)/100; }
  182. if (stristr($y0, '%')!== false) { $y0 = ($y0+0)/100; }
  183. if (stristr($r, '%')!== false) { $r = ($r+0)/100; }
  184. // x1 and y1 (fx, fy) should be inside the circle defined by x0 y0 and r else error in mPDF
  185. while (pow(($x1-$x0),2) + pow(($y1 - $y0),2) >= pow($r,2)) { $r += 0.05; }
  186. $this->mpdf_ref->gradients[$n]['coords']=array( $x1, $y1, $x0, $y0, abs($r) );
  187. $this->mpdf_ref->gradients[$n]['col1'] = $gradient_info['color'][0]['color'];
  188. $this->mpdf_ref->gradients[$n]['col2'] = $gradient_info['color'][(count($gradient_info['color'])-1)]['color'];
  189. }
  190. $this->mpdf_ref->gradients[$n]['extend']=array('true','true');
  191. /* Only uses 2 colours for mPDF
  192. $this->mpdf_ref->gradients[$n]['color'] = array();
  193. $n_color = count($gradient_info['color']);
  194. for ($i = 0;$i<$n_color;$i++){
  195. $color = array (
  196. 'color' => $gradient_info['color'][$i]['color'],
  197. 'offset' => $gradient_info['color'][$i]['offset'],
  198. 'opacity' => $gradient_info['color'][$i]['opacity']
  199. );
  200. array_push($this->mpdf_ref->gradients[$n]['color'],$color);
  201. }
  202. */
  203. $return .= '/Sh'.count($this->mpdf_ref->gradients).' sh Q ';
  204. return $return;
  205. }
  206. function svgOffset ($attribs){
  207. // save all <svg> tag attributes
  208. $this->svg_attribs = $attribs;
  209. if(isset($this->svg_attribs['viewBox'])) {
  210. $vb = preg_split('/\s+/is', trim($this->svg_attribs['viewBox']));
  211. if (count($vb)==4) {
  212. $this->svg_info['x'] = $vb[0];
  213. $this->svg_info['y'] = $vb[1];
  214. $this->svg_info['w'] = $vb[2];
  215. $this->svg_info['h'] = $vb[3];
  216. return;
  217. }
  218. }
  219. $svg_w = $this->mpdf_ref->ConvertSize($attribs['width']); // mm (interprets numbers as pixels)
  220. $svg_h = $this->mpdf_ref->ConvertSize($attribs['height']); // mm
  221. // Added to handle file without height or width specified
  222. if (!$svg_w && !$svg_h) { $svg_w = $svg_h = $this->mpdf_ref->blk[$this->mpdf_ref->blklvl]['inner_width'] ; } // DEFAULT
  223. if (!$svg_w) { $svg_w = $svg_h; }
  224. if (!$svg_h) { $svg_h = $svg_w; }
  225. $this->svg_info['x'] = 0;
  226. $this->svg_info['y'] = 0;
  227. $this->svg_info['w'] = $svg_w/0.2645; // mm->pixels
  228. $this->svg_info['h'] = $svg_h/0.2645; // mm->pixels
  229. }
  230. //
  231. // check if points are within svg, if not, set to max
  232. function svg_overflow($x,$y)
  233. {
  234. $x2 = $x;
  235. $y2 = $y;
  236. if(isset($this->svg_attribs['overflow']))
  237. {
  238. if($this->svg_attribs['overflow'] == 'hidden')
  239. {
  240. // Not sure if this is supposed to strip off units, but since I dont use any I will omlt this step
  241. $svg_w = preg_replace("/([0-9\.]*)(.*)/i","$1",$this->svg_attribs['width']);
  242. $svg_h = preg_replace("/([0-9\.]*)(.*)/i","$1",$this->svg_attribs['height']);
  243. // $xmax = floor($this->svg_attribs['width']);
  244. $xmax = floor($svg_w);
  245. $xmin = 0;
  246. // $ymax = floor(($this->svg_attribs['height'] * -1));
  247. $ymax = floor(($svg_h * -1));
  248. $ymin = 0;
  249. if($x > $xmax) $x2 = $xmax; // right edge
  250. if($x < $xmin) $x2 = $xmin; // left edge
  251. if($y < $ymax) $y2 = $ymax; // bottom
  252. if($y > $ymin) $y2 = $ymin; // top
  253. }
  254. }
  255. return array( 'x' => $x2, 'y' => $y2);
  256. }
  257. function svgDefineStyle($critere_style){
  258. $tmp = count($this->svg_style)-1;
  259. $current_style = $this->svg_style[$tmp];
  260. unset($current_style['transformations']);
  261. // TRANSFORM SCALE
  262. $transformations = '';
  263. if (isset($critere_style['transform'])){
  264. preg_match_all('/(matrix|translate|scale|rotate|skewX|skewY)\((.*?)\)/is',$critere_style['transform'],$m);
  265. if (count($m[0])) {
  266. for($i=0; $i<count($m[0]); $i++) {
  267. $c = strtolower($m[1][$i]);
  268. $v = trim($m[2][$i]);
  269. $vv = preg_split('/[ ,]+/',$v);
  270. if ($c=='matrix' && count($vv)==6) {
  271. $transformations .= sprintf(' %.3f %.3f %.3f %.3f %.3f %.3f cm ', $vv[0], $vv[1], $vv[2], $vv[3], $vv[4], $vv[5]);
  272. }
  273. else if ($c=='translate' && count($vv)) {
  274. $tm[4] = $vv[0];
  275. if (count($vv)==2) { $t_y = -$vv[1]; }
  276. else { $t_y = 0; }
  277. $tm[5] = $t_y;
  278. $transformations .= sprintf(' 1 0 0 1 %.3f %.3f cm ', $tm[4], $tm[5]);
  279. }
  280. else if ($c=='scale' && count($vv)) {
  281. if (count($vv)==2) { $s_y = $vv[1]; }
  282. else { $s_y = $vv[0]; }
  283. $tm[0] = $vv[0];
  284. $tm[3] = $s_y;
  285. $transformations .= sprintf(' %.3f 0 0 %.3f 0 0 cm ', $tm[0], $tm[3]);
  286. }
  287. else if ($c=='rotate' && count($vv)) {
  288. $tm[0] = cos(deg2rad(-$vv[0]));
  289. $tm[1] = sin(deg2rad(-$vv[0]));
  290. $tm[2] = -$tm[1];
  291. $tm[3] = $tm[0];
  292. if (count($vv)==3) {
  293. $transformations .= sprintf(' 1 0 0 1 %.3f %.3f cm ', $vv[1], -$vv[2]);
  294. }
  295. $transformations .= sprintf(' %.3f %.3f %.3f %.3f 0 0 cm ', $tm[0], $tm[1], $tm[2], $tm[3]);
  296. if (count($vv)==3) {
  297. $transformations .= sprintf(' 1 0 0 1 %.3f %.3f cm ', -$vv[1], $vv[2]);
  298. }
  299. }
  300. else if ($c=='skewx' && count($vv)) {
  301. $tm[2] = tan(deg2rad(-$vv[0]));
  302. $transformations .= sprintf(' 1 0 %.3f 1 0 0 cm ', $tm[2]);
  303. }
  304. else if ($c=='skewy' && count($vv)) {
  305. $tm[1] = tan(deg2rad(-$vv[0]));
  306. $transformations .= sprintf(' 1 %.3f 0 1 0 0 cm ', $tm[1]);
  307. }
  308. }
  309. }
  310. $current_style['transformations'] = $transformations;
  311. }
  312. if (isset($critere_style['style'])){
  313. if (preg_match('/fill:\s*rgb\((\d+),\s*(\d+),\s*(\d+)\)/',$critere_style['style'], $m)) {
  314. $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);
  315. }
  316. else { $tmp = preg_replace("/(.*)fill:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']);
  317. if ($tmp != $critere_style['style']){ $current_style['fill'] = $tmp; }
  318. }
  319. $tmp = preg_replace("/(.*)fill-opacity:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']);
  320. if ($tmp != $critere_style['style']){ $current_style['fill-opacity'] = $tmp;}
  321. $tmp = preg_replace("/(.*)fill-rule:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']);
  322. if ($tmp != $critere_style['style']){ $current_style['fill-rule'] = $tmp;}
  323. if (preg_match('/stroke:\s*rgb\((\d+),\s*(\d+),\s*(\d+)\)/',$critere_style['style'], $m)) {
  324. $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);
  325. }
  326. else { $tmp = preg_replace("/(.*)stroke:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']);
  327. if ($tmp != $critere_style['style']){ $current_style['stroke'] = $tmp; }
  328. }
  329. $tmp = preg_replace("/(.*)stroke-linecap:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']);
  330. if ($tmp != $critere_style['style']){ $current_style['stroke-linecap'] = $tmp;}
  331. $tmp = preg_replace("/(.*)stroke-linejoin:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']);
  332. if ($tmp != $critere_style['style']){ $current_style['stroke-linejoin'] = $tmp;}
  333. $tmp = preg_replace("/(.*)stroke-miterlimit:\s*([a-z0-9#]*|none)(.*)/i","$2",$critere_style['style']);
  334. if ($tmp != $critere_style['style']){ $current_style['stroke-miterlimit'] = $tmp;}
  335. $tmp = preg_replace("/(.*)stroke-opacity:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']);
  336. if ($tmp != $critere_style['style']){ $current_style['stroke-opacity'] = $tmp; }
  337. $tmp = preg_replace("/(.*)stroke-width:\s*([a-z0-9.]*|none)(.*)/i","$2",$critere_style['style']);
  338. if ($tmp != $critere_style['style']){ $current_style['stroke-width'] = $tmp;}
  339. }
  340. if(isset($critere_style['fill'])){
  341. $current_style['fill'] = $critere_style['fill'];
  342. }
  343. if(isset($critere_style['fill-opacity'])){
  344. $current_style['fill-opacity'] = $critere_style['fill-opacity'];
  345. }
  346. if(isset($critere_style['fill-rule'])){
  347. $current_style['fill-rule'] = $critere_style['fill-rule'];
  348. }
  349. if(isset($critere_style['stroke'])){
  350. $current_style['stroke'] = $critere_style['stroke'];
  351. }
  352. if(isset($critere_style['stroke-linecap'])){
  353. $current_style['stroke-linecap'] = $critere_style['stroke-linecap'];
  354. }
  355. if(isset($critere_style['stroke-linejoin'])){
  356. $current_style['stroke-linejoin'] = $critere_style['stroke-linejoin'];
  357. }
  358. if(isset($critere_style['stroke-miterlimit'])){
  359. $current_style['stroke-miterlimit'] = $critere_style['stroke-miterlimit'];
  360. }
  361. if(isset($critere_style['stroke-opacity'])){
  362. $current_style['stroke-opacity'] = $critere_style['stroke-opacity'];
  363. }
  364. if(isset($critere_style['stroke-width'])){
  365. $current_style['stroke-width'] = $critere_style['stroke-width'];
  366. }
  367. return $current_style;
  368. }
  369. //
  370. // Cette fonction ecrit le style dans le stream svg.
  371. function svgStyle($critere_style, $attribs, $element){
  372. $path_style = '';
  373. if (substr_count($critere_style['fill'],'url')>0){
  374. //
  375. // couleur degradé
  376. $id_gradient = preg_replace("/url\(#([\w_]*)\)/i","$1",$critere_style['fill']);
  377. if ($id_gradient != $critere_style['fill']) {
  378. $fill_gradient = $this->svgGradient($this->svg_gradient[$id_gradient], $attribs, $element);
  379. $path_style = "q ";
  380. $w = "W";
  381. $style .= 'N';
  382. }
  383. }
  384. else if ($critere_style['fill'] != 'none'){
  385. // fill couleur pleine
  386. $col = $this->mpdf_ref->ConvertColor($critere_style['fill']);
  387. if ($col) {
  388. $path_style .= sprintf('%.3f %.3f %.3f rg ',$col['R']/255,$col['G']/255,$col['B']/255);
  389. $style .= 'F';
  390. }
  391. }
  392. if ($critere_style['stroke'] != 'none'){
  393. $col = $this->mpdf_ref->ConvertColor($critere_style['stroke']);
  394. if ($col) {
  395. $path_style .= sprintf('%.3f %.3f %.3f RG ',$col['R']/255,$col['G']/255,$col['B']/255);
  396. $style .= 'D';
  397. $path_style .= sprintf('%.3f w ',$critere_style['stroke-width']);
  398. }
  399. }
  400. if ($critere_style['stroke'] != 'none'){
  401. if ($critere_style['stroke-linejoin'] == 'miter'){
  402. $path_style .= ' 0 j ';
  403. }
  404. else if ($critere_style['stroke-linejoin'] == 'round'){
  405. $path_style .= ' 1 j ';
  406. }
  407. else if ($critere_style['stroke-linejoin'] == 'bevel'){
  408. $path_style .= ' 2 j ';
  409. }
  410. if ($critere_style['stroke-linecap'] == 'butt'){
  411. $path_style .= ' 0 J ';
  412. }
  413. else if ($critere_style['stroke-linecap'] == 'round'){
  414. $path_style .= ' 1 J ';
  415. }
  416. else if ($critere_style['stroke-linecap'] == 'square'){
  417. $path_style .= ' 2 J ';
  418. }
  419. if (isset($critere_style['stroke-miterlimit'])){
  420. $path_style .= sprintf('%.2f M ',$critere_style['stroke-miterlimit']);
  421. }
  422. }
  423. if ($critere_style['fill-opacity'] > 0 && $critere_style['fill-opacity'] <= 1){
  424. $gs = $this->mpdf_ref->AddExtGState(array('ca'=>$critere_style['fill-opacity'], 'BM'=>'/Normal'));
  425. $path_style .= sprintf(' /GS%d gs ', $gs);
  426. }
  427. if ($critere_style['stroke-opacity'] > 0 && $critere_style['stroke-opacity'] <= 1){
  428. $gs = $this->mpdf_ref->AddExtGState(array('CA'=>$critere_style['stroke-opacity'], 'BM'=>'/Normal'));
  429. $path_style .= sprintf(' /GS%d gs ', $gs);
  430. }
  431. switch ($style){
  432. case 'F':
  433. $op = 'f';
  434. break;
  435. case 'FD':
  436. $op = 'B';
  437. break;
  438. case 'ND':
  439. $op = 'S';
  440. break;
  441. case 'D':
  442. $op = 'S';
  443. break;
  444. default:
  445. $op = 'n';
  446. }
  447. $final_style = "$path_style $w $op $fill_gradient \n";
  448. // echo 'svgStyle: '. $final_style .'<br><br>';
  449. return $final_style;
  450. }
  451. //
  452. // fonction retracant les <path />
  453. function svgPath($command, $arguments){
  454. global $xbase, $ybase;
  455. $path_cmd = '';
  456. preg_match_all('/[\-^]?[\d.]+/', $arguments, $a, PREG_SET_ORDER);
  457. // if the command is a capital letter, the coords go absolute, otherwise relative
  458. if(strtolower($command) == $command) $relative = true;
  459. else $relative = false;
  460. $ile_argumentow = count($a);
  461. // each command may have different needs for arguments [1 to 8]
  462. switch(strtolower($command)){
  463. case 'm': // move
  464. for($i = 0; $i<$ile_argumentow; $i+=2){
  465. $x = $a[$i][0];
  466. $y = $a[$i+1][0];
  467. if($relative){
  468. $pdfx = ($xbase + $x);
  469. $pdfy = ($ybase - $y);
  470. $xbase += $x;
  471. $ybase += -$y;
  472. }
  473. else{
  474. $pdfx = $x;
  475. $pdfy = -$y ;
  476. $xbase = $x;
  477. $ybase = -$y;
  478. }
  479. $pdf_pt = $this->svg_overflow($pdfx,$pdfy);
  480. if($i == 0) $path_cmd .= sprintf('%.3f %.3f m ', $pdf_pt['x'], $pdf_pt['y']);
  481. else $path_cmd .= sprintf('%.3f %.3f l ', $pdf_pt['x'], $pdf_pt['y']);
  482. }
  483. break;
  484. case 'l': // a simple line
  485. for($i = 0; $i<$ile_argumentow; $i+=2){
  486. $x = ($a[$i][0]);
  487. $y = ($a[$i+1][0]);
  488. if($relative){
  489. $pdfx = ($xbase + $x);
  490. $pdfy = ($ybase - $y);
  491. $xbase += $x;
  492. $ybase += -$y;
  493. }
  494. else{
  495. $pdfx = $x ;
  496. $pdfy = -$y ;
  497. $xbase = $x;
  498. $ybase = -$y;
  499. }
  500. $pdf_pt = $this->svg_overflow($pdfx,$pdfy);
  501. $path_cmd .= sprintf('%.3f %.3f l ', $pdf_pt['x'], $pdf_pt['y']);
  502. }
  503. break;
  504. case 'h': // a very simple horizontal line
  505. for($i = 0; $i<$ile_argumentow; $i++){
  506. $x = ($a[$i][0]);
  507. if($relative){
  508. $y = 0;
  509. $pdfx = ($xbase + $x) ;
  510. $pdfy = ($ybase - $y) ;
  511. $xbase += $x;
  512. $ybase += -$y;
  513. }
  514. else{
  515. $y = -$ybase;
  516. $pdfx = $x;
  517. $pdfy = -$y;
  518. $xbase = $x;
  519. $ybase = -$y;
  520. }
  521. $pdf_pt = $this->svg_overflow($pdfx,$pdfy);
  522. $path_cmd .= sprintf('%.3f %.3f l ', $pdf_pt['x'], $pdf_pt['y']);
  523. }
  524. break;
  525. case 'v': // the simplest line, vertical
  526. for($i = 0; $i<$ile_argumentow; $i++){
  527. $y = ($a[$i][0]);
  528. if($relative){
  529. $x = 0;
  530. $pdfx = ($xbase + $x);
  531. $pdfy = ($ybase - $y);
  532. $xbase += $x;
  533. $ybase += -$y;
  534. }
  535. else{
  536. $x = $xbase;
  537. $pdfx = $x;
  538. $pdfy = -$y;
  539. $xbase = $x;
  540. $ybase = -$y;
  541. }
  542. $pdf_pt = $this->svg_overflow($pdfx,$pdfy);
  543. $path_cmd .= sprintf('%.3f %.3f l ', $pdf_pt['x'], $pdf_pt['y']);
  544. }
  545. break;
  546. case 's': // bezier with first vertex equal first control
  547. if ($this->lastcommand == 'C' || $this->lastcommand == 'c') {
  548. for($i = 0; $i<$ile_argumentow; $i += 4){
  549. $x1 = $this->lastcontrolpoints[0];
  550. $y1 = $this->lastcontrolpoints[1];
  551. $x2 = ($a[$i][0]);
  552. $y2 = ($a[$i+1][0]);
  553. $x = ($a[$i+2][0]);
  554. $y = ($a[$i+3][0]);
  555. if($relative){
  556. $pdfx1 = ($xbase + $x1);
  557. $pdfy1 = ($ybase - $y1);
  558. $pdfx2 = ($xbase + $x2);
  559. $pdfy2 = ($ybase - $y2);
  560. $pdfx = ($xbase + $x);
  561. $pdfy = ($ybase - $y);
  562. $xbase += $x;
  563. $ybase += -$y;
  564. }
  565. else{
  566. $pdfx1 = $xbase + $x1;
  567. $pdfy1 = $ybase -$y1;
  568. $pdfx2 = $x2;
  569. $pdfy2 = -$y2;
  570. $pdfx = $x;
  571. $pdfy = -$y;
  572. $xbase = $x;
  573. $ybase = -$y;
  574. }
  575. $this->lastcontrolpoints = array(($x-$x1),($y-$y1));
  576. // $pdf_pt2 = $this->svg_overflow($pdfx2,$pdfy2);
  577. // $pdf_pt1 = $this->svg_overflow($pdfx1,$pdfy1);
  578. $pdf_pt = $this->svg_overflow($pdfx,$pdfy);
  579. if( ($pdf_pt['x'] != $pdfx) || ($pdf_pt['y'] != $pdfy) )
  580. {
  581. $path_cmd .= sprintf('%.3f %.3f l ', $pdf_pt['x'], $pdf_pt['y']);
  582. }
  583. else
  584. {
  585. $path_cmd .= sprintf('%.3f %.3f %.3f %.3f %.3f %.3f c ', $pdfx1, $pdfy1, $pdfx2, $pdfy2, $pdfx, $pdfy);
  586. }
  587. }
  588. }
  589. break;
  590. case 'c': // bezier with second vertex equal second control
  591. for($i = 0; $i<$ile_argumentow; $i += 6){
  592. $x1 = ($a[$i][0]);
  593. $y1 = ($a[$i+1][0]);
  594. $x2 = ($a[$i+2][0]);
  595. $y2 = ($a[$i+3][0]);
  596. $x = ($a[$i+4][0]);
  597. $y = ($a[$i+5][0]);
  598. if($relative){
  599. $pdfx1 = ($xbase + $x1);
  600. $pdfy1 = ($ybase - $y1);
  601. $pdfx2 = ($xbase + $x2);
  602. $pdfy2 = ($ybase - $y2);
  603. $pdfx = ($xbase + $x);
  604. $pdfy = ($ybase - $y);
  605. $xbase += $x;
  606. $ybase += -$y;
  607. }
  608. else{
  609. $pdfx1 = $x1;
  610. $pdfy1 = -$y1;
  611. $pdfx2 = $x2;
  612. $pdfy2 = -$y2;
  613. $pdfx = $x;
  614. $pdfy = -$y;
  615. $xbase = $x;
  616. $ybase = -$y;
  617. }
  618. $this->lastcontrolpoints = array(($x-$x2),($y-$y2));
  619. // $pdf_pt2 = $this->svg_overflow($pdfx2,$pdfy2);
  620. // $pdf_pt1 = $this->svg_overflow($pdfx1,$pdfy1);
  621. $pdf_pt = $this->svg_overflow($pdfx,$pdfy);
  622. if( ($pdf_pt['x'] != $pdfx) || ($pdf_pt['y'] != $pdfy) )
  623. {
  624. $path_cmd .= sprintf('%.3f %.3f l ', $pdf_pt['x'], $pdf_pt['y']);
  625. }
  626. else
  627. {
  628. $path_cmd .= sprintf('%.3f %.3f %.3f %.3f %.3f %.3f c ', $pdfx1, $pdfy1, $pdfx2, $pdfy2, $pdfx, $pdfy);
  629. }
  630. }
  631. break;
  632. case 'q': // bezier quadratic avec point de control
  633. for($i = 0; $i<$ile_argumentow; $i += 4){
  634. $x1 = ($a[$i][0]);
  635. $y1 = ($a[$i+1][0]);
  636. $x = ($a[$i+2][0]);
  637. $y = ($a[$i+3][0]);
  638. if($relative){
  639. $pdfx1 = ($xbase + ($x1*2/3));
  640. $pdfy1 = ($ybase - ($y1*2/3));
  641. $pdfx2 = ($xbase + $x - ($x1*2/3));
  642. $pdfy2 = ($ybase - $y - ($y1*2/3));
  643. $pdfx = ($xbase + $x);
  644. $pdfy = ($ybase - $y);
  645. $xbase += $x;
  646. $ybase += -$y;
  647. }
  648. else{
  649. $pdfx1 = ($xbase+(($x1-$xbase)*2/3));
  650. $pdfy1 = ($ybase-(($y1+$ybase)*2/3));
  651. $pdfx2 = ($x+(($x1-$x)*2/3));
  652. $pdfy2 = (-$y-(($y1-$y)*2/3));
  653. $pdfx = $x;
  654. $pdfy = -$y;
  655. $xbase = $x;
  656. $ybase = -$y;
  657. }
  658. $this->lastcontrolpoints = array(($x-$x1),($y-$y1));
  659. // $pdf_pt2 = $this->svg_overflow($pdfx2,$pdfy2);
  660. // $pdf_pt1 = $this->svg_overflow($pdfx1,$pdfy1);
  661. $pdf_pt = $this->svg_overflow($pdfx,$pdfy);
  662. if( ($pdf_pt['x'] != $pdfx) || ($pdf_pt['y'] != $pdfy) )
  663. {
  664. $path_cmd .= sprintf('%.3f %.3f l ', $pdf_pt['x'], $pdf_pt['y']);
  665. }
  666. else
  667. {
  668. $path_cmd .= sprintf('%.3f %.3f %.3f %.3f %.3f %.3f c ', $pdfx1, $pdfy1, $pdfx2, $pdfy2, $pdfx, $pdfy);
  669. }
  670. }
  671. break;
  672. case 't': // bezier quadratic avec point de control simetrique a lancien point de control
  673. if ($this->lastcommand == 'Q' || $this->lastcommand == 'q' || $this->lastcommand == 'T' || $this->lastcommand == 't') {
  674. $x = ($a[0][0]);
  675. $y = ($a[1][0]);
  676. $x1 = $this->lastcontrolpoints[0];
  677. $y1 = $this->lastcontrolpoints[1];
  678. if($relative){
  679. $pdfx = ($xbase + $x);
  680. $pdfy = ($ybase - $y);
  681. $pdfx1 = ($xbase + ($x1*2/3));
  682. $pdfy1 = ($ybase - ($y1*2/3));
  683. $pdfx2 = ($xbase + $x - ($x1*2/3));
  684. $pdfy2 = ($ybase -$y - ($y1*2/3));
  685. $xbase += $x;
  686. $ybase += -$y;
  687. }
  688. else{
  689. $pdfx = $x;
  690. $pdfy = -$y;
  691. $pdfx1 = ($xbase + ($x1*2/3));
  692. $pdfy1 = ($ybase - ($y1*2/3));
  693. $pdfx2 = ($x - ($x1*2/3));
  694. $pdfy2 = (-$y - ($y1*2/3));
  695. $xbase = $x;
  696. $ybase = -$y;
  697. }
  698. $this->lastcontrolpoints = array(($x-$pdfx2),($y-$pdfy2));
  699. $path_cmd .= sprintf('%.3f %.3f %.3f %.3f %.3f %.3f c ', $pdfx1, $pdfy1, $pdfx2, $pdfy2, $pdfx, $pdfy);
  700. }
  701. $this->lastcontrolpoints = array();
  702. break;
  703. case 'a': // Elliptical arc
  704. for($i = 0; $i<$ile_argumentow; $i += 7){
  705. $rx = ($a[$i][0]);
  706. $ry = ($a[$i+1][0]);
  707. $angle = ($a[$i+2][0]); //x-axis-rotation
  708. $largeArcFlag = ($a[$i+3][0]);
  709. $sweepFlag = ($a[$i+4][0]);
  710. $x2 = ($a[$i+5][0]);
  711. $y2 = ($a[$i+6][0]);
  712. $x1 = $xbase;
  713. $y1 = -$ybase;
  714. if($relative){
  715. $x2 = $xbase + $x2;
  716. $y2 = -$ybase + $y2;
  717. $xbase += ($a[$i+5][0]);
  718. $ybase += -($a[$i+6][0]);
  719. }
  720. else{
  721. $xbase = $x2;
  722. $ybase = -$y2;
  723. }
  724. $path_cmd .= $this->Arcto($x1, $y1, $x2, $y2, $rx, $ry, $angle, $largeArcFlag, $sweepFlag);
  725. }
  726. break;
  727. case'z':
  728. $path_cmd .= 'h ';
  729. break;
  730. default:
  731. break;
  732. }
  733. $this->lastcommand = $command;
  734. return $path_cmd;
  735. }
  736. function Arcto($x1, $y1, $x2, $y2, $rx, $ry, $angle, $largeArcFlag, $sweepFlag) {
  737. // 1. Treat out-of-range parameters as described in
  738. // http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
  739. // If the endpoints (x1, y1) and (x2, y2) are identical, then this
  740. // is equivalent to omitting the elliptical arc segment entirely
  741. if ($x1 == $x2 && $y1 == $y2) return '';
  742. // If rX = 0 or rY = 0 then this arc is treated as a straight line
  743. // segment (a "lineto") joining the endpoints.
  744. if ($rx == 0.0 || $ry == 0.0) {
  745. // return Lineto(x2, y2); // ****
  746. }
  747. // If rX or rY have negative signs, these are dropped; the absolute
  748. // value is used instead.
  749. if ($rx<0.0) $rx = -$rx;
  750. if ($ry<0.0) $ry = -$ry;
  751. // 2. convert to center parameterization as shown in
  752. // http://www.w3.org/TR/SVG/implnote.html
  753. $sinPhi = sin(deg2rad($angle));
  754. $cosPhi = cos(deg2rad($angle));
  755. $x1dash = $cosPhi * ($x1-$x2)/2.0 + $sinPhi * ($y1-$y2)/2.0;
  756. $y1dash = -$sinPhi * ($x1-$x2)/2.0 + $cosPhi * ($y1-$y2)/2.0;
  757. $numerator = $rx*$rx*$ry*$ry - $rx*$rx*$y1dash*$y1dash - $ry*$ry*$x1dash*$x1dash;
  758. if ($numerator < 0.0) {
  759. // If rX , rY and are such that there is no solution (basically,
  760. // the ellipse is not big enough to reach from (x1, y1) to (x2,
  761. // y2)) then the ellipse is scaled up uniformly until there is
  762. // exactly one solution (until the ellipse is just big enough).
  763. // -> find factor s, such that numerator' with rx'=s*rx and
  764. // ry'=s*ry becomes 0 :
  765. $s = sqrt(1.0 - $numerator/($rx*$rx*$ry*$ry));
  766. $rx *= $s;
  767. $ry *= $s;
  768. $root = 0.0;
  769. }
  770. else {
  771. $root = ($largeArcFlag == $sweepFlag ? -1.0 : 1.0) * sqrt( $numerator/($rx*$rx*$y1dash*$y1dash+$ry*$ry*$x1dash*$x1dash) );
  772. }
  773. $cxdash = $root*$rx*$y1dash/$ry;
  774. $cydash = -$root*$ry*$x1dash/$rx;
  775. $cx = $cosPhi * $cxdash - $sinPhi * $cydash + ($x1+$x2)/2.0;
  776. $cy = $sinPhi * $cxdash + $cosPhi * $cydash + ($y1+$y2)/2.0;
  777. $theta1 = $this->CalcVectorAngle(1.0, 0.0, ($x1dash-$cxdash)/$rx, ($y1dash-$cydash)/$ry);
  778. $dtheta = $this->CalcVectorAngle(($x1dash-$cxdash)/$rx, ($y1dash-$cydash)/$ry, (-$x1dash-$cxdash)/$rx, (-$y1dash-$cydash)/$ry);
  779. if (!$sweepFlag && $dtheta>0)
  780. $dtheta -= 2.0*M_PI;
  781. else if ($sweepFlag && $dtheta<0)
  782. $dtheta += 2.0*M_PI;
  783. // 3. convert into cubic bezier segments <= 90deg
  784. $segments = ceil(abs($dtheta/(M_PI/2.0)));
  785. $delta = $dtheta/$segments;
  786. $t = 8.0/3.0 * sin($delta/4.0) * sin($delta/4.0) / sin($delta/2.0);
  787. $coords = array();
  788. for ($i = 0; $i < $segments; $i++) {
  789. $cosTheta1 = cos($theta1);
  790. $sinTheta1 = sin($theta1);
  791. $theta2 = $theta1 + $delta;
  792. $cosTheta2 = cos($theta2);
  793. $sinTheta2 = sin($theta2);
  794. // a) calculate endpoint of the segment:
  795. $xe = $cosPhi * $rx*$cosTheta2 - $sinPhi * $ry*$sinTheta2 + $cx;
  796. $ye = $sinPhi * $rx*$cosTheta2 + $cosPhi * $ry*$sinTheta2 + $cy;
  797. // b) calculate gradients at start/end points of segment:
  798. $dx1 = $t * ( - $cosPhi * $rx*$sinTheta1 - $sinPhi * $ry*$cosTheta1);
  799. $dy1 = $t * ( - $sinPhi * $rx*$sinTheta1 + $cosPhi * $ry*$cosTheta1);
  800. $dxe = $t * ( $cosPhi * $rx*$sinTheta2 + $sinPhi * $ry*$cosTheta2);
  801. $dye = $t * ( $sinPhi * $rx*$sinTheta2 - $cosPhi * $ry*$cosTheta2);
  802. // c) draw the cubic bezier:
  803. $coords[$i] = array(($x1+$dx1), ($y1+$dy1), ($xe+$dxe), ($ye+$dye), $xe, $ye);
  804. // do next segment
  805. $theta1 = $theta2;
  806. $x1 = $xe;
  807. $y1 = $ye;
  808. }
  809. $path = ' ';
  810. foreach($coords AS $c) {
  811. $cpx1 = $c[0];
  812. $cpy1 = $c[1];
  813. $cpx2 = $c[2];
  814. $cpy2 = $c[3];
  815. $x2 = $c[4];
  816. $y2 = $c[5];
  817. $path .= sprintf('%.3f %.3f %.3f %.3f %.3f %.3f c ', $cpx1, -$cpy1, $cpx2, -$cpy2, $x2, -$y2) ."\n";
  818. }
  819. return $path ;
  820. }
  821. function CalcVectorAngle($ux, $uy, $vx, $vy) {
  822. $ta = atan2($uy, $ux);
  823. $tb = atan2($vy, $vx);
  824. if ($tb >= $ta)
  825. return ($tb-$ta);
  826. return (6.28318530718 - ($ta-$tb));
  827. }
  828. //
  829. // fonction retracant les <rect />
  830. function svgRect($arguments){
  831. $x = $arguments['x'];
  832. $y = $arguments['y'];
  833. $h = $arguments['h'];
  834. $w = $arguments['w'];
  835. $rx = ($arguments['rx']/2);
  836. $ry = ($arguments['ry']/2);
  837. if ($rx>0 and $ry == 0){$ry = $rx;}
  838. if ($ry>0 and $rx == 0){$rx = $ry;}
  839. if ($rx == 0 and $ry == 0){
  840. // trace un rectangle sans angle arrondit
  841. $path_cmd = sprintf('%.3f %.3f m ', ($x), -($y));
  842. $path_cmd .= sprintf('%.3f %.3f l ', (($x+$w)), -($y));
  843. $path_cmd .= sprintf('%.3f %.3f l ', (($x+$w)), -(($y+$h)));
  844. $path_cmd .= sprintf('%.3f %.3f l ', ($x), -(($y+$h)));
  845. $path_cmd .= sprintf('%.3f %.3f l h ', ($x), -($y));
  846. }
  847. else {
  848. // trace un rectangle avec les arrondit
  849. // les points de controle du bezier sont deduis grace a la constante kappa
  850. $kappa = 4*(sqrt(2)-1)/3;
  851. $kx = $kappa*$rx;
  852. $ky = $kappa*$ry;
  853. $path_cmd = sprintf('%.3f %.3f m ', $x+($rx), -$y);
  854. $path_cmd .= sprintf('%.3f %.3f l ', $x+(($w-$rx)), -$y);
  855. $path_cmd .= sprintf('%.3f %.3f %.3f %.3f %.3f %.3f c ', $x+(($w-$rx+$kx)), -$y, $x+($w), -$y+((-$ry+$ky)), $x+($w), -$y+(-$ry) );
  856. $path_cmd .= sprintf('%.3f %.3f l ', $x+($w), -$y+((-$h+$ry)));
  857. $path_cmd .= sprintf('%.3f %.3f %.3f %.3f %.3f %.3f c ', $x+($w), -$y+((-$h-$ky+$ry)), $x+(($w-$rx+$kx)), -$y+(-$h), $x+(($w-$rx)), -$y+(-$h) );
  858. $path_cmd .= sprintf('%.3f %.3f l ', $x+($rx), -$y+(-$h));
  859. $path_cmd .= sprintf('%.3f %.3f %.3f %.3f %.3f %.3f c ', $x+(($rx-$kx)), -$y+(-$h), $x, -$y+((-$h-$ky+$ry)), $x, -$y+((-$h+$ry)) );
  860. $path_cmd .= sprintf('%.3f %.3f l ', $x, -$y+(-$ry));
  861. $path_cmd .= sprintf('%.3f %.3f %.3f %.3f %.3f %.3f c h ', $x, -$y+((-$ry+$ky)), $x+(($rx-$kx)), -$y, $x+($rx), -$y );
  862. }
  863. return $path_cmd;
  864. }
  865. //
  866. // fonction retracant les <ellipse /> et <circle />
  867. // le cercle est tracé grave a 4 bezier cubic, les poitn de controles
  868. // sont deduis grace a la constante kappa * rayon
  869. function svgEllipse($arguments){
  870. $kappa = 4*(sqrt(2)-1)/3;
  871. $cx = $arguments['cx'] ;
  872. $cy = $arguments['cy'] ;
  873. $rx = $arguments['rx'] ;
  874. $ry = $arguments['ry'] ;
  875. $x1 = $cx;
  876. $y1 = -$cy+$ry;
  877. $x2 = $cx+$rx;
  878. $y2 = -$cy;
  879. $x3 = $cx;
  880. $y3 = -$cy-$ry;
  881. $x4 = $cx-$rx;
  882. $y4 = -$cy;
  883. $path_cmd = sprintf('%.3f %.3f m ', $x1, $y1);
  884. $path_cmd .= sprintf('%.3f %.3f %.3f %.3f %.3f %.3f c ', $x1+($rx*$kappa), $y1, $x2, $y2+($ry*$kappa), $x2, $y2);
  885. $path_cmd .= sprintf('%.3f %.3f %.3f %.3f %.3f %.3f c ', $x2, $y2-($ry*$kappa), $x3+($rx*$kappa), $y3, $x3, $y3);
  886. $path_cmd .= sprintf('%.3f %.3f %.3f %.3f %.3f %.3f c ', $x3-($rx*$kappa), $y3, $x4, $y4-($ry*$kappa), $x4, $y4);
  887. $path_cmd .= sprintf('%.3f %.3f %.3f %.3f %.3f %.3f c ', $x4, $y4+($ry*$kappa), $x1-($rx*$kappa), $y1, $x1, $y1);
  888. $path_cmd .= 'h ';
  889. return $path_cmd;
  890. }
  891. //
  892. // fonction retracant les <polyline /> et les <line />
  893. function svgPolyline($arguments){
  894. $xbase = $arguments[0] ;
  895. $ybase = - $arguments[1] ;
  896. $path_cmd = sprintf('%.3f %.3f m ', $xbase, $ybase);
  897. for ($i = 2; $i<count($arguments);$i += 2) {
  898. $tmp_x = $arguments[$i] ;
  899. $tmp_y = - $arguments[($i+1)] ;
  900. $path_cmd .= sprintf('%.3f %.3f l ', $tmp_x, $tmp_y);
  901. }
  902. // $path_cmd .= 'h '; // ?? In error - don't close subpath here
  903. return $path_cmd;
  904. }
  905. //
  906. // fonction retracant les <polygone />
  907. function svgPolygon($arguments){
  908. $xbase = $arguments[0] ;
  909. $ybase = - $arguments[1] ;
  910. $path_cmd = sprintf('%.3f %.3f m ', $xbase, $ybase);
  911. for ($i = 2; $i<count($arguments);$i += 2) {
  912. $tmp_x = $arguments[$i] ;
  913. $tmp_y = - $arguments[($i+1)] ;
  914. $path_cmd .= sprintf('%.3f %.3f l ', $tmp_x, $tmp_y);
  915. }
  916. $path_cmd .= sprintf('%.3f %.3f l ', $xbase, $ybase);
  917. $path_cmd .= 'h ';
  918. return $path_cmd;
  919. }
  920. //
  921. // write string to image
  922. function svgText(){
  923. // $tmp = count($this->txt_style)-1;
  924. $current_style = array_pop($this->txt_style);
  925. $style = '';
  926. if(isset($this->txt_data[2]))
  927. {
  928. // select font
  929. $style .= ($current_style['font-weight'] == 'bold')?'B':'';
  930. $style .= ($current_style['font-style'] == 'italic')?'I':'';
  931. $size = $current_style['font-size'];
  932. $current_style['font-family'] = $this->mpdf_ref->SetFont($current_style['font-family'],$style,$current_style['font-size'],false);
  933. $col = $this->mpdf_ref->ConvertColor($current_style['fill']);
  934. $x = $this->txt_data[0];
  935. $y = $this->txt_data[1];
  936. $txt = $this->txt_data[2];
  937. $txt = trim($txt);
  938. $txt = $this->mpdf_ref->purify_utf8_text($txt);
  939. if ($this->mpdf_ref->text_input_as_HTML) {
  940. $txt = $this->mpdf_ref->all_entities_to_utf8($txt);
  941. }
  942. if (!$this->mpdf_ref->is_MB) { $txt = mb_convert_encoding($txt,$this->mpdf_ref->mb_enc,'UTF-8'); }
  943. $this->mpdf_ref->magic_reverse_dir($txt);
  944. $this->mpdf_ref->ConvertIndic($txt);
  945. if ($current_style['text-anchor']=='middle') {
  946. $tw = $this->mpdf_ref->GetStringWidth($txt)*2.835/2;
  947. }
  948. else if ($current_style['text-anchor']=='end') {
  949. $tw = $this->mpdf_ref->GetStringWidth($txt)*2.835;
  950. }
  951. else $tw = 0;
  952. if ($this->mpdf_ref->useSubsets && $this->mpdf_ref->CurrentFont['type']=='Type1subset' && !$this->mpdf_ref->isCJK && !$this->mpdf_ref->usingCoreFont) {
  953. $txt = $this->mpdf_ref->UTF8toSubset($txt);
  954. }
  955. else {
  956. if ($this->mpdf_ref->is_MB && !$this->mpdf_ref->usingCoreFont) {
  957. $txt= $this->mpdf_ref->UTF8ToUTF16BE($txt, false);
  958. }
  959. $txt='('.$this->mpdf_ref->_escape($txt).')';
  960. }
  961. $this->mpdf_ref->CurrentFont['used']= true;
  962. $pdfx = ($x - $tw);
  963. $pdfy = -$y ;
  964. $xbase = $x;
  965. $ybase = -$y;
  966. $path_cmd = sprintf('q BT /F%d %.3f Tf %.3f %.3f Td 0 Tr %.3f %.3f %.3f rg %s Tj ET Q ',$this->mpdf_ref->CurrentFont['i'],$this->mpdf_ref->FontSizePt,$pdfx,$pdfy,$col['R']/255,$col['G']/255,$col['B']/255,$txt);
  967. unset($this->txt_data[0], $this->txt_data[1],$this->txt_data[2]);
  968. }
  969. else
  970. {
  971. die("No string to write!");
  972. }
  973. $path_cmd .= 'h ';
  974. return $path_cmd;
  975. }
  976. function svgDefineTxtStyle($critere_style)
  977. {
  978. // get copy of current/default txt style, and modify it with supplied attributes
  979. $tmp = count($this->txt_style)-1;
  980. $current_style = $this->txt_style[$tmp];
  981. if (isset($critere_style['font'])){
  982. // [ [ <'font-style'> || <'font-variant'> || <'font-weight'> ]?<'font-size'> [ / <'line-height'> ]? <'font-family'> ]
  983. $tmp = preg_replace("/(.*)(italic|oblique)(.*)/i","$2",$critere_style['font']);
  984. if ($tmp != $critere_style['font']){
  985. if($tmp == 'oblique'){
  986. $tmp = 'italic';
  987. }
  988. $current_style['font-style'] = $tmp;
  989. }
  990. $tmp = preg_replace("/(.*)(bold|bolder)(.*)/i","$2",$critere_style['font']);
  991. if ($tmp != $critere_style['font']){
  992. if($tmp == 'bolder'){
  993. $tmp = 'bold';
  994. }
  995. $current_style['font-weight'] = $tmp;
  996. }
  997. // select digits not followed by percent sign nor preceeded by forward slash
  998. $tmp = preg_replace("/(.*)\b(\d+)[\b|\/](.*)/i","$2",$critere_style['font']);
  999. if ($tmp != $critere_style['font']){ $current_style['font-size'] = $tmp; }
  1000. }
  1001. if(isset($critere_style['fill'])){
  1002. $current_style['fill'] = $critere_style['fill'];
  1003. }
  1004. if(isset($critere_style['font-style'])){
  1005. if(strtolower($critere_style['font-style']) == 'oblique')
  1006. {
  1007. $critere_style['font-style'] = 'italic';
  1008. }
  1009. $current_style['font-style'] = $critere_style['font-style'];
  1010. }
  1011. if(isset($critere_style['font-weight'])){
  1012. if(strtolower($critere_style['font-weight']) == 'bolder')
  1013. {
  1014. $critere_style['font-weight'] = 'bold';
  1015. }
  1016. $current_style['font-weight'] = $critere_style['font-weight'];
  1017. }
  1018. if(isset($critere_style['font-size'])){
  1019. $current_style['font-size'] = $this->mpdf_ref->ConvertSize($critere_style['font-size'])* 2.835;
  1020. }
  1021. if(isset($critere_style['font-family'])){
  1022. $current_style['font-family'] = $critere_style['font-family'];
  1023. }
  1024. if(isset($critere_style['text-anchor'])){
  1025. $current_style['text-anchor'] = $critere_style['text-anchor'];
  1026. }
  1027. // add current style to text style array (will remove it later after writing text to svg_string)
  1028. array_push($this->txt_style,$current_style);
  1029. }
  1030. //
  1031. // fonction ajoutant un gradient
  1032. function svgAddGradient($id,$array_gradient){
  1033. $this->svg_gradient[$id] = $array_gradient;
  1034. }
  1035. //
  1036. // Ajoute une couleur dans le gradient correspondant
  1037. //
  1038. // function ecrivant dans le svgstring
  1039. function svgWriteString($content){
  1040. $this->svg_string .= $content;
  1041. }
  1042. // analise le svg et renvoie aux fonctions precedente our le traitement
  1043. function ImageSVG($data){
  1044. $this->svg_info = array();
  1045. $this->svg_info['data'] = $data;
  1046. $this->svg_string = '';
  1047. //
  1048. // chargement unique des fonctions
  1049. if(!function_exists(xml_svg2pdf_start)){
  1050. function xml_svg2pdf_start($parser, $name, $attribs){
  1051. //
  1052. // definition
  1053. global $svg_class, $last_gradid;
  1054. switch (strtolower($name)){
  1055. case 'svg':
  1056. $svg_class->svgOffset($attribs);
  1057. break;
  1058. case 'path':
  1059. $path = $attribs['d'];
  1060. preg_match_all('/([a-z]|[A-Z])([ ,\-.\d]+)*/', $path, $commands, PREG_SET_ORDER);
  1061. $path_cmd = '';
  1062. foreach($commands as $c){
  1063. if(count($c)==3){
  1064. list($tmp, $command, $arguments) = $c;
  1065. }
  1066. else{
  1067. list($tmp, $command) = $c;
  1068. $arguments = '';
  1069. }
  1070. $path_cmd .= $svg_class->svgPath($command, $arguments);
  1071. }
  1072. $critere_style = $attribs;
  1073. unset($critere_style['d']);
  1074. $path_style = $svg_class->svgDefineStyle($critere_style);
  1075. break;
  1076. case 'rect':
  1077. if (!isset($attribs['x'])) {$attribs['x'] = 0;}
  1078. if (!isset($attribs['y'])) {$attribs['y'] = 0;}
  1079. if (!isset($attribs['rx'])) {$attribs['rx'] = 0;}
  1080. if (!isset($attribs['ry'])) {$attribs['ry'] = 0;}
  1081. $arguments = array(
  1082. 'x' => $attribs['x'],
  1083. 'y' => $attribs['y'],
  1084. 'w' => $attribs['width'],
  1085. 'h' => $attribs['height'],
  1086. 'rx' => $attribs['rx'],
  1087. 'ry' => $attribs['ry']
  1088. );
  1089. $path_cmd = $svg_class->svgRect($arguments);
  1090. $critere_style = $attribs;
  1091. unset($critere_style['x'],$critere_style['y'],$critere_style['rx'],$critere_style['ry'],$critere_style['height'],$critere_style['width']);
  1092. $path_style = $svg_class->svgDefineStyle($critere_style);
  1093. break;
  1094. case 'circle':
  1095. if (!isset($attribs['cx'])) {$attribs['cx'] = 0;}
  1096. if (!isset($attribs['cy'])) {$attribs['cy'] = 0;}
  1097. $arguments = array(
  1098. 'cx' => $attribs['cx'],
  1099. 'cy' => $attribs['cy'],
  1100. 'rx' => $attribs['r'],
  1101. 'ry' => $attribs['r']
  1102. );
  1103. $path_cmd = $svg_class->svgEllipse($arguments);
  1104. $critere_style = $attribs;
  1105. unset($critere_style['cx'],$critere_style['cy'],$critere_style['r']);
  1106. $path_style = $svg_class->svgDefineStyle($critere_style);
  1107. break;
  1108. case 'ellipse':
  1109. if (!isset($attribs['cx'])) {$attribs['cx'] = 0;}
  1110. if (!isset($attribs['cy'])) {$attribs['cy'] = 0;}
  1111. $arguments = array(
  1112. 'cx' => $attribs['cx'],
  1113. 'cy' => $attribs['cy'],
  1114. 'rx' => $attribs['rx'],
  1115. 'ry' => $attribs['ry']
  1116. );
  1117. $path_cmd = $svg_class->svgEllipse($arguments);
  1118. $critere_style = $attribs;
  1119. unset($critere_style['cx'],$critere_style['cy'],$critere_style['rx'],$critere_style['ry']);
  1120. $path_style = $svg_class->svgDefineStyle($critere_style);
  1121. break;
  1122. case 'line':
  1123. $arguments = array($attribs['x1'],$attribs['y1'],$attribs['x2'],$attribs['y2']);
  1124. $path_cmd = $svg_class->svgPolyline($arguments);
  1125. $critere_style = $attribs;
  1126. unset($critere_style['x1'],$critere_style['y1'],$critere_style['x2'],$critere_style['y2']);
  1127. $path_style = $svg_class->svgDefineStyle($critere_style);
  1128. break;
  1129. case 'polyline':
  1130. $path = $attribs['points'];
  1131. preg_match_all('/[0-9\-\.]*/',$path, $tmp, PREG_SET_ORDER);
  1132. $arguments = array();
  1133. for ($i=0;$i<count($tmp);$i++){
  1134. if ($tmp[$i][0] !=''){
  1135. array_push($arguments, $tmp[$i][0]);
  1136. }
  1137. }
  1138. $path_cmd = $svg_class->svgPolyline($arguments);
  1139. $critere_style = $attribs;
  1140. unset($critere_style['points']);
  1141. $path_style = $svg_class->svgDefineStyle($critere_style);
  1142. break;
  1143. case 'polygon':
  1144. $path = $attribs['points'];
  1145. preg_match_all('/([\-]*[0-9\.]+)/',$path, $tmp);
  1146. $arguments = array();
  1147. for ($i=0;$i<count($tmp[0]);$i++){
  1148. if ($tmp[0][$i] !=''){
  1149. array_push($arguments, $tmp[0][$i]);
  1150. }
  1151. }
  1152. $path_cmd = $svg_class->svgPolygon($arguments);
  1153. // definition du style de la forme:
  1154. $critere_style = $attribs;
  1155. unset($critere_style['points']);
  1156. $path_style = $svg_class->svgDefineStyle($critere_style);
  1157. break;
  1158. case 'lineargradient':
  1159. $tmp_gradient = array(
  1160. 'type' => 'linear',
  1161. 'info' => array(
  1162. 'x1' => $attribs['x1'],
  1163. 'y1' => $attribs['y1'],
  1164. 'x2' => $attribs['x2'],
  1165. 'y2' => $attribs['y2']
  1166. ),
  1167. 'transform' => $attribs['gradientTransform'],
  1168. 'color' => array()
  1169. );
  1170. $last_gradid = $attribs['id'];
  1171. $svg_class->svgAddGradient($attribs['id'],$tmp_gradient);
  1172. break;
  1173. case 'radialgradient':
  1174. $tmp_gradient = array(
  1175. 'type' => 'radial',
  1176. 'info' => array(
  1177. 'x0' => $attribs['cx'],
  1178. 'y0' => $attribs['cy'],
  1179. 'x1' => $attribs['fx'],
  1180. 'y1' => $attribs['fy'],
  1181. 'r' => $attribs['r']
  1182. ),
  1183. 'transform' => $attribs['gradientTransform'],
  1184. 'color' => array()
  1185. );
  1186. $last_gradid = $attribs['id'];
  1187. $svg_class->svgAddGradient($attribs['id'],$tmp_gradient);
  1188. break;
  1189. case 'stop':
  1190. if (!$last_gradid) break;
  1191. if (isset($attribs['style']) AND !isset($attribs['stop-color'])){
  1192. $color = preg_replace('/stop-color:([0-9#]*)/i','$1',$attribs['style']);
  1193. } else {
  1194. $color = $attribs['stop-color'];
  1195. }
  1196. $col = $svg_class->mpdf_ref->ConvertColor($color);
  1197. $color_r = $col['R'];
  1198. $color_g = $col['G'];
  1199. $color_b = $col['B'];
  1200. $color_final = $path_style .= sprintf('%.3f %.3f %.3f',$color_r/255,$color_g/255,$color_b/255);
  1201. $tmp_color = array(
  1202. 'color' => $color_final,
  1203. 'offset' => $attribs['offset'],
  1204. 'opacity' => $attribs['stop-opacity']
  1205. );
  1206. array_push($svg_class->svg_gradient[$last_gradid]['color'],$tmp_color);
  1207. break;
  1208. case 'g':
  1209. $array_style = $svg_class->svgDefineStyle($attribs);
  1210. if ($array_style['transformations']) {
  1211. $svg_class->svgWriteString(' q '.$array_style['transformations']);
  1212. }
  1213. array_push($svg_class->svg_style,$array_style);
  1214. break;
  1215. case 'text':
  1216. $svg_class->txt_data = array();
  1217. $svg_class->txt_data[0] = $attribs['x'];
  1218. $svg_class->txt_data[1] = $attribs['y'];
  1219. $critere_style = $attribs;
  1220. unset($critere_style['x'], $critere_style['y']);
  1221. $svg_class->svgDefineTxtStyle($critere_style);
  1222. break;
  1223. }
  1224. //
  1225. //insertion des path et du style dans le flux de donné general.
  1226. if (isset($path_cmd)){
  1227. $get_style = $svg_class->svgStyle($path_style, $attribs, strtolower($name));
  1228. if ($path_style['transformations']) { // transformation on an element
  1229. $svg_class->svgWriteString(" q ".$path_style['transformations']. "$path_cmd $get_style" . " Q\n");
  1230. }
  1231. else {
  1232. $svg_class->svgWriteString("$path_cmd $get_style\n");
  1233. }
  1234. }
  1235. }
  1236. function characterData($parser, $data)
  1237. {
  1238. global $svg_class;
  1239. if(isset($svg_class->txt_data[2]))
  1240. {
  1241. $svg_class->txt_data[2] .= $data;
  1242. }
  1243. else
  1244. {
  1245. $svg_class->txt_data[2] = $data;
  1246. }
  1247. }
  1248. function xml_svg2pdf_end($parser, $name){
  1249. global $svg_class;
  1250. switch($name){
  1251. case "g":
  1252. $tmp = count($svg_class->svg_style)-1;
  1253. $current_style = $svg_class->svg_style[$tmp];
  1254. if ($current_style['transformations']) {
  1255. $svg_class->svgWriteString(" Q ");
  1256. }
  1257. array_pop($svg_class->svg_style);
  1258. break;
  1259. case 'radialgradient':
  1260. case 'lineargradient':
  1261. $last_gradid = '';
  1262. break;
  1263. case "text":
  1264. $path_cmd = $svg_class->svgText();
  1265. // echo 'path >> '.$path_cmd."<br><br>";
  1266. // echo "style >> ".$get_style[1]."<br><br>";
  1267. $svg_class->svgWriteString($path_cmd);
  1268. break;
  1269. }
  1270. }
  1271. }
  1272. $svg2pdf_xml='';
  1273. global $svg_class;
  1274. $svg_class = $this;
  1275. $svg2pdf_xml_parser = xml_parser_create("utf-8");
  1276. xml_parser_set_option($svg2pdf_xml_parser, XML_OPTION_CASE_FOLDING, false);
  1277. xml_set_element_handler($svg2pdf_xml_parser, "xml_svg2pdf_start", "xml_svg2pdf_end");
  1278. xml_set_character_data_handler($svg2pdf_xml_parser, "characterData");
  1279. xml_parse($svg2pdf_xml_parser, $data);
  1280. return array('x'=>$this->svg_info['x'],'y'=>-$this->svg_info['y'],'w'=>$this->svg_info['w'],'h'=>-$this->svg_info['h'],'data'=>$svg_class->svg_string);
  1281. }
  1282. }
  1283. ?>