PageRenderTime 59ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/app/vendors/html2pdf/styleHTML.class.php

https://github.com/ata/steak
PHP | 1437 lines | 1131 code | 160 blank | 146 comment | 214 complexity | d77d9928f45592fc3554ac43ac3bcf95 MD5 | raw file
  1. <?php
  2. /**
  3. * Logiciel : HTML2PDF - classe styleHTML
  4. *
  5. * Convertisseur HTML => PDF, utilise fpdf de Olivier PLATHEY
  6. * Distribué sous la licence GPL.
  7. *
  8. * @author Laurent MINGUET <webmaster@spipu.net>
  9. * @version 3.21 - 05/05/2009
  10. */
  11. if (!defined('__CLASS_STYLEHTML__'))
  12. {
  13. define('__CLASS_STYLEHTML__', true);
  14. class styleHTML
  15. {
  16. var $css = array(); // tableau des CSS
  17. var $css_keys = array(); // tableau des clefs CSS, pour l'ordre d'execution
  18. var $value = array(); // valeurs actuelles
  19. var $table = array(); // tableau d'empilement pour historisation des niveaux
  20. var $pdf = null; // référence au PDF parent
  21. var $htmlColor = array(); // liste des couleurs HTML
  22. /**
  23. * Constructeur
  24. *
  25. * @param &pdf référence à l'objet HTML2PDF parent
  26. * @return null
  27. */
  28. function styleHTML(&$pdf)
  29. {
  30. $this->init(); // initialisation
  31. $this->pdf = &$pdf;
  32. }
  33. /**
  34. * Initialisation du style
  35. *
  36. * @return null
  37. */
  38. function init()
  39. {
  40. $color = array();
  41. $color['AliceBlue'] = '#F0F8FF';
  42. $color['AntiqueWhite'] = '#FAEBD7';
  43. $color['Aqua'] = '#00FFFF';
  44. $color['Aquamarine'] = '#7FFFD4';
  45. $color['Azure'] = '#F0FFFF';
  46. $color['Beige'] = '#F5F5DC';
  47. $color['Bisque'] = '#FFE4C4';
  48. $color['Black'] = '#000000';
  49. $color['BlanchedAlmond'] = '#FFEBCD';
  50. $color['Blue'] = '#0000FF';
  51. $color['BlueViolet'] = '#8A2BE2';
  52. $color['Brown'] = '#A52A2A';
  53. $color['BurlyWood'] = '#DEB887';
  54. $color['CadetBlue'] = '#5F9EA0';
  55. $color['Chartreuse'] = '#7FFF00';
  56. $color['Chocolate'] = '#D2691E';
  57. $color['Coral'] = '#FF7F50';
  58. $color['CornflowerBlue'] = '#6495ED';
  59. $color['Cornsilk'] = '#FFF8DC';
  60. $color['Crimson'] = '#DC143C';
  61. $color['Cyan'] = '#00FFFF';
  62. $color['DarkBlue'] = '#00008B';
  63. $color['DarkCyan'] = '#008B8B';
  64. $color['DarkGoldenRod'] = '#B8860B';
  65. $color['DarkGray'] = '#A9A9A9';
  66. $color['DarkGrey'] = '#A9A9A9';
  67. $color['DarkGreen'] = '#006400';
  68. $color['DarkKhaki'] = '#BDB76B';
  69. $color['DarkMagenta'] = '#8B008B';
  70. $color['DarkOliveGreen'] = '#556B2F';
  71. $color['Darkorange'] = '#FF8C00';
  72. $color['DarkOrchid'] = '#9932CC';
  73. $color['DarkRed'] = '#8B0000';
  74. $color['DarkSalmon'] = '#E9967A';
  75. $color['DarkSeaGreen'] = '#8FBC8F';
  76. $color['DarkSlateBlue'] = '#483D8B';
  77. $color['DarkSlateGray'] = '#2F4F4F';
  78. $color['DarkSlateGrey'] = '#2F4F4F';
  79. $color['DarkTurquoise'] = '#00CED1';
  80. $color['DarkViolet'] = '#9400D3';
  81. $color['DeepPink'] = '#FF1493';
  82. $color['DeepSkyBlue'] = '#00BFFF';
  83. $color['DimGray'] = '#696969';
  84. $color['DimGrey'] = '#696969';
  85. $color['DodgerBlue'] = '#1E90FF';
  86. $color['FireBrick'] = '#B22222';
  87. $color['FloralWhite'] = '#FFFAF0';
  88. $color['ForestGreen'] = '#228B22';
  89. $color['Fuchsia'] = '#FF00FF';
  90. $color['Gainsboro'] = '#DCDCDC';
  91. $color['GhostWhite'] = '#F8F8FF';
  92. $color['Gold'] = '#FFD700';
  93. $color['GoldenRod'] = '#DAA520';
  94. $color['Gray'] = '#808080';
  95. $color['Grey'] = '#808080';
  96. $color['Green'] = '#008000';
  97. $color['GreenYellow'] = '#ADFF2F';
  98. $color['HoneyDew'] = '#F0FFF0';
  99. $color['HotPink'] = '#FF69B4';
  100. $color['IndianRed'] = '#CD5C5C';
  101. $color['Indigo'] = '#4B0082';
  102. $color['Ivory'] = '#FFFFF0';
  103. $color['Khaki'] = '#F0E68C';
  104. $color['Lavender'] = '#E6E6FA';
  105. $color['LavenderBlush'] = '#FFF0F5';
  106. $color['LawnGreen'] = '#7CFC00';
  107. $color['LemonChiffon'] = '#FFFACD';
  108. $color['LightBlue'] = '#ADD8E6';
  109. $color['LightCoral'] = '#F08080';
  110. $color['LightCyan'] = '#E0FFFF';
  111. $color['LightGoldenRodYellow'] = '#FAFAD2';
  112. $color['LightGray'] = '#D3D3D3';
  113. $color['LightGrey'] = '#D3D3D3';
  114. $color['LightGreen'] = '#90EE90';
  115. $color['LightPink'] = '#FFB6C1';
  116. $color['LightSalmon'] = '#FFA07A';
  117. $color['LightSeaGreen'] = '#20B2AA';
  118. $color['LightSkyBlue'] = '#87CEFA';
  119. $color['LightSlateGray'] = '#778899';
  120. $color['LightSlateGrey'] = '#778899';
  121. $color['LightSteelBlue'] = '#B0C4DE';
  122. $color['LightYellow'] = '#FFFFE0';
  123. $color['Lime'] = '#00FF00';
  124. $color['LimeGreen'] = '#32CD32';
  125. $color['Linen'] = '#FAF0E6';
  126. $color['Magenta'] = '#FF00FF';
  127. $color['Maroon'] = '#800000';
  128. $color['MediumAquaMarine'] = '#66CDAA';
  129. $color['MediumBlue'] = '#0000CD';
  130. $color['MediumOrchid'] = '#BA55D3';
  131. $color['MediumPurple'] = '#9370D8';
  132. $color['MediumSeaGreen'] = '#3CB371';
  133. $color['MediumSlateBlue'] = '#7B68EE';
  134. $color['MediumSpringGreen'] = '#00FA9A';
  135. $color['MediumTurquoise'] = '#48D1CC';
  136. $color['MediumVioletRed'] = '#C71585';
  137. $color['MidnightBlue'] = '#191970';
  138. $color['MintCream'] = '#F5FFFA';
  139. $color['MistyRose'] = '#FFE4E1';
  140. $color['Moccasin'] = '#FFE4B5';
  141. $color['NavajoWhite'] = '#FFDEAD';
  142. $color['Navy'] = '#000080';
  143. $color['OldLace'] = '#FDF5E6';
  144. $color['Olive'] = '#808000';
  145. $color['OliveDrab'] = '#6B8E23';
  146. $color['Orange'] = '#FFA500';
  147. $color['OrangeRed'] = '#FF4500';
  148. $color['Orchid'] = '#DA70D6';
  149. $color['PaleGoldenRod'] = '#EEE8AA';
  150. $color['PaleGreen'] = '#98FB98';
  151. $color['PaleTurquoise'] = '#AFEEEE';
  152. $color['PaleVioletRed'] = '#D87093';
  153. $color['PapayaWhip'] = '#FFEFD5';
  154. $color['PeachPuff'] = '#FFDAB9';
  155. $color['Peru'] = '#CD853F';
  156. $color['Pink'] = '#FFC0CB';
  157. $color['Plum'] = '#DDA0DD';
  158. $color['PowderBlue'] = '#B0E0E6';
  159. $color['Purple'] = '#800080';
  160. $color['Red'] = '#FF0000';
  161. $color['RosyBrown'] = '#BC8F8F';
  162. $color['RoyalBlue'] = '#4169E1';
  163. $color['SaddleBrown'] = '#8B4513';
  164. $color['Salmon'] = '#FA8072';
  165. $color['SandyBrown'] = '#F4A460';
  166. $color['SeaGreen'] = '#2E8B57';
  167. $color['SeaShell'] = '#FFF5EE';
  168. $color['Sienna'] = '#A0522D';
  169. $color['Silver'] = '#C0C0C0';
  170. $color['SkyBlue'] = '#87CEEB';
  171. $color['SlateBlue'] = '#6A5ACD';
  172. $color['SlateGray'] = '#708090';
  173. $color['SlateGrey'] = '#708090';
  174. $color['Snow'] = '#FFFAFA';
  175. $color['SpringGreen'] = '#00FF7F';
  176. $color['SteelBlue'] = '#4682B4';
  177. $color['Tan'] = '#D2B48C';
  178. $color['Teal'] = '#008080';
  179. $color['Thistle'] = '#D8BFD8';
  180. $color['Tomato'] = '#FF6347';
  181. $color['Turquoise'] = '#40E0D0';
  182. $color['Violet'] = '#EE82EE';
  183. $color['Wheat'] = '#F5DEB3';
  184. $color['White'] = '#FFFFFF';
  185. $color['WhiteSmoke'] = '#F5F5F5';
  186. $color['Yellow'] = '#FFFF00';
  187. $color['YellowGreen'] = '#9ACD32';
  188. $this->htmlColor = array();
  189. foreach($color as $key => $val) $this->htmlColor[strtolower($key)] = $val;
  190. unset($color);
  191. $this->table = array();
  192. $this->value = array();
  193. $this->initStyle();
  194. // initialisation des styles sans héritages
  195. $this->resetStyle();
  196. }
  197. function initStyle()
  198. {
  199. $this->value['id_balise'] = 'body'; // balise
  200. $this->value['id_name'] = null; // name
  201. $this->value['id_id'] = null; // id
  202. $this->value['id_class'] = null; // class
  203. $this->value['id_lst'] = array('*'); // lst de dependance
  204. $this->value['mini-size'] = 1.; // rapport de taille spécifique aux sup, sub
  205. $this->value['mini-decal'] = 0; // rapport de position spécifique aux sup, sub
  206. $this->value['font-family'] = 'Arial';
  207. $this->value['font-bold'] = false;
  208. $this->value['font-italic'] = false;
  209. $this->value['font-underline'] = false;
  210. $this->value['font-overline'] = false;
  211. $this->value['font-linethrough'] = false;
  212. $this->value['font-size'] = $this->ConvertToMM('10pt');
  213. $this->value['text-indent'] = 0;
  214. $this->value['text-align'] = 'left';
  215. $this->value['vertical-align'] = 'middle';
  216. $this->value['line-height'] = 'normal';
  217. $this->value['position'] = null;
  218. $this->value['x'] = null;
  219. $this->value['y'] = null;
  220. $this->value['width'] = 0;
  221. $this->value['height'] = 0;
  222. $this->value['top'] = null;
  223. $this->value['right'] = null;
  224. $this->value['bottom'] = null;
  225. $this->value['left'] = null;
  226. $this->value['float'] = null;
  227. $this->value['display'] = null;
  228. $this->value['color'] = array(0, 0, 0);
  229. $this->value['background'] = array('color' => null, 'image' => null, 'position' => null, 'repeat' => null);
  230. $this->value['border'] = array();
  231. $this->value['padding'] = array();
  232. $this->value['margin'] = array();
  233. $this->value['margin-auto'] = false;
  234. $this->value['list-style-type'] = '';
  235. $this->value['list-style-image'] = '';
  236. $this->value['xc'] = null;
  237. $this->value['yc'] = null;
  238. }
  239. /**
  240. * Initialisation des styles sans héritages
  241. *
  242. * @param string balise HTML
  243. * @return null
  244. */
  245. function resetStyle($balise = '')
  246. {
  247. $collapse = isset($this->value['border']['collapse']) ? $this->value['border']['collapse'] : false;
  248. if (!in_array($balise, array('tr', 'td', 'th'))) $collapse = false;
  249. $this->value['position'] = null;
  250. $this->value['x'] = null;
  251. $this->value['y'] = null;
  252. $this->value['width'] = 0;
  253. $this->value['height'] = 0;
  254. $this->value['top'] = null;
  255. $this->value['right'] = null;
  256. $this->value['bottom'] = null;
  257. $this->value['left'] = null;
  258. $this->value['float'] = null;
  259. $this->value['display'] = null;
  260. $this->value['background'] = array('color' => null, 'image' => null, 'position' => null, 'repeat' => null);
  261. $this->value['border'] = array(
  262. 't' => $this->readBorder('none'),
  263. 'r' => $this->readBorder('none'),
  264. 'b' => $this->readBorder('none'),
  265. 'l' => $this->readBorder('none'),
  266. 'radius' => array(0, 0),
  267. 'collapse' => $collapse,
  268. );
  269. $this->value['margin'] = array(
  270. 't' => 0,
  271. 'r' => 0,
  272. 'b' => 0,
  273. 'l' => 0
  274. );
  275. $this->value['margin-auto'] = false;
  276. if (in_array($balise, array('div')))
  277. $this->value['vertical-align'] = 'top';
  278. if (in_array($balise, array('ul', 'li')))
  279. {
  280. $this->value['list-style-type'] = '';
  281. $this->value['list-style-image'] = '';
  282. }
  283. if (!in_array($balise, array('tr', 'td')))
  284. {
  285. $this->value['padding'] = array(
  286. 't' => 0,
  287. 'r' => 0,
  288. 'b' => 0,
  289. 'l' => 0
  290. );
  291. }
  292. else
  293. {
  294. $this->value['padding'] = array(
  295. 't' => $this->ConvertToMM('1px'),
  296. 'r' => $this->ConvertToMM('1px'),
  297. 'b' => $this->ConvertToMM('1px'),
  298. 'l' => $this->ConvertToMM('1px')
  299. );
  300. }
  301. if ($balise=='hr')
  302. {
  303. $this->value['border'] = array(
  304. 't' => $this->readBorder('solid 1px #000000'),
  305. 'r' => $this->readBorder('solid 1px #000000'),
  306. 'b' => $this->readBorder('solid 1px #000000'),
  307. 'l' => $this->readBorder('solid 1px #000000'),
  308. 'radius' => array(0, 0),
  309. 'collapse' => false,
  310. );
  311. $this->ConvertBackground('#FFFFFF', $this->value['background']);
  312. }
  313. $this->value['xc'] = null;
  314. $this->value['yc'] = null;
  315. }
  316. /**
  317. * Initialisation de la font PDF
  318. *
  319. * @return null
  320. */
  321. function FontSet()
  322. {
  323. $b = ($this->value['font-bold'] ? 'B' : '');
  324. $i = ($this->value['font-italic'] ? 'I' : '');
  325. $u = ($this->value['font-underline'] ? 'U' : '');
  326. // taille en mm, à ramener en pt
  327. $size = $this->value['font-size'];
  328. $size = 72 * $size / 25.4;
  329. $this->pdf->setOverline($this->value['font-overline']);
  330. $this->pdf->setLinethrough($this->value['font-linethrough']);
  331. // application de la fonte
  332. $this->pdf->SetFont($this->value['font-family'], $b.$i.$u, $this->value['mini-size']*$size);
  333. $this->pdf->SetTextColor($this->value['color'][0],$this->value['color'][1], $this->value['color'][2]);
  334. if ($this->value['background']['color'])
  335. $this->pdf->SetFillColor($this->value['background']['color'][0],$this->value['background']['color'][1], $this->value['background']['color'][2]);
  336. else
  337. $this->pdf->SetFillColor(255);
  338. }
  339. /**
  340. * Monter d'un niveau dans l'historisation
  341. *
  342. * @return null
  343. */
  344. function save()
  345. {
  346. $this->table[count($this->table)] = $this->value;
  347. }
  348. /**
  349. * Descendre d'un niveau dans l'historisation
  350. *
  351. * @return null
  352. */
  353. function load()
  354. {
  355. if (count($this->table))
  356. {
  357. $this->value = $this->table[count($this->table)-1];
  358. unset($this->table[count($this->table)-1]);
  359. }
  360. }
  361. function setPosition(&$current_x, &$current_y)
  362. {
  363. $this->value['xc'] = $current_x;
  364. $this->value['yc'] = $current_y;
  365. if ($this->value['position']=='relative' || $this->value['position']=='absolute')
  366. {
  367. if ($this->value['right']!==null)
  368. {
  369. $x = $this->getLastWidth(true) - $this->value['right'] - $this->value['width'];
  370. if ($this->value['margin']['r']) $x-= $this->value['margin']['r'];
  371. }
  372. else
  373. {
  374. $x = $this->value['left'];
  375. if ($this->value['margin']['l']) $x+= $this->value['margin']['l'];
  376. }
  377. if ($this->value['bottom']!==null)
  378. {
  379. $y = $this->getLastHeight(true) - $this->value['bottom'] - $this->value['height'];
  380. if ($this->value['margin']['b']) $y-= $this->value['margin']['b'];
  381. }
  382. else
  383. {
  384. $y = $this->value['top'];
  385. if ($this->value['margin']['t']) $y+= $this->value['margin']['t'];
  386. }
  387. if ($this->value['position']=='relative')
  388. {
  389. $this->value['x'] = $current_x + $x;
  390. $this->value['y'] = $current_y + $y;
  391. }
  392. else
  393. {
  394. $this->value['x'] = $this->getLastAbsoluteX()+$x;
  395. $this->value['y'] = $this->getLastAbsoluteY()+$y;
  396. }
  397. }
  398. else
  399. {
  400. $this->value['x'] = $current_x;
  401. $this->value['y'] = $current_y;
  402. if ($this->value['margin']['l']) $this->value['x']+= $this->value['margin']['l'];
  403. if ($this->value['margin']['t']) $this->value['y']+= $this->value['margin']['t'];
  404. }
  405. $current_x = $this->value['x'];
  406. $current_y = $this->value['y'];
  407. }
  408. /**
  409. * Analyse un tableau de style provenant du parseurHTML
  410. *
  411. * @param string nom de la balise
  412. * @param array tableau de style
  413. * @return null
  414. */
  415. function analyse($balise, &$param)
  416. {
  417. // preparation
  418. $balise = strtolower($balise);
  419. $id = isset($param['id']) ? strtolower(trim($param['id'])) : null; if (!$id) $id = null;
  420. $name = isset($param['name']) ? strtolower(trim($param['name'])) : null; if (!$name) $name = null;
  421. // lecture de la propriete classe
  422. $class = array();
  423. $tmp = isset($param['class']) ? preg_replace('/[\s]+/', ' ', strtolower($param['class'])) : '';
  424. $tmp = explode(' ', $tmp);
  425. foreach($tmp as $k => $v)
  426. {
  427. $v = trim($v);
  428. if ($v) $class[] = $v;
  429. }
  430. // identification de la balise et des styles direct qui pourraient lui être appliqués
  431. $this->value['id_balise'] = $balise;
  432. $this->value['id_name'] = $name;
  433. $this->value['id_id'] = $id;
  434. $this->value['id_class'] = $class;
  435. $this->value['id_lst'] = array();
  436. $this->value['id_lst'][] = '*';
  437. $this->value['id_lst'][] = $balise;
  438. if (count($class))
  439. {
  440. foreach($class as $v)
  441. {
  442. $this->value['id_lst'][] = '*.'.$v;
  443. $this->value['id_lst'][] = '.'.$v;
  444. $this->value['id_lst'][] = $balise.'.'.$v;
  445. }
  446. }
  447. if ($id)
  448. {
  449. $this->value['id_lst'][] = '*#'.$id;
  450. $this->value['id_lst'][] = '#'.$id;
  451. $this->value['id_lst'][] = $id.'#'.$id;
  452. }
  453. // style CSS
  454. $styles = $this->getFromCSS();
  455. // on ajoute le style propre à la balise
  456. $styles = array_merge($styles, $param['style']);
  457. if (isset($param['allwidth']) && !isset($styles['width'])) $styles['width'] = '100%';
  458. // mise à zero des styles non hérités
  459. $this->resetStyle($balise);
  460. // interpreration des nouvelles valeurs
  461. $correct_width = false;
  462. foreach($styles as $nom => $val)
  463. {
  464. switch($nom)
  465. {
  466. case 'font-family':
  467. $val = explode(',', $val);
  468. $val = trim($val[0]);
  469. if ($val) $this->value['font-family'] = $val;
  470. break;
  471. case 'font-weight':
  472. $this->value['font-bold'] = ($val=='bold');
  473. break;
  474. case 'font-style':
  475. $this->value['font-italic'] = ($val=='italic');
  476. break;
  477. case 'text-decoration':
  478. $val = explode(' ', $val);
  479. $this->value['font-underline'] = (in_array('underline', $val));
  480. $this->value['font-overline'] = (in_array('overline', $val));
  481. $this->value['font-linethrough'] = (in_array('line-through', $val));
  482. break;
  483. case 'text-indent':
  484. $this->value['text-indent'] = $this->ConvertToMM($val);
  485. break;
  486. case 'font-size':
  487. $val = $this->ConvertToMM($val, $this->value['font-size']);
  488. if ($val) $this->value['font-size'] = $val;
  489. break;
  490. case 'color':
  491. $res = null;
  492. $this->value['color'] = $this->ConvertToRVB($val, $res);
  493. if ($balise=='hr')
  494. {
  495. $this->value['border']['l']['color'] = $this->value['color'];
  496. $this->value['border']['t']['color'] = $this->value['color'];
  497. $this->value['border']['r']['color'] = $this->value['color'];
  498. $this->value['border']['b']['color'] = $this->value['color'];
  499. }
  500. break;
  501. case 'text-align':
  502. $this->value['text-align'] = $val;
  503. break;
  504. case 'vertical-align':
  505. $this->value['vertical-align'] = $val;
  506. break;
  507. case 'width':
  508. $this->value['width'] = $this->ConvertToMM($val, $this->getLastWidth());
  509. if ($this->value['width'] && substr($val, -1)=='%') $correct_width=true;
  510. break;
  511. case 'height':
  512. $this->value['height'] = $this->ConvertToMM($val, $this->getLastHeight());
  513. break;
  514. case 'line-height':
  515. if (preg_match('/^[0-9\.]+$/isU', $val)) $val = floor($val*100).'%';
  516. $this->value['line-height'] = $val;
  517. break;
  518. case 'padding':
  519. $val = explode(' ', $val);
  520. foreach($val as $k => $v)
  521. {
  522. $v = trim($v);
  523. if ($v!='') $val[$k] = $v;
  524. else unset($val[$k]);
  525. }
  526. $val = array_values($val);
  527. if (count($val)!=4)
  528. {
  529. $val = $this->ConvertToMM($val[0], 0);
  530. $this->value['padding']['t'] = $val;
  531. $this->value['padding']['r'] = $val;
  532. $this->value['padding']['b'] = $val;
  533. $this->value['padding']['l'] = $val;
  534. }
  535. else
  536. {
  537. $this->value['padding']['t'] = $this->ConvertToMM($val[0], 0);
  538. $this->value['padding']['r'] = $this->ConvertToMM($val[1], 0);
  539. $this->value['padding']['b'] = $this->ConvertToMM($val[2], 0);
  540. $this->value['padding']['l'] = $this->ConvertToMM($val[3], 0);
  541. }
  542. break;
  543. case 'padding-top':
  544. $this->value['padding']['t'] = $this->ConvertToMM($val, 0);
  545. break;
  546. case 'padding-right':
  547. $this->value['padding']['r'] = $this->ConvertToMM($val, 0);
  548. break;
  549. case 'padding-bottom':
  550. $this->value['padding']['b'] = $this->ConvertToMM($val, 0);
  551. break;
  552. case 'padding-left':
  553. $this->value['padding']['l'] = $this->ConvertToMM($val, 0);
  554. break;
  555. case 'margin':
  556. if ($val=='auto')
  557. {
  558. $this->value['margin-auto'] = true;
  559. break;
  560. }
  561. $val = explode(' ', $val);
  562. foreach($val as $k => $v)
  563. {
  564. $v = trim($v);
  565. if ($v!='') $val[$k] = $v;
  566. else unset($val[$k]);
  567. }
  568. $val = array_values($val);
  569. if (count($val)!=4)
  570. {
  571. $val = $this->ConvertToMM($val[0], 0);
  572. $this->value['margin']['t'] = $val;
  573. $this->value['margin']['r'] = $val;
  574. $this->value['margin']['b'] = $val;
  575. $this->value['margin']['l'] = $val;
  576. }
  577. else
  578. {
  579. $this->value['margin']['t'] = $this->ConvertToMM($val[0], 0);
  580. $this->value['margin']['r'] = $this->ConvertToMM($val[1], 0);
  581. $this->value['margin']['b'] = $this->ConvertToMM($val[2], 0);
  582. $this->value['margin']['l'] = $this->ConvertToMM($val[3], 0);
  583. }
  584. break;
  585. case 'margin-top':
  586. $this->value['margin']['t'] = $this->ConvertToMM($val, 0);
  587. break;
  588. case 'margin-right':
  589. $this->value['margin']['r'] = $this->ConvertToMM($val, 0);
  590. break;
  591. case 'margin-bottom':
  592. $this->value['margin']['b'] = $this->ConvertToMM($val, 0);
  593. break;
  594. case 'margin-left':
  595. $this->value['margin']['l'] = $this->ConvertToMM($val, 0);
  596. break;
  597. case 'border':
  598. $val = $this->readBorder($val);
  599. $this->value['border']['t'] = $val;
  600. $this->value['border']['r'] = $val;
  601. $this->value['border']['b'] = $val;
  602. $this->value['border']['l'] = $val;
  603. break;
  604. case 'border-style':
  605. $val = explode(' ', $val);
  606. foreach($val as $val_k => $val_v)
  607. if (!in_array($val_v, array('solid', 'dotted', 'dashed')))
  608. $val[$val_k] = null;
  609. $this->duplicateBorder($val);
  610. if ($val[0]) $this->value['border']['t']['type'] = $val[0];
  611. if ($val[1]) $this->value['border']['r']['type'] = $val[1];
  612. if ($val[2]) $this->value['border']['b']['type'] = $val[2];
  613. if ($val[3]) $this->value['border']['l']['type'] = $val[3];
  614. break;
  615. case 'border-top-style':
  616. if (in_array($val, array('solid', 'dotted', 'dashed')))
  617. $this->value['border']['t']['type'] = $val;
  618. break;
  619. case 'border-right-style':
  620. if (in_array($val, array('solid', 'dotted', 'dashed')))
  621. $this->value['border']['r']['type'] = $val;
  622. break;
  623. case 'border-bottom-style':
  624. if (in_array($val, array('solid', 'dotted', 'dashed')))
  625. $this->value['border']['b']['type'] = $val;
  626. break;
  627. case 'border-left-style':
  628. if (in_array($val, array('solid', 'dotted', 'dashed')))
  629. $this->value['border']['l']['type'] = $val;
  630. break;
  631. case 'border-color':
  632. $res = false;
  633. $val = preg_replace('/,[\s]+/', ',', $val);
  634. $val = explode(' ', $val);
  635. foreach($val as $val_k => $val_v)
  636. {
  637. $val[$val_k] = $this->ConvertToRVB($val_v, $res);
  638. if (!$res) $val[$val_k] = null;
  639. }
  640. $this->duplicateBorder($val);
  641. if (is_array($val[0])) $this->value['border']['t']['color'] = $val[0];
  642. if (is_array($val[1])) $this->value['border']['r']['color'] = $val[1];
  643. if (is_array($val[2])) $this->value['border']['b']['color'] = $val[2];
  644. if (is_array($val[3])) $this->value['border']['l']['color'] = $val[3];
  645. break;
  646. case 'border-top-color':
  647. $res = false;
  648. $val = $this->ConvertToRVB($val, $res);
  649. if ($res) $this->value['border']['t']['color'] = $val;
  650. break;
  651. case 'border-right-color':
  652. $res = false;
  653. $val = $this->ConvertToRVB($val, $res);
  654. if ($res) $this->value['border']['r']['color'] = $val;
  655. break;
  656. case 'border-bottom-color':
  657. $res = false;
  658. $val = $this->ConvertToRVB($val, $res);
  659. if ($res) $this->value['border']['b']['color'] = $val;
  660. break;
  661. case 'border-left-color':
  662. $res = false;
  663. $val = $this->ConvertToRVB($val, $res);
  664. if ($res) $this->value['border']['l']['color'] = $val;
  665. break;
  666. case 'border-width':
  667. $val = explode(' ', $val);
  668. foreach($val as $val_k => $val_v)
  669. {
  670. $val[$val_k] = $this->ConvertToMM($val_v, 0);
  671. }
  672. $this->duplicateBorder($val);
  673. if ($val[0]) $this->value['border']['t']['width'] = $val[0];
  674. if ($val[1]) $this->value['border']['r']['width'] = $val[1];
  675. if ($val[2]) $this->value['border']['b']['width'] = $val[2];
  676. if ($val[3]) $this->value['border']['l']['width'] = $val[3];
  677. break;
  678. case 'border-top-width':
  679. $val = $this->ConvertToMM($val, 0);;
  680. if ($val) $this->value['border']['t']['width'] = $val;
  681. break;
  682. case 'border-right-width':
  683. $val = $this->ConvertToMM($val, 0);;
  684. if ($val) $this->value['border']['r']['width'] = $val;
  685. break;
  686. case 'border-bottom-width':
  687. $val = $this->ConvertToMM($val, 0);;
  688. if ($val) $this->value['border']['b']['width'] = $val;
  689. break;
  690. case 'border-left-width':
  691. $val = $this->ConvertToMM($val, 0);;
  692. if ($val) $this->value['border']['l']['width'] = $val;
  693. break;
  694. case 'border-collapse':
  695. if ($balise=='table') $this->value['border']['collapse'] = ($val=='collapse');
  696. break;
  697. case 'border-radius':
  698. // nettoyage des valeurs
  699. $val = explode(' ', $val);
  700. foreach($val as $k => $v)
  701. {
  702. $v = trim($v);
  703. if ($v)
  704. {
  705. $v = $this->ConvertToMM($v, 0);
  706. if ($v) $val[$k] = $v;
  707. else unset($val[$k]);
  708. }
  709. else unset($val[$k]);
  710. }
  711. $val = array_values($val);
  712. if (!isset($val[1]) && isset($val[0])) $val[1] = $val[0];
  713. if (count($val)==2)
  714. $this->value['border']['radius'] = array($val[0], $val[1]);
  715. break;
  716. case 'border-top':
  717. $this->value['border']['t'] = $this->readBorder($val);
  718. break;
  719. case 'border-right':
  720. $this->value['border']['r'] = $this->readBorder($val);
  721. break;
  722. case 'border-bottom':
  723. $this->value['border']['b'] = $this->readBorder($val);
  724. break;
  725. case 'border-left':
  726. $this->value['border']['l'] = $this->readBorder($val);
  727. break;
  728. case 'background-color':
  729. $this->value['background']['color'] = $this->ConvertBackgroundColor($val);
  730. break;
  731. case 'background-image':
  732. $this->value['background']['image'] = $this->ConvertBackgroundImage($val);
  733. break;
  734. case 'background-position':
  735. $res = null;
  736. $this->value['background']['position'] = $this->ConvertBackgroundPosition($val, $res);
  737. break;
  738. case 'background-repeat':
  739. $this->value['background']['repeat'] = $this->ConvertBackgroundRepeat($val);
  740. break;
  741. case 'background':
  742. $this->ConvertBackground($val, $this->value['background']);
  743. break;
  744. case 'position':
  745. if ($val=='absolute') $this->value['position'] = 'absolute';
  746. else if ($val=='relative') $this->value['position'] = 'relative';
  747. else $this->value['position'] = null;
  748. break;
  749. case 'float':
  750. if ($val=='left') $this->value['float'] = 'left';
  751. else if ($val=='right') $this->value['float'] = 'right';
  752. else $this->value['float'] = null;
  753. break;
  754. case 'display':
  755. if ($val=='inline') $this->value['display'] = 'inline';
  756. else if ($val=='block') $this->value['display'] = 'block';
  757. else if ($val=='none') $this->value['display'] = 'none';
  758. else $this->value['display'] = null;
  759. break;
  760. case 'top':
  761. case 'bottom':
  762. case 'left':
  763. case 'right':
  764. $this->value[$nom] = $val;
  765. break;
  766. case 'list-style':
  767. case 'list-style-type':
  768. case 'list-style-image':
  769. if ($nom=='list-style') $nom = 'list-style-type';
  770. $this->value[$nom] = $val;
  771. break;
  772. default:
  773. break;
  774. }
  775. }
  776. // correction de la largeur pour correspondre au modèle de boite quick
  777. if ($correct_width)
  778. {
  779. if (!in_array($balise, array('table', 'div', 'hr')))
  780. {
  781. $this->value['width']-= $this->value['padding']['l'] + $this->value['padding']['r'];
  782. $this->value['width']-= $this->value['border']['l']['width'] + $this->value['border']['r']['width'];
  783. }
  784. if (in_array($balise, array('th', 'td')))
  785. {
  786. $this->value['width']-= $this->ConvertToMM(isset($param['cellspacing']) ? $param['cellspacing'] : '2px');
  787. }
  788. if ($this->value['width']<0) $this->value['width']=0;
  789. }
  790. else
  791. {
  792. if ($this->value['width'])
  793. {
  794. if ($this->value['border']['l']['width']) $this->value['width'] += $this->value['border']['l']['width'];
  795. if ($this->value['border']['r']['width']) $this->value['width'] += $this->value['border']['r']['width'];
  796. if ($this->value['padding']['l']) $this->value['width'] += $this->value['padding']['l'];
  797. if ($this->value['padding']['r']) $this->value['width'] += $this->value['padding']['r'];
  798. }
  799. }
  800. if ($this->value['height'])
  801. {
  802. if ($this->value['border']['b']['width']) { $this->value['height'] += $this->value['border']['b']['width']; }
  803. if ($this->value['border']['t']['width']) { $this->value['height'] += $this->value['border']['t']['width']; }
  804. if ($this->value['padding']['b']) $this->value['height'] += $this->value['padding']['b'];
  805. if ($this->value['padding']['t']) $this->value['height'] += $this->value['padding']['t'];
  806. }
  807. if ($this->value['top']!=null) $this->value['top'] = $this->ConvertToMM($this->value['top'], $this->getLastHeight(true));
  808. if ($this->value['bottom']!=null) $this->value['bottom'] = $this->ConvertToMM($this->value['bottom'], $this->getLastHeight(true));
  809. if ($this->value['left']!=null) $this->value['left'] = $this->ConvertToMM($this->value['left'], $this->getLastWidth(true));
  810. if ($this->value['right']!=null) $this->value['right'] = $this->ConvertToMM($this->value['right'], $this->getLastWidth(true));
  811. if ($this->value['top'] && $this->value['bottom'] && $this->value['height']) $this->value['bottom'] = null;
  812. if ($this->value['left'] && $this->value['right'] && $this->value['width']) $this->value['right'] = null;
  813. }
  814. /**
  815. * Récupération de la hauteur de ligne courante
  816. *
  817. * @return float hauteur en mm
  818. */
  819. function getLineHeight()
  820. {
  821. $val = $this->value['line-height'];
  822. if ($val=='normal') $val = '108%';
  823. return $this->ConvertToMM($val, $this->value['font-size']);
  824. }
  825. /**
  826. * Récupération de la largeur de l'objet parent
  827. *
  828. * @return float largeur
  829. */
  830. function getLastWidth($mode = false)
  831. {
  832. for($k=count($this->table); $k>0; $k--)
  833. {
  834. if ($this->table[$k-1]['width'])
  835. {
  836. $w = $this->table[$k-1]['width'];
  837. if ($mode)
  838. {
  839. $w+= $this->table[$k-1]['border']['l']['width'] + $this->table[$k-1]['padding']['l']+0.02;
  840. $w+= $this->table[$k-1]['border']['r']['width'] + $this->table[$k-1]['padding']['r']+0.02;
  841. }
  842. return $w;
  843. }
  844. }
  845. return $this->pdf->w - $this->pdf->lMargin - $this->pdf->rMargin;
  846. }
  847. /**
  848. * Récupération de la hauteur de l'objet parent
  849. *
  850. * @return float hauteur
  851. */
  852. function getLastHeight($mode = false)
  853. {
  854. for($k=count($this->table); $k>0; $k--)
  855. {
  856. if ($this->table[$k-1]['height'])
  857. {
  858. $h = $this->table[$k-1]['height'];
  859. if ($mode)
  860. {
  861. $h+= $this->table[$k-1]['border']['t']['width'] + $this->table[$k-1]['padding']['t']+0.02;
  862. $h+= $this->table[$k-1]['border']['b']['width'] + $this->table[$k-1]['padding']['b']+0.02;
  863. }
  864. return $h;
  865. }
  866. }
  867. return $this->pdf->h - $this->pdf->tMargin - $this->pdf->bMargin;
  868. }
  869. function getFloat()
  870. {
  871. if ($this->value['float']=='left') return 'left';
  872. if ($this->value['float']=='right') return 'right';
  873. return null;
  874. }
  875. function getLastAbsoluteX()
  876. {
  877. for($k=count($this->table); $k>0; $k--)
  878. {
  879. if ($this->table[$k-1]['x'] && $this->table[$k-1]['position']) return $this->table[$k-1]['x'];
  880. }
  881. return $this->pdf->lMargin;
  882. }
  883. function getLastAbsoluteY()
  884. {
  885. for($k=count($this->table); $k>0; $k--)
  886. {
  887. if ($this->table[$k-1]['y'] && $this->table[$k-1]['position']) return $this->table[$k-1]['y'];
  888. }
  889. return $this->pdf->tMargin;
  890. }
  891. /**
  892. * Récupération des propriétés CSS de la balise en cours
  893. *
  894. * @return array() tableau des propriétés CSS
  895. */
  896. function getFromCSS()
  897. {
  898. $styles = array(); // style à appliquer
  899. $getit = array(); // styles à récuperer
  900. // identification des styles direct, et ceux des parents
  901. $lst = array();
  902. $lst[] = $this->value['id_lst'];
  903. for($i=count($this->table)-1; $i>=0; $i--) $lst[] = $this->table[$i]['id_lst'];
  904. // identification des styles à récuperer
  905. foreach($this->css_keys as $key => $num)
  906. if ($this->getReccursiveStyle($key, $lst))
  907. $getit[$key] = $num;
  908. // si des styles sont à recuperer
  909. if (count($getit))
  910. {
  911. // on les récupère, mais dans l'odre de définition, afin de garder les priorités
  912. asort($getit);
  913. foreach($getit as $key => $val) $styles = array_merge($styles, $this->css[$key]);
  914. }
  915. return $styles;
  916. }
  917. /**
  918. * Identification des styles à récuperer, en fonction de la balise et de ses parents
  919. *
  920. * @param string clef CSS à analyser
  921. * @param array() tableau des styles direct, et ceux des parents
  922. * @param string prochaine etape
  923. * @return boolean clef autorisée ou non
  924. */
  925. function getReccursiveStyle($key, $lst, $next = null)
  926. {
  927. // si propchaine etape, on construit les valeurs
  928. if ($next!==null)
  929. {
  930. if ($next) $key = trim(substr($key, 0, -strlen($next))); // on elève cette etape
  931. unset($lst[0]);
  932. if (!count($lst)) return false; // pas d'etape possible
  933. $lst = array_values($lst);
  934. }
  935. // pour chaque style direct possible de l'etape en cours
  936. foreach($lst[0] as $nom)
  937. {
  938. if ($key==$nom) return true; // si la clef conrrespond => ok
  939. if (substr($key, -strlen(' '.$nom))==' '.$nom && $this->getReccursiveStyle($key, $lst, $nom)) return true; // si la clef est la fin, on analyse ce qui précède
  940. }
  941. // si on est pas à la premiere etape, on doit analyse toutes les sous etapes
  942. if ($next!==null && $this->getReccursiveStyle($key, $lst, '')) return true;
  943. // aucun style trouvé
  944. return false;
  945. }
  946. /**
  947. * Analyse d'une propriété Border
  948. *
  949. * @param string propriété border
  950. * @return array() propriété décodée
  951. */
  952. function readBorder($val)
  953. {
  954. $none = array('type' => 'none', 'width' => 0, 'color' => array(0, 0, 0));
  955. // valeurs par défault
  956. $type = 'solid';
  957. $width = $this->ConvertToMM('1pt');
  958. $color = array(0, 0, 0);
  959. // nettoyage des valeurs
  960. $val = explode(' ', $val);
  961. foreach($val as $k => $v)
  962. {
  963. $v = trim($v);
  964. if ($v) $val[$k] = $v;
  965. else unset($val[$k]);
  966. }
  967. $val = array_values($val);
  968. // identification des valeurs
  969. $res = null;
  970. foreach($val as $key)
  971. {
  972. if ($key=='none' || $key=='hidden') return $none;
  973. if ($this->ConvertToMM($key)!==null) $width = $this->ConvertToMM($key);
  974. else if (in_array($key, array('solid', 'dotted', 'dashed'))) $type = $key;
  975. else
  976. {
  977. $tmp = $this->ConvertToRVB($key, $res);
  978. if ($res) $color = $tmp;
  979. }
  980. }
  981. if (!$width) return $none;
  982. return array('type' => $type, 'width' => $width, 'color' => $color);
  983. }
  984. function duplicateBorder(&$val)
  985. {
  986. if (count($val)==1)
  987. {
  988. $val[1] = $val[0];
  989. $val[2] = $val[0];
  990. $val[3] = $val[0];
  991. }
  992. else if (count($val)==2)
  993. {
  994. $val[2] = $val[0];
  995. $val[3] = $val[1];
  996. }
  997. else if (count($val)==3)
  998. {
  999. $val[3] = $val[1];
  1000. }
  1001. }
  1002. function ConvertBackground($stl, &$res)
  1003. {
  1004. // Image
  1005. $text = '/url\(([^)]*)\)/isU';
  1006. if (preg_match($text, $stl, $match))
  1007. {
  1008. $res['image'] = $this->ConvertBackgroundImage($match[0]);
  1009. $stl = preg_replace($text, '', $stl);
  1010. $stl = preg_replace('/[\s]+/', ' ', $stl);
  1011. }
  1012. // protection des espaces
  1013. $stl = preg_replace('/,[\s]+/', ',', $stl);
  1014. $lst = explode(' ', $stl);
  1015. $pos = '';
  1016. foreach($lst as $val)
  1017. {
  1018. $ok = false;
  1019. $color = $this->ConvertToRVB($val, $ok);
  1020. if ($ok)
  1021. {
  1022. $res['color'] = $color;
  1023. }
  1024. else if ($val=='transparent')
  1025. {
  1026. $res['color'] = null;
  1027. }
  1028. else
  1029. {
  1030. $repeat = $this->ConvertBackgroundRepeat($val);
  1031. if ($repeat)
  1032. {
  1033. $res['repeat'] = $repeat;
  1034. }
  1035. else
  1036. {
  1037. $pos.= ($pos ? ' ' : '').$val;
  1038. }
  1039. }
  1040. }
  1041. if ($pos)
  1042. {
  1043. $pos = $this->ConvertBackgroundPosition($pos, $ok);
  1044. if ($ok) $res['position'] = $pos;
  1045. }
  1046. }
  1047. function ConvertBackgroundColor($val)
  1048. {
  1049. $res = null;
  1050. if ($val=='transparent') return null;
  1051. else return $this->ConvertToRVB($val, $res);
  1052. }
  1053. function ConvertBackgroundImage($val)
  1054. {
  1055. if ($val=='none')
  1056. return null;
  1057. else if (preg_match('/^url\(([^)]*)\)$/isU', $val, $match))
  1058. return $match[1];
  1059. else
  1060. return null;
  1061. }
  1062. function ConvertBackgroundPosition($val, &$res)
  1063. {
  1064. $val = explode(' ', $val);
  1065. if (count($val)<2)
  1066. {
  1067. if (!$val[0]) return null;
  1068. $val[1] = 'center';
  1069. }
  1070. if (count($val)>2) return null;
  1071. $x = 0;
  1072. $y = 0;
  1073. $res = true;
  1074. if ($val[0]=='left') $x = '0%';
  1075. else if ($val[0]=='center') $x = '50%';
  1076. else if ($val[0]=='right') $x = '100%';
  1077. else if ($val[0]=='top') $y = '0%';
  1078. else if ($val[0]=='bottom') $y = '100%';
  1079. else if (preg_match('/^[-]?[0-9\.]+%$/isU', $val[0])) $x = $val[0];
  1080. else if ($this->ConvertToMM($val[0])) $x = $this->ConvertToMM($val[0]);
  1081. else $res = false;
  1082. if ($val[1]=='left') $x = '0%';
  1083. else if ($val[1]=='right') $x = '100%';
  1084. else if ($val[1]=='top') $y = '0%';
  1085. else if ($val[1]=='center') $y = '50%';
  1086. else if ($val[1]=='bottom') $y = '100%';
  1087. else if (preg_match('/^[-]?[0-9\.]+%$/isU', $val[1])) $y = $val[1];
  1088. else if ($this->ConvertToMM($val[1])) $y = $this->ConvertToMM($val[1]);
  1089. else $res = false;
  1090. $val[0] = $x;
  1091. $val[1] = $y;
  1092. return $val;
  1093. }
  1094. function ConvertBackgroundRepeat($val)
  1095. {
  1096. switch($val)
  1097. {
  1098. case 'repeat':
  1099. return array(true, true);
  1100. case 'repeat-x':
  1101. return array(true, false);
  1102. case 'repeat-y':
  1103. return array(false, true);
  1104. case 'no-repeat':
  1105. return array(false, false);
  1106. }
  1107. return null;
  1108. }
  1109. /**
  1110. * Convertir une longueur en mm
  1111. *
  1112. * @param string longueur, avec unité, à convertir
  1113. * @param float longueur du parent
  1114. * @return float longueur exprimée en mm
  1115. */
  1116. function ConvertToMM($val, $old=0.)
  1117. {
  1118. $val = trim($val);
  1119. if (preg_match('/^[0-9\.\-]+$/isU', $val)) $val.= 'px';
  1120. if (preg_match('/^[0-9\.\-]+px$/isU', $val)) $val = 25.4/96. * str_replace('px', '', $val);
  1121. else if (preg_match('/^[0-9\.\-]+pt$/isU', $val)) $val = 25.4/72. * str_replace('pt', '', $val);
  1122. else if (preg_match('/^[0-9\.\-]+in$/isU', $val)) $val = 25.4 * str_replace('in', '', $val);
  1123. else if (preg_match('/^[0-9\.\-]+mm$/isU', $val)) $val = 1.*str_replace('mm', '', $val);
  1124. else if (preg_match('/^[0-9\.\-]+%$/isU', $val)) $val = 1.*$old*str_replace('%', '', $val)/100.;
  1125. else $val = null;
  1126. return $val;
  1127. }
  1128. /**
  1129. * Décomposition d'un code couleur HTML
  1130. *
  1131. * @param string couleur au format CSS
  1132. * @return array(r, v, b) couleur exprimé par ses comporantes R, V, B, de 0 à 255.
  1133. */
  1134. function ConvertToRVB($val, &$res)
  1135. {
  1136. $val = trim($val);
  1137. $res = true;
  1138. if (strtolower($val)=='transparent') return array(null, null, null);
  1139. if (isset($this->htmlColor[strtolower($val)])) $val = $this->htmlColor[strtolower($val)];
  1140. if (preg_match('/rgb\([\s]*([0-9%]+)[\s]*,[\s]*([0-9%]+)[\s]*,[\s]*([0-9%]+)[\s]*\)/isU', $val, $match))
  1141. {
  1142. $r =$match[1]; if (substr($r, -1)=='%') $r = floor(255*substr($r, 0, -1)/100);
  1143. $v =$match[2]; if (substr($v, -1)=='%') $v = floor(255*substr($v, 0, -1)/100);
  1144. $b =$match[3]; if (substr($b, -1)=='%') $b = floor(255*substr($b, 0, -1)/100);
  1145. }
  1146. else if (strlen($val)==7 && substr($val, 0, 1)=='#')
  1147. {
  1148. $r = hexdec(substr($val, 1, 2));
  1149. $v = hexdec(substr($val, 3, 2));
  1150. $b = hexdec(substr($val, 5, 2));
  1151. }
  1152. else if (strlen($val)==4 && substr($val, 0, 1)=='#')
  1153. {
  1154. $r = hexdec(substr($val, 1, 1).substr($val, 1, 1));
  1155. $v = hexdec(substr($val, 2, 1).substr($val, 2, 1));
  1156. $b = hexdec(substr($val, 3, 1).substr($val, 3, 1));
  1157. }
  1158. else
  1159. {
  1160. $r=0;
  1161. $v=0;
  1162. $b=0;
  1163. $res = false;
  1164. }
  1165. return array(floor($r), floor($v), floor($b));
  1166. }
  1167. /**
  1168. * Analyser une feuille de style
  1169. *
  1170. * @param string code CSS
  1171. * @return null
  1172. */
  1173. function analyseStyle(&$code)
  1174. {
  1175. // on remplace tous les espaces, tab, \r, \n, par des espaces uniques
  1176. $code = preg_replace('/[\s]+/', ' ', $code);
  1177. // on enlève les commentaires
  1178. $code = preg_replace('/\/\*.*?\*\//s', '', $code);
  1179. // on analyse chaque style
  1180. preg_match_all('/([^{}]+){([^}]*)}/isU', $code, $match);
  1181. for($k=0; $k<count($match[0]); $k++)
  1182. {
  1183. // noms
  1184. $noms = strtolower(trim($match[1][$k]));
  1185. // style, séparé par des; => on remplie le tableau correspondant
  1186. $styles = trim($match[2][$k]);
  1187. $styles = explode(';', $styles);
  1188. $stl = array();
  1189. foreach($styles as $style)
  1190. {
  1191. $tmp = explode(':', $style);
  1192. if (count($tmp)>1)
  1193. {
  1194. $cod = $tmp[0]; unset($tmp[0]); $tmp = implode(':', $tmp);
  1195. $stl[trim(strtolower($cod))] = trim($tmp);
  1196. }
  1197. }
  1198. // décomposition des noms par les ,
  1199. $noms = explode(',', $noms);
  1200. foreach($noms as $nom)
  1201. {
  1202. $nom = trim($nom);
  1203. // Si il a une fonction spécifique, comme :hover => on zap
  1204. if (strpos($nom, ':')!==false) continue;
  1205. if (!isset($this->css[$nom]))
  1206. $this->css[$nom] = $stl;
  1207. else
  1208. $this->css[$nom] = array_merge($this->css[$nom], $stl);
  1209. }
  1210. }
  1211. $this->css_keys = array_flip(array_keys($this->css));
  1212. }
  1213. /**
  1214. * Extraction des feuille de style du code HTML
  1215. *
  1216. * @param string code HTML
  1217. * @return null
  1218. */
  1219. function readStyle(&$html)
  1220. {
  1221. $style = ' ';
  1222. // extraction des balises link, et suppression de celles-ci dans le code HTML
  1223. preg_match_all('/<link([^>]*)>/isU', $html, $match);
  1224. $html = preg_replace('/<link[^>]*>/isU', '', $html);
  1225. $html = preg_replace('/<\/link[^>]*>/isU', '', $html);
  1226. // analyse de chaque balise
  1227. foreach($match[1] as $code)
  1228. {
  1229. $tmp = array();
  1230. // lecture des paramétres du type nom=valeur
  1231. $prop = '([a-zA-Z0-9_]+)=([^"\'\s>]+)';
  1232. preg_match_all('/'.$prop.'/is', $code, $match);
  1233. for($k=0; $k<count($match[0]); $k++)
  1234. $tmp[trim(strtolower($match[1][$k]))] = trim($match[2][$k]);
  1235. // lecture des paramétres du type nom="valeur"
  1236. $prop = '([a-zA-Z0-9_]+)=["]([^"]*)["]';
  1237. preg_match_all('/'.$prop.'/is', $code, $match);
  1238. for($k=0; $k<count($match[0]); $k++)
  1239. $tmp[trim(strtolower($match[1][$k]))] = trim($match[2][$k]);
  1240. // lecture des paramétres du type nom='valeur'
  1241. $prop = "([a-zA-Z0-9_]+)=[']([^']*)[']";
  1242. preg_match_all('/'.$prop.'/is', $code, $match);
  1243. for($k=0; $k<count($match[0]); $k++)
  1244. $tmp[trim(strtolower($match[1][$k]))] = trim($match[2][$k]);
  1245. // si de type text/css => on garde
  1246. if (isset($tmp['type']) && strtolower($tmp['type'])=='text/css' && isset($tmp['href']))
  1247. {
  1248. $content = @file_get_contents($tmp['href']);
  1249. $url = $tmp['href'];
  1250. if (strpos($url, 'http://')!==false)
  1251. {
  1252. $url = str_replace('http://', '', $url);
  1253. $url = explode('/', $url);
  1254. $url_main = 'http://'.$url[0].'/';
  1255. $url_self = $url; unset($url_self[count($url_self)-1]); $url_self = 'http://'.implode('/', $url_self).'/';
  1256. $content = preg_replace('/url\(([^\\\\][^)]*)\)/isU', 'url('.$url_self.'$1)', $content);
  1257. $content = preg_replace('/url\((\\\\[^)]*)\)/isU', 'url('.$url_main.'$1)', $content);
  1258. }
  1259. $style.= $content."\n";
  1260. }
  1261. }
  1262. // extraction des balises style, et suppression de celles-ci dans le code HTML
  1263. preg_match_all('/<style[^>]*>(.*)<\/style[^>]*>/isU', $html, $match);
  1264. $html = preg_replace('/<style[^>]*>(.*)<\/style[^>]*>/isU', '', $html);
  1265. // analyse de chaque balise
  1266. foreach($match[1] as $code)
  1267. {
  1268. $code = str_replace('<!--', '', $code);
  1269. $code = str_replace('-->', '', $code);
  1270. $style.= $code."\n";
  1271. }
  1272. $this->analyseStyle($style);
  1273. }
  1274. }
  1275. }
  1276. ?>