Dépôt officiel du core SPIP * Copie possible par svn sur svn://trac.rezo.net/spip * Les svn:externals sont présent dans https://git.spip.net/SPIP/[nom du plugin dist] https://www.spip.net
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

505 lines
14 KiB

  1. <?php
  2. /***************************************************************************\
  3. * SPIP, Systeme de publication pour l'internet *
  4. * *
  5. * Copyright (c) 2001-2019 *
  6. * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
  7. * *
  8. * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
  9. * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
  10. \***************************************************************************/
  11. /**
  12. * Ce fichier contient les fonctions simples
  13. * de traitement d'image.
  14. *
  15. * @package SPIP\Core\Filtres\Images
  16. */
  17. if (!defined('_ECRIRE_INC_VERSION')) {
  18. return;
  19. }
  20. include_spip('inc/filtres_images_lib_mini'); // par precaution
  21. /**
  22. * Transforme un code couleur textuel (black, white, green...) et code hexadécimal
  23. *
  24. * @param string $couleur
  25. * Le code couleur textuel
  26. * @return string
  27. * Le code hexadécimal de la couleur (sans le #) ou le code couleur textuel si non trouvé
  28. */
  29. function couleur_html_to_hex($couleur) {
  30. $couleurs_html = array(
  31. 'aliceblue' => 'F0F8FF',
  32. 'antiquewhite' => 'FAEBD7',
  33. 'aqua' => '00FFFF',
  34. 'aquamarine' => '7FFFD4',
  35. 'azure' => 'F0FFFF',
  36. 'beige' => 'F5F5DC',
  37. 'bisque' => 'FFE4C4',
  38. 'black' => '000000',
  39. 'blanchedalmond' => 'FFEBCD',
  40. 'blue' => '0000FF',
  41. 'blueviolet' => '8A2BE2',
  42. 'brown' => 'A52A2A',
  43. 'burlywood' => 'DEB887',
  44. 'cadetblue' => '5F9EA0',
  45. 'chartreuse' => '7FFF00',
  46. 'chocolate' => 'D2691E',
  47. 'coral' => 'FF7F50',
  48. 'cornflowerblue' => '6495ED',
  49. 'cornsilk' => 'FFF8DC',
  50. 'crimson' => 'DC143C',
  51. 'cyan' => '00FFFF',
  52. 'darkblue' => '00008B',
  53. 'darkcyan' => '008B8B',
  54. 'darkgoldenrod' => 'B8860B',
  55. 'darkgray' => 'A9A9A9',
  56. 'darkgreen' => '006400',
  57. 'darkgrey' => 'A9A9A9',
  58. 'darkkhaki' => 'BDB76B',
  59. 'darkmagenta' => '8B008B',
  60. 'darkolivegreen' => '556B2F',
  61. 'darkorange' => 'FF8C00',
  62. 'darkorchid' => '9932CC',
  63. 'darkred' => '8B0000',
  64. 'darksalmon' => 'E9967A',
  65. 'darkseagreen' => '8FBC8F',
  66. 'darkslateblue' => '483D8B',
  67. 'darkslategray' => '2F4F4F',
  68. 'darkslategrey' => '2F4F4F',
  69. 'darkturquoise' => '00CED1',
  70. 'darkviolet' => '9400D3',
  71. 'deeppink' => 'FF1493',
  72. 'deepskyblue' => '00BFFF',
  73. 'dimgray' => '696969',
  74. 'dimgrey' => '696969',
  75. 'dodgerblue' => '1E90FF',
  76. 'firebrick' => 'B22222',
  77. 'floralwhite' => 'FFFAF0',
  78. 'forestgreen' => '228B22',
  79. 'fuchsia' => 'FF00FF',
  80. 'gainsboro' => 'DCDCDC',
  81. 'ghostwhite' => 'F8F8FF',
  82. 'gold' => 'FFD700',
  83. 'goldenrod' => 'DAA520',
  84. 'gray' => '808080',
  85. 'green' => '008000',
  86. 'greenyellow' => 'ADFF2F',
  87. 'grey' => '808080',
  88. 'honeydew' => 'F0FFF0',
  89. 'hotpink' => 'FF69B4',
  90. 'indianred' => 'CD5C5C',
  91. 'indigo' => '4B0082',
  92. 'ivory' => 'FFFFF0',
  93. 'khaki' => 'F0E68C',
  94. 'lavender' => 'E6E6FA',
  95. 'lavenderblush' => 'FFF0F5',
  96. 'lawngreen' => '7CFC00',
  97. 'lemonchiffon' => 'FFFACD',
  98. 'lightblue' => 'ADD8E6',
  99. 'lightcoral' => 'F08080',
  100. 'lightcyan' => 'E0FFFF',
  101. 'lightgoldenrodyellow' => 'FAFAD2',
  102. 'lightgray' => 'D3D3D3',
  103. 'lightgreen' => '90EE90',
  104. 'lightgrey' => 'D3D3D3',
  105. 'lightpink' => 'FFB6C1',
  106. 'lightsalmon' => 'FFA07A',
  107. 'lightseagreen' => '20B2AA',
  108. 'lightskyblue' => '87CEFA',
  109. 'lightslategray' => '778899',
  110. 'lightslategrey' => '778899',
  111. 'lightsteelblue' => 'B0C4DE',
  112. 'lightyellow' => 'FFFFE0',
  113. 'lime' => '00FF00',
  114. 'limegreen' => '32CD32',
  115. 'linen' => 'FAF0E6',
  116. 'magenta' => 'FF00FF',
  117. 'maroon' => '800000',
  118. 'mediumaquamarine' => '66CDAA',
  119. 'mediumblue' => '0000CD',
  120. 'mediumorchid' => 'BA55D3',
  121. 'mediumpurple' => '9370DB',
  122. 'mediumseagreen' => '3CB371',
  123. 'mediumslateblue' => '7B68EE',
  124. 'mediumspringgreen' => '00FA9A',
  125. 'mediumturquoise' => '48D1CC',
  126. 'mediumvioletred' => 'C71585',
  127. 'midnightblue' => '191970',
  128. 'mintcream' => 'F5FFFA',
  129. 'mistyrose' => 'FFE4E1',
  130. 'moccasin' => 'FFE4B5',
  131. 'navajowhite' => 'FFDEAD',
  132. 'navy' => '000080',
  133. 'oldlace' => 'FDF5E6',
  134. 'olive' => '808000',
  135. 'olivedrab' => '6B8E23',
  136. 'orange' => 'FFA500',
  137. 'orangered' => 'FF4500',
  138. 'orchid' => 'DA70D6',
  139. 'palegoldenrod' => 'EEE8AA',
  140. 'palegreen' => '98FB98',
  141. 'paleturquoise' => 'AFEEEE',
  142. 'palevioletred' => 'DB7093',
  143. 'papayawhip' => 'FFEFD5',
  144. 'peachpuff' => 'FFDAB9',
  145. 'peru' => 'CD853F',
  146. 'pink' => 'FFC0CB',
  147. 'plum' => 'DDA0DD',
  148. 'powderblue' => 'B0E0E6',
  149. 'purple' => '800080',
  150. 'rebeccapurple' => '663399',
  151. 'red' => 'FF0000',
  152. 'rosybrown' => 'BC8F8F',
  153. 'royalblue' => '4169E1',
  154. 'saddlebrown' => '8B4513',
  155. 'salmon' => 'FA8072',
  156. 'sandybrown' => 'F4A460',
  157. 'seagreen' => '2E8B57',
  158. 'seashell' => 'FFF5EE',
  159. 'sienna' => 'A0522D',
  160. 'silver' => 'C0C0C0',
  161. 'skyblue' => '87CEEB',
  162. 'slateblue' => '6A5ACD',
  163. 'slategray' => '708090',
  164. 'slategrey' => '708090',
  165. 'snow' => 'FFFAFA',
  166. 'springgreen' => '00FF7F',
  167. 'steelblue' => '4682B4',
  168. 'tan' => 'D2B48C',
  169. 'teal' => '008080',
  170. 'thistle' => 'D8BFD8',
  171. 'tomato' => 'FF6347',
  172. 'turquoise' => '40E0D0',
  173. 'violet' => 'EE82EE',
  174. 'wheat' => 'F5DEB3',
  175. 'white' => 'FFFFFF',
  176. 'whitesmoke' => 'F5F5F5',
  177. 'yellow' => 'FFFF00',
  178. 'yellowgreen' => '9ACD32',
  179. );
  180. if (isset($couleurs_html[$lc = strtolower($couleur)])) {
  181. return $couleurs_html[$lc];
  182. }
  183. return $couleur;
  184. }
  185. /**
  186. * Rend une couleur (code hexadécimal) plus foncée
  187. *
  188. * @uses _couleur_hex_to_dec() Pour transformer le code hexadécimal en décimal
  189. *
  190. * @param string $couleur
  191. * Code hexadécimal d'une couleur
  192. * @param float $coeff
  193. * Coefficient (de 0 à 1)
  194. * @return string
  195. * Code hexadécimal de la couleur plus foncée
  196. */
  197. function couleur_foncer($couleur, $coeff = 0.5) {
  198. $couleurs = _couleur_hex_to_dec($couleur);
  199. $red = $couleurs['red'] - round(($couleurs['red']) * $coeff);
  200. $green = $couleurs['green'] - round(($couleurs['green']) * $coeff);
  201. $blue = $couleurs['blue'] - round(($couleurs['blue']) * $coeff);
  202. $couleur = _couleur_dec_to_hex($red, $green, $blue);
  203. return $couleur;
  204. }
  205. /**
  206. * Eclaircit une couleur (code hexadécimal)
  207. *
  208. * @uses _couleur_hex_to_dec() Pour transformer le code hexadécimal en décimal
  209. *
  210. * @param string $couleur
  211. * Code hexadécimal d'une couleur
  212. * @param float $coeff
  213. * Coefficient (de 0 à 1)
  214. * @return string
  215. * Code hexadécimal de la couleur éclaircie
  216. */
  217. function couleur_eclaircir($couleur, $coeff = 0.5) {
  218. $couleurs = _couleur_hex_to_dec($couleur);
  219. $red = $couleurs['red'] + round((255 - $couleurs['red']) * $coeff);
  220. $green = $couleurs['green'] + round((255 - $couleurs['green']) * $coeff);
  221. $blue = $couleurs['blue'] + round((255 - $couleurs['blue']) * $coeff);
  222. $couleur = _couleur_dec_to_hex($red, $green, $blue);
  223. return $couleur;
  224. }
  225. /**
  226. * Selectionne les images qui vont subir une transformation sur un critere de taille
  227. *
  228. * Les images exclues sont marquees d'une class filtre_inactif qui bloque les filtres suivants
  229. * dans la fonction image_filtrer
  230. *
  231. * @param string $img
  232. * Un tag html `<img src=... />`.
  233. * @param int $width_min
  234. * Largeur minimale de l'image à traiter (0 par défaut)
  235. * @param int $height_min
  236. * Hauteur minimale de l'image à traiter (0 par défaut)
  237. * @param int $width_max
  238. * Largeur minimale de l'image à traiter (10000 par défaut)
  239. * @param int $height_max
  240. * Hauteur minimale de l'image à traiter (10000 par défaut)
  241. * @return
  242. * Le tag html `<img src=... />` avec une class `filtre_inactif` ou pas
  243. */
  244. function image_select($img, $width_min = 0, $height_min = 0, $width_max = 10000, $height_max = 1000) {
  245. if (!$img) {
  246. return $img;
  247. }
  248. list($h, $l) = taille_image($img);
  249. $select = true;
  250. if ($l < $width_min or $l > $width_max or $h < $height_min or $h > $height_max) {
  251. $select = false;
  252. }
  253. $class = extraire_attribut($img, 'class');
  254. $p = strpos($class, 'filtre_inactif');
  255. if (($select == false) and ($p === false)) {
  256. $class .= ' filtre_inactif';
  257. $img = inserer_attribut($img, 'class', $class);
  258. }
  259. if (($select == true) and ($p !== false)) {
  260. // no_image_filtrer : historique, a virer
  261. $class = preg_replace(',\s*(filtre_inactif|no_image_filtrer),', '', $class);
  262. $img = inserer_attribut($img, 'class', $class);
  263. }
  264. return $img;
  265. }
  266. /**
  267. * Réduit les images à une taille maximale (chevauchant un rectangle)
  268. *
  269. * L'image possède un côté réduit dans les dimensions indiquées et
  270. * l'autre côté (hauteur ou largeur) de l'image peut être plus grand
  271. * que les dimensions du rectangle.
  272. *
  273. * Alors que image_reduire produit la plus petite image tenant dans un
  274. * rectangle, image_passe_partout produit la plus grande image qui
  275. * remplit ce rectangle.
  276. *
  277. * @example
  278. * ```
  279. * [(#FICHIER
  280. * |image_passe_partout{70,70}
  281. * |image_recadre{70,70,center})]
  282. * ```
  283. *
  284. * @filtre
  285. * @link http://www.spip.net/4562
  286. * @see image_reduire()
  287. * @uses taille_image()
  288. * @uses ratio_passe_partout()
  289. * @uses process_image_reduire()
  290. *
  291. * @param string $img
  292. * Chemin de l'image ou code html d'une balise img
  293. * @param int $taille_x
  294. * - Largeur maximale en pixels désirée
  295. * - -1 prend la taille de réduction des vignettes par défaut
  296. * - 0 la taille s'adapte à la largeur
  297. * @param int $taille_y
  298. * - Hauteur maximale en pixels désirée
  299. * - -1 pour prendre pareil que la largeur
  300. * - 0 la taille s'adapte à la hauteur
  301. * @param bool $force
  302. * @param bool $cherche_image
  303. * Inutilisé
  304. * @param string $process
  305. * Librairie graphique à utiliser (gd1, gd2, netpbm, convert, imagick).
  306. * AUTO utilise la librairie sélectionnée dans la configuration.
  307. * @return string
  308. * Code HTML de l'image ou du texte.
  309. **/
  310. function image_passe_partout(
  311. $img,
  312. $taille_x = -1,
  313. $taille_y = -1,
  314. $force = false,
  315. $cherche_image = false,
  316. $process = 'AUTO'
  317. ) {
  318. if (!$img) {
  319. return '';
  320. }
  321. list($hauteur, $largeur) = taille_image($img);
  322. if ($taille_x == -1) {
  323. $taille_x = isset($GLOBALS['meta']['taille_preview']) ? $GLOBALS['meta']['taille_preview'] : 150;
  324. }
  325. if ($taille_y == -1) {
  326. $taille_y = $taille_x;
  327. }
  328. if ($taille_x == 0 and $taille_y > 0) {
  329. $taille_x = 1;
  330. } # {0,300} -> c'est 300 qui compte
  331. elseif ($taille_x > 0 and $taille_y == 0) {
  332. $taille_y = 1;
  333. } # {300,0} -> c'est 300 qui compte
  334. elseif ($taille_x == 0 and $taille_y == 0) {
  335. return '';
  336. }
  337. list($destWidth, $destHeight, $ratio) = ratio_passe_partout($largeur, $hauteur, $taille_x, $taille_y);
  338. $fonction = array('image_passe_partout', func_get_args());
  339. return process_image_reduire($fonction, $img, $destWidth, $destHeight, $force, $process);
  340. }
  341. /**
  342. * Réduit les images à une taille maximale (inscrite dans un rectangle)
  343. *
  344. * L'image possède un côté dans les dimensions indiquées et
  345. * l'autre côté (hauteur ou largeur) de l'image peut être plus petit
  346. * que les dimensions du rectangle.
  347. *
  348. * Peut être utilisé pour réduire toutes les images d'un texte.
  349. *
  350. * @example
  351. * ```
  352. * [(#LOGO_ARTICLE|image_reduire{130})]
  353. * [(#TEXTE|image_reduire{600,0})]
  354. * ```
  355. *
  356. * @filtre
  357. * @see image_reduire_par()
  358. * @see image_passe_partout()
  359. * @uses process_image_reduire()
  360. *
  361. * @param string $img
  362. * Chemin de l'image ou code html d'une balise img
  363. * @param int $taille
  364. * - Largeur maximale en pixels désirée
  365. * - -1 prend la taille de réduction des vignettes par défaut
  366. * - 0 la taille s'adapte à la largeur
  367. * @param int $taille_y
  368. * - Hauteur maximale en pixels désirée
  369. * - -1 pour prendre pareil que la largeur
  370. * - 0 la taille s'adapte à la hauteur
  371. * @param bool $force
  372. * @param bool $cherche_image
  373. * Inutilisé
  374. * @param string $process
  375. * Librairie graphique à utiliser (gd1, gd2, netpbm, convert, imagick).
  376. * AUTO utilise la librairie sélectionnée dans la configuration.
  377. * @return string
  378. * Code HTML de l'image ou du texte.
  379. **/
  380. function image_reduire($img, $taille = -1, $taille_y = -1, $force = false, $cherche_image = false, $process = 'AUTO') {
  381. // Determiner la taille x,y maxi
  382. // prendre le reglage de previsu par defaut
  383. if ($taille == -1) {
  384. $taille = (isset($GLOBALS['meta']['taille_preview']) and intval($GLOBALS['meta']['taille_preview'])) ? intval($GLOBALS['meta']['taille_preview']) : 150;
  385. }
  386. if ($taille_y == -1) {
  387. $taille_y = $taille;
  388. }
  389. if ($taille == 0 and $taille_y > 0) {
  390. $taille = 10000;
  391. } # {0,300} -> c'est 300 qui compte
  392. elseif ($taille > 0 and $taille_y == 0) {
  393. $taille_y = 10000;
  394. } # {300,0} -> c'est 300 qui compte
  395. elseif ($taille == 0 and $taille_y == 0) {
  396. return '';
  397. }
  398. $fonction = array('image_reduire', func_get_args());
  399. return process_image_reduire($fonction, $img, $taille, $taille_y, $force, $process);
  400. }
  401. /**
  402. * Réduit les images d'un certain facteur
  403. *
  404. * @filtre
  405. * @uses image_reduire()
  406. *
  407. * @param string $img
  408. * Chemin de l'image ou code html d'une balise img
  409. * @param int $val
  410. * Facteur de réduction
  411. * @param bool $force
  412. * @return string
  413. * Code HTML de l'image ou du texte.
  414. **/
  415. function image_reduire_par($img, $val = 1, $force = false) {
  416. list($hauteur, $largeur) = taille_image($img);
  417. $l = round($largeur / $val);
  418. $h = round($hauteur / $val);
  419. if ($l > $h) {
  420. $h = 0;
  421. } else {
  422. $l = 0;
  423. }
  424. $img = image_reduire($img, $l, $h, $force);
  425. return $img;
  426. }
  427. /**
  428. * Modifie la saturation de la couleur transmise
  429. *
  430. * @note
  431. * Nécessite le plugin `filtres_images` pour fonctionner.
  432. * La couleur d’entrée est retournée tel quelle en cas d'absence.
  433. *
  434. * @see couleur_saturation() du plugin `filtres_images`
  435. * @uses couleur_saturation()
  436. *
  437. * @param string $couleur
  438. * Couleur en écriture hexadécimale, tel que `ff3300`
  439. * @param float $val
  440. * Pourcentage désiré (entre 0 et 1)
  441. * @return string
  442. * Couleur en écriture hexadécimale.
  443. **/
  444. function filtre_couleur_saturation_dist($couleur, $val) {
  445. if (function_exists('couleur_saturation')) {
  446. return couleur_saturation($couleur, $val);
  447. }
  448. return $couleur;
  449. }
  450. /**
  451. * Modifie la luminance de la couleur transmise
  452. *
  453. * @note
  454. * Nécessite le plugin `filtres_images` pour fonctionner.
  455. * La couleur d’entrée est retournée tel quelle en cas d'absence.
  456. *
  457. * @see couleur_luminance() du plugin `filtres_images`
  458. * @uses couleur_luminance()
  459. *
  460. * @param string $couleur
  461. * Couleur en écriture hexadécimale, tel que `ff3300`
  462. * @param float $val
  463. * Pourcentage désiré (entre 0 et 1)
  464. * @return string
  465. * Couleur en écriture hexadécimale.
  466. **/
  467. function filtre_couleur_luminance_dist($couleur, $val) {
  468. if (function_exists('couleur_luminance')) {
  469. return couleur_luminance($couleur, $val);
  470. }
  471. return $couleur;
  472. }