styleHTML.class.php 47 KB

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