PageRenderTime 47ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/spip/ecrire/inc/filtres_images_lib_mini.php

https://github.com/eyeswebcrea/espace-couture-sittler.fr
PHP | 931 lines | 681 code | 103 blank | 147 comment | 193 complexity | b90b24e6486dcbdff7c7ead4f8845420 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-3.0
  1. <?php
  2. /***************************************************************************\
  3. * SPIP, Systeme de publication pour l'internet *
  4. * *
  5. * Copyright (c) 2001-2011 *
  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. if (!defined('_ECRIRE_INC_VERSION')) return;
  12. include_spip('inc/filtres'); // par precaution
  13. /**
  14. * Transforme une couleur vectorielle R,G,B en hexa
  15. *
  16. * @param int $red
  17. * @param int $green
  18. * @param int $blue
  19. * @return string
  20. */
  21. function _couleur_dec_to_hex($red, $green, $blue) {
  22. $red = dechex($red);
  23. $green = dechex($green);
  24. $blue = dechex($blue);
  25. if (strlen($red) == 1) $red = "0".$red;
  26. if (strlen($green) == 1) $green = "0".$green;
  27. if (strlen($blue) == 1) $blue = "0".$blue;
  28. return "$red$green$blue";
  29. }
  30. /**
  31. * Transforme une couleur hexa en vectorielle R,G,B
  32. *
  33. * @param string $couleur
  34. * @return array
  35. */
  36. function _couleur_hex_to_dec($couleur) {
  37. include_spip("inc/filtres_images_mini");
  38. $couleur = couleur_html_to_hex($couleur);
  39. $couleur = preg_replace(",^#,","",$couleur);
  40. $retour["red"] = hexdec(substr($couleur, 0, 2));
  41. $retour["green"] = hexdec(substr($couleur, 2, 2));
  42. $retour["blue"] = hexdec(substr($couleur, 4, 2));
  43. return $retour;
  44. }
  45. function statut_effacer_images_temporaires($stat){
  46. static $statut = false; // par defaut on grave toute les images
  47. // une constante a utiliser lorsqu'on a des filtres image_xxx qui ne produisent pas des images
  48. if (defined('_CONSERVER_IMAGES_TEMPORAIRES'))
  49. $statut = false;
  50. if ($stat==='get') return $statut;
  51. $statut = $stat?true:false;
  52. }
  53. // http://doc.spip.org/@cherche_image_nommee
  54. function cherche_image_nommee($nom, $formats = array ('gif', 'jpg', 'png')) {
  55. if (strncmp(_DIR_IMG, $nom,$n=strlen(_DIR_IMG))==0) {
  56. $nom = substr($nom,$n);
  57. } else if (strncmp(_DIR_IMG_PACK, $nom,$n=strlen(_DIR_IMG_PACK))==0) {
  58. $nom = substr($nom,$n);
  59. } else if (strncmp(_DIR_IMG_ICONE_DIST, $nom,$n=strlen(_DIR_IMG_ICONES_DIST))==0) {
  60. $nom = substr($nom,$n);
  61. }
  62. $pos = strrpos($nom, "/");
  63. if ($pos > 0) {
  64. $chemin = substr($nom, 0, $pos+1);
  65. $nom = substr($nom, $pos+1);
  66. } else {
  67. $chemin = "";
  68. }
  69. reset($formats);
  70. while (list(, $format) = each($formats)) {
  71. if (@file_exists(_DIR_IMG . "$chemin$nom.$format")){
  72. return array((_DIR_IMG . $chemin), $nom, $format);
  73. } else if (@file_exists(_DIR_IMG_PACK . "$chemin$nom.$format")){
  74. return array((_DIR_IMG_PACK . $chemin), $nom, $format);
  75. } else if (@file_exists(_DIR_IMG_ICONES_DIST . "$chemin$nom.$format")){
  76. return array((_DIR_IMG_ICONES_DIST . $chemin), $nom, $format);
  77. }
  78. }
  79. }
  80. // Fonctions de traitement d'image
  81. // uniquement pour GD2
  82. // http://doc.spip.org/@image_valeurs_trans
  83. function _image_valeurs_trans($img, $effet, $forcer_format = false, $fonction_creation = NULL) {
  84. static $images_recalcul = array();
  85. if (strlen($img)==0) return false;
  86. $source = trim(extraire_attribut($img, 'src'));
  87. if (strlen($source) < 1){
  88. $source = $img;
  89. $img = "<img src='$source' />";
  90. }
  91. // les protocoles web prennent au moins 3 lettres
  92. if (preg_match(';^(\w{3,7}://);', $source)){
  93. include_spip('inc/distant');
  94. $fichier = _DIR_RACINE . copie_locale($source);
  95. if (!$fichier) return "";
  96. } else {
  97. // enlever le timestamp eventuel
  98. $source=preg_replace(',[?][0-9]+$,','',$source);
  99. $fichier = $source;
  100. }
  101. $terminaison_dest = "";
  102. if (preg_match(",\.(gif|jpe?g|png)($|[?]),i", $fichier, $regs)) {
  103. $terminaison = strtolower($regs[1]);
  104. $terminaison_dest = $terminaison;
  105. if ($terminaison == "gif") $terminaison_dest = "png";
  106. }
  107. if ($forcer_format!==false) $terminaison_dest = $forcer_format;
  108. if (!$terminaison_dest) return false;
  109. $term_fonction = $terminaison;
  110. if ($term_fonction == "jpg") $term_fonction = "jpeg";
  111. $nom_fichier = substr($fichier, 0, strlen($fichier) - (strlen($terminaison) + 1));
  112. $fichier_dest = $nom_fichier;
  113. if (@file_exists($f = $fichier)){
  114. list ($ret["hauteur"],$ret["largeur"]) = taille_image($img);
  115. $date_src = @filemtime($f);
  116. }
  117. elseif (@file_exists($f = "$fichier.src")
  118. AND lire_fichier($f,$valeurs)
  119. AND $valeurs=unserialize($valeurs)
  120. AND isset($valeurs["hauteur_dest"])
  121. AND isset($valeurs["largeur_dest"])) {
  122. $ret["hauteur"] = $valeurs["hauteur_dest"];
  123. $ret["largeur"] = $valeurs["largeur_dest"];
  124. $date_src = $valeurs["date"];
  125. }
  126. // pas de fichier source par la
  127. else
  128. return false;
  129. // pas de taille mesurable
  130. if (!($ret["hauteur"] OR $ret["largeur"]))
  131. return false;
  132. // cas general :
  133. // on a un dossier cache commun et un nom de fichier qui varie avec l'effet
  134. // cas particulier de reduire :
  135. // un cache par dimension, et le nom de fichier est conserve, suffixe par la dimension aussi
  136. $cache = "cache-gd2";
  137. if (substr($effet,0,7)=='reduire') {
  138. list(,$maxWidth,$maxHeight) = explode('-',$effet);
  139. list ($destWidth,$destHeight) = _image_ratio($ret['largeur'], $ret['hauteur'], $maxWidth, $maxHeight);
  140. $ret['largeur_dest'] = $destWidth;
  141. $ret['hauteur_dest'] = $destHeight;
  142. $effet = "L{$destWidth}xH$destHeight";
  143. $cache = "cache-vignettes";
  144. $fichier_dest = basename($fichier_dest);
  145. if (($ret['largeur']<=$maxWidth)&&($ret['hauteur']<=$maxHeight)){
  146. // on garde la terminaison initiale car image simplement copiee
  147. // et on postfixe son nom avec un md5 du path
  148. $terminaison_dest = $terminaison;
  149. $fichier_dest .= '-'.substr(md5("$fichier"),0,5);
  150. }
  151. else
  152. $fichier_dest .= '-'.substr(md5("$fichier-$effet"),0,5);
  153. $cache = sous_repertoire(_DIR_VAR, $cache);
  154. $cache = sous_repertoire($cache, $effet);
  155. # cherche un cache existant
  156. /*foreach (array('gif','jpg','png') as $fmt)
  157. if (@file_exists($cache . $fichier_dest . '.' . $fmt)) {
  158. $terminaison_dest = $fmt;
  159. }*/
  160. }
  161. else {
  162. $fichier_dest = md5("$fichier-$effet");
  163. $cache = sous_repertoire(_DIR_VAR, $cache);
  164. }
  165. $fichier_dest = $cache . $fichier_dest . "." .$terminaison_dest;
  166. $GLOBALS["images_calculees"][] = $fichier_dest;
  167. $creer = true;
  168. // si recalcul des images demande, recalculer chaque image une fois
  169. if (isset($GLOBALS['var_images']) && $GLOBALS['var_images'] && !isset($images_recalcul[$fichier_dest])){
  170. $images_recalcul[$fichier_dest] = true;
  171. }
  172. else {
  173. if (@file_exists($f = $fichier_dest)){
  174. if (filemtime($f)>=$date_src)
  175. $creer = false;
  176. }
  177. else if (@file_exists($f = "$fichier_dest.src")
  178. AND lire_fichier($f,$valeurs)
  179. AND $valeurs=unserialize($valeurs)
  180. AND $valeurs["date"]>=$date_src)
  181. $creer = false;
  182. }
  183. if ($creer) {
  184. if (!@file_exists($fichier)) {
  185. if (!@file_exists("$fichier.src")) {
  186. spip_log("Image absente : $fichier");
  187. return false;
  188. }
  189. # on reconstruit l'image source absente a partir de la chaine des .src
  190. reconstruire_image_intermediaire($fichier);
  191. }
  192. }
  193. // todo: si une image png est nommee .jpg, le reconnaitre avec le bon $f
  194. $f = "imagecreatefrom".$term_fonction;
  195. if (!function_exists($f)) return false;
  196. $ret["fonction_imagecreatefrom"] = $f;
  197. $ret["fichier"] = $fichier;
  198. $ret["fonction_image"] = "_image_image".$terminaison_dest;
  199. $ret["fichier_dest"] = $fichier_dest;
  200. $ret["format_source"] = ($terminaison != 'jpeg' ? $terminaison : 'jpg');
  201. $ret["format_dest"] = $terminaison_dest;
  202. $ret["date_src"] = $date_src;
  203. $ret["creer"] = $creer;
  204. $ret["class"] = extraire_attribut($img, 'class');
  205. $ret["alt"] = extraire_attribut($img, 'alt');
  206. $ret["style"] = extraire_attribut($img, 'style');
  207. $ret["tag"] = $img;
  208. if ($fonction_creation){
  209. $ret["reconstruction"] = $fonction_creation;
  210. # ecrire ici comment creer le fichier, car il est pas sur qu'on l'ecrira reelement
  211. # cas de image_reduire qui finalement ne reduit pas l'image source
  212. # ca evite d'essayer de le creer au prochain hit si il n'est pas la
  213. #ecrire_fichier($ret['fichier_dest'].'.src',serialize($ret),true);
  214. }
  215. return $ret;
  216. }
  217. // http://doc.spip.org/@image_imagepng
  218. function _image_imagepng($img,$fichier) {
  219. if (!function_exists('imagepng')) return false;
  220. $tmp = $fichier.".tmp";
  221. $ret = imagepng($img,$tmp);
  222. $taille_test = getimagesize($tmp);
  223. if ($taille_test[0] < 1) return false;
  224. spip_unlink($fichier); // le fichier peut deja exister
  225. @rename($tmp, $fichier);
  226. return $ret;
  227. }
  228. // http://doc.spip.org/@image_imagegif
  229. function _image_imagegif($img,$fichier) {
  230. if (!function_exists('imagegif')) return false;
  231. $tmp = $fichier.".tmp";
  232. $ret = imagegif($img,$tmp);
  233. $taille_test = getimagesize($tmp);
  234. if ($taille_test[0] < 1) return false;
  235. spip_unlink($fichier); // le fichier peut deja exister
  236. @rename($tmp, $fichier);
  237. return $ret;
  238. }
  239. // http://doc.spip.org/@image_imagejpg
  240. function _image_imagejpg($img,$fichier,$qualite=_IMG_GD_QUALITE) {
  241. if (!function_exists('imagejpeg')) return false;
  242. $tmp = $fichier.".tmp";
  243. $ret = imagejpeg($img,$tmp, $qualite);
  244. $taille_test = getimagesize($tmp);
  245. if ($taille_test[0] < 1) return false;
  246. spip_unlink($fichier); // le fichier peut deja exister
  247. @rename($tmp, $fichier);
  248. return $ret;
  249. }
  250. // http://doc.spip.org/@image_imageico
  251. function _image_imageico($img, $fichier) {
  252. $gd_image_array = array($img);
  253. return ecrire_fichier($fichier, phpthumb_functions::GD2ICOstring($gd_image_array));
  254. }
  255. // $qualite est utilise pour la qualite de compression des jpeg
  256. // http://doc.spip.org/@image_gd_output
  257. function _image_gd_output($img,$valeurs, $qualite=_IMG_GD_QUALITE){
  258. $fonction = "_image_image".$valeurs['format_dest'];
  259. $ret = false;
  260. #un flag pour reperer les images gravees
  261. $lock =
  262. !statut_effacer_images_temporaires('get') // si la fonction n'a pas ete activee, on grave tout
  263. OR (@file_exists($valeurs['fichier_dest']) AND !@file_exists($valeurs['fichier_dest'].'.src'));
  264. if (
  265. function_exists($fonction)
  266. && ($ret = $fonction($img,$valeurs['fichier_dest'],$qualite)) # on a reussi a creer l'image
  267. && isset($valeurs['reconstruction']) # et on sait comment la resonctruire le cas echeant
  268. && !$lock
  269. )
  270. if (@file_exists($valeurs['fichier_dest'])){
  271. // dans tous les cas mettre a jour la taille de l'image finale
  272. list ($valeurs["hauteur_dest"],$valeurs["largeur_dest"]) = taille_image($valeurs['fichier_dest']);
  273. $valeurs['date'] = @filemtime($valeurs['fichier_dest']); // pour la retrouver apres disparition
  274. ecrire_fichier($valeurs['fichier_dest'].'.src',serialize($valeurs),true);
  275. }
  276. return $ret;
  277. }
  278. // http://doc.spip.org/@reconstruire_image_intermediaire
  279. function reconstruire_image_intermediaire($fichier_manquant){
  280. $reconstruire = array();
  281. $fichier = $fichier_manquant;
  282. while (
  283. !@file_exists($fichier)
  284. AND lire_fichier($src = "$fichier.src",$source)
  285. AND $valeurs=unserialize($source)
  286. AND ($fichier = $valeurs['fichier']) # l'origine est connue (on ne verifie pas son existence, qu'importe ...)
  287. ) {
  288. spip_unlink($src); // si jamais on a un timeout pendant la reconstruction, elle se fera naturellement au hit suivant
  289. $reconstruire[] = $valeurs['reconstruction'];
  290. }
  291. while (count($reconstruire)){
  292. $r = array_pop($reconstruire);
  293. $fonction = $r[0];
  294. $args = $r[1];
  295. call_user_func_array($fonction, $args);
  296. }
  297. // cette image intermediaire est commune a plusieurs series de filtre, il faut la conserver
  298. // mais l'on peut nettoyer les miettes de sa creation
  299. ramasse_miettes($fichier_manquant);
  300. }
  301. // http://doc.spip.org/@ramasse_miettes
  302. function ramasse_miettes($fichier){
  303. if (!lire_fichier($src = "$fichier.src",$source)
  304. OR !$valeurs=unserialize($source)) return;
  305. spip_unlink($src); # on supprime la reference a sa source pour marquer cette image comme non intermediaire
  306. while (
  307. ($fichier = $valeurs['fichier']) # l'origine est connue (on ne verifie pas son existence, qu'importe ...)
  308. AND (substr($fichier,0,strlen(_DIR_VAR))==_DIR_VAR) # et est dans local
  309. AND (lire_fichier($src = "$fichier.src",$source)) # le fichier a une source connue (c'est donc une image calculee intermediaire)
  310. AND ($valeurs=unserialize($source)) # et valide
  311. ) {
  312. # on efface le fichier
  313. spip_unlink($fichier);
  314. # mais laisse le .src qui permet de savoir comment reconstruire l'image si besoin
  315. #spip_unlink($src);
  316. }
  317. }
  318. // http://doc.spip.org/@image_graver
  319. function image_graver($img){
  320. // appeler le filtre post_image_filtrer qui permet de faire
  321. // des traitements auto a la fin d'une serie de filtres
  322. $img = pipeline('post_image_filtrer',$img);
  323. $fichier = extraire_attribut($img, 'src');
  324. if (($p=strpos($fichier,'?'))!==FALSE)
  325. $fichier=substr($fichier,0,$p);
  326. if (strlen($fichier) < 1)
  327. $fichier = $img;
  328. # si jamais le fichier final n'a pas ete calcule car suppose temporaire
  329. if (!@file_exists($fichier))
  330. reconstruire_image_intermediaire($fichier);
  331. ramasse_miettes($fichier);
  332. return $img; // on ne change rien
  333. }
  334. // Transforme une image a palette indexee (256 couleurs max) en "vraies" couleurs RGB
  335. // http://doc.spip.org/@imagepalettetotruecolor
  336. function imagepalettetotruecolor(&$img) {
  337. if ($img AND !imageistruecolor($img) AND function_exists('imagecreatetruecolor')) {
  338. $w = imagesx($img);
  339. $h = imagesy($img);
  340. $img1 = imagecreatetruecolor($w,$h);
  341. //Conserver la transparence si possible
  342. if(function_exists('ImageCopyResampled')) {
  343. if (function_exists("imageAntiAlias")) imageAntiAlias($img1,true);
  344. @imagealphablending($img1, false);
  345. @imagesavealpha($img1,true);
  346. @ImageCopyResampled($img1, $img, 0, 0, 0, 0, $w, $h, $w, $h);
  347. } else {
  348. imagecopy($img1,$img,0,0,0,0,$w,$h);
  349. }
  350. $img = $img1;
  351. }
  352. }
  353. // http://doc.spip.org/@image_tag_changer_taille
  354. function _image_tag_changer_taille($tag,$width,$height,$style=false){
  355. if ($style===false) $style = extraire_attribut($tag,'style');
  356. // enlever le width et height du style
  357. $style = preg_replace(",(^|;)\s*(width|height)\s*:\s*[^;]+,ims","",$style);
  358. if ($style AND $style{0}==';') $style=substr($style,1);
  359. // mettre des attributs de width et height sur les images,
  360. // ca accelere le rendu du navigateur
  361. // ca permet aux navigateurs de reserver la bonne taille
  362. // quand on a desactive l'affichage des images.
  363. $tag = inserer_attribut($tag,'width',$width);
  364. $tag = inserer_attribut($tag,'height',$height);
  365. $style = "height:".$height."px;width:".$width."px;".$style;
  366. // attributs deprecies. Transformer en CSS
  367. if ($espace = extraire_attribut($tag, 'hspace')){
  368. $style = "margin:${espace}px;".$style;
  369. $tag = inserer_attribut($tag,'hspace','');
  370. }
  371. $tag = inserer_attribut($tag,'style',$style);
  372. return $tag;
  373. }
  374. // function d'ecriture du de la balise img en sortie des filtre image
  375. // reprend le tag initial et surcharge les tags modifies
  376. function _image_ecrire_tag($valeurs,$surcharge=array()){
  377. $tag = str_replace(">","/>",str_replace("/>",">",$valeurs['tag'])); // fermer les tags img pas bien fermes;
  378. // le style
  379. $style = $valeurs['style'];
  380. if (isset($surcharge['style'])){
  381. $style = $surcharge['style'];
  382. unset($surcharge['style']);
  383. }
  384. // traiter specifiquement la largeur et la hauteur
  385. $width = $valeurs['largeur'];
  386. if (isset($surcharge['width'])){
  387. $width = $surcharge['width'];
  388. unset($surcharge['width']);
  389. }
  390. $height = $valeurs['hauteur'];
  391. if (isset($surcharge['height'])){
  392. $height = $surcharge['height'];
  393. unset($surcharge['height']);
  394. }
  395. $tag = _image_tag_changer_taille($tag,$width,$height,$style);
  396. // traiter specifiquement le src qui peut etre repris dans un onmouseout
  397. // on remplace toute les ref a src dans le tag
  398. $src = extraire_attribut($tag,'src');
  399. if (isset($surcharge['src'])){
  400. $tag = str_replace($src,$surcharge['src'],$tag);
  401. // si il y a des & dans src, alors ils peuvent provenir d'un &amp
  402. // pas garanti comme methode, mais mieux que rien
  403. if (strpos($src,'&') !== false)
  404. $tag = str_replace(str_replace("&","&amp;",$src),$surcharge['src'],$tag);
  405. $src = $surcharge['src'];
  406. unset($surcharge['src']);
  407. }
  408. $class = $valeurs['class'];
  409. if (isset($surcharge['class'])){
  410. $class = $surcharge['class'];
  411. unset($surcharge['class']);
  412. }
  413. if(strlen($class))
  414. $tag = inserer_attribut($tag,'class',$class);
  415. if (count($surcharge))
  416. foreach($surcharge as $attribut=>$valeur)
  417. $tag = inserer_attribut($tag,$attribut,$valeur);
  418. return $tag;
  419. }
  420. function _image_creer_vignette($valeurs, $maxWidth, $maxHeight, $process='AUTO', $force=false, $test_cache_only = false) {
  421. // ordre de preference des formats graphiques pour creer les vignettes
  422. // le premier format disponible, selon la methode demandee, est utilise
  423. $image = $valeurs['fichier'];
  424. $format = $valeurs['format_source'];
  425. $destdir = dirname($valeurs['fichier_dest']);
  426. $destfile = basename($valeurs['fichier_dest'],".".$valeurs["format_dest"]);
  427. $format_sortie = $valeurs['format_dest'];
  428. // liste des formats qu'on sait lire
  429. $img = isset($GLOBALS['meta']['formats_graphiques'])
  430. ? (strpos($GLOBALS['meta']['formats_graphiques'], $format)!==false)
  431. : false;
  432. // si le doc n'est pas une image, refuser
  433. if (!$force AND !$img) return;
  434. $destination = "$destdir/$destfile";
  435. // chercher un cache
  436. $vignette = '';
  437. if ($test_cache_only AND !$vignette) return;
  438. // utiliser le cache ?
  439. if (!$test_cache_only)
  440. if ($force OR !$vignette OR (@filemtime($vignette) < @filemtime($image))) {
  441. $creation = true;
  442. // calculer la taille
  443. if (($srcWidth=$valeurs['largeur']) && ($srcHeight=$valeurs['hauteur'])){
  444. if (!($destWidth=$valeurs['largeur_dest']) || !($destHeight=$valeurs['hauteur_dest']))
  445. list ($destWidth,$destHeight) = _image_ratio($valeurs['largeur'], $valeurs['hauteur'], $maxWidth, $maxHeight);
  446. }
  447. elseif ($process == 'convert' OR $process == 'imagick') {
  448. $destWidth = $maxWidth;
  449. $destHeight = $maxHeight;
  450. } else {
  451. spip_log("echec $process sur $image");
  452. return;
  453. }
  454. // Si l'image est de la taille demandee (ou plus petite), simplement
  455. // la retourner
  456. if ($srcWidth
  457. AND $srcWidth <= $maxWidth AND $srcHeight <= $maxHeight) {
  458. $vignette = $destination.'.'.$format;
  459. @copy($image, $vignette);
  460. }
  461. // imagemagick en ligne de commande
  462. else if ($process == 'convert') {
  463. define('_CONVERT_COMMAND', 'convert');
  464. define ('_RESIZE_COMMAND', _CONVERT_COMMAND.' -quality 85 -resize %xx%y! %src %dest');
  465. $vignette = $destination.".".$format_sortie;
  466. $commande = str_replace(
  467. array('%x', '%y', '%src', '%dest'),
  468. array(
  469. $destWidth,
  470. $destHeight,
  471. escapeshellcmd($image),
  472. escapeshellcmd($vignette)
  473. ),
  474. _RESIZE_COMMAND);
  475. spip_log($commande);
  476. exec($commande);
  477. if (!@file_exists($vignette)) {
  478. spip_log("echec convert sur $vignette");
  479. return; // echec commande
  480. }
  481. }
  482. else
  483. // imagick (php4-imagemagick)
  484. if ($process == 'imagick') {
  485. $vignette = "$destination.".$format_sortie;
  486. $handle = imagick_readimage($image);
  487. imagick_resize($handle, $destWidth, $destHeight, IMAGICK_FILTER_LANCZOS, 0.75);
  488. imagick_write($handle, $vignette);
  489. if (!@file_exists($vignette)) {
  490. spip_log("echec imagick sur $vignette");
  491. return;
  492. }
  493. }
  494. else
  495. // netpbm
  496. if ($process == "netpbm") {
  497. define('_PNMSCALE_COMMAND', 'pnmscale'); // chemin a changer dans mes_options
  498. if (_PNMSCALE_COMMAND == '') return;
  499. $vignette = $destination.".".$format_sortie;
  500. $pnmtojpeg_command = str_replace("pnmscale", "pnmtojpeg", _PNMSCALE_COMMAND);
  501. if ($format == "jpg") {
  502. $jpegtopnm_command = str_replace("pnmscale", "jpegtopnm", _PNMSCALE_COMMAND);
  503. exec("$jpegtopnm_command $image | "._PNMSCALE_COMMAND." -width $destWidth | $pnmtojpeg_command > $vignette");
  504. if (!($s = @filesize($vignette)))
  505. spip_unlink($vignette);
  506. if (!@file_exists($vignette)) {
  507. spip_log("echec netpbm-jpg sur $vignette");
  508. return;
  509. }
  510. } else if ($format == "gif") {
  511. $giftopnm_command = str_replace("pnmscale", "giftopnm", _PNMSCALE_COMMAND);
  512. exec("$giftopnm_command $image | "._PNMSCALE_COMMAND." -width $destWidth | $pnmtojpeg_command > $vignette");
  513. if (!($s = @filesize($vignette)))
  514. spip_unlink($vignette);
  515. if (!@file_exists($vignette)) {
  516. spip_log("echec netpbm-gif sur $vignette");
  517. return;
  518. }
  519. } else if ($format == "png") {
  520. $pngtopnm_command = str_replace("pnmscale", "pngtopnm", _PNMSCALE_COMMAND);
  521. exec("$pngtopnm_command $image | "._PNMSCALE_COMMAND." -width $destWidth | $pnmtojpeg_command > $vignette");
  522. if (!($s = @filesize($vignette)))
  523. spip_unlink($vignette);
  524. if (!@file_exists($vignette)) {
  525. spip_log("echec netpbm-png sur $vignette");
  526. return;
  527. }
  528. }
  529. }
  530. // gd ou gd2
  531. else if ($process == 'gd1' OR $process == 'gd2') {
  532. if (_IMG_GD_MAX_PIXELS && $srcWidth*$srcHeight>_IMG_GD_MAX_PIXELS){
  533. spip_log("vignette gd1/gd2 impossible : ".$srcWidth*$srcHeight."pixels");
  534. return;
  535. }
  536. $destFormat = $format_sortie;
  537. if (!$destFormat) {
  538. spip_log("pas de format pour $image");
  539. return;
  540. }
  541. $fonction_imagecreatefrom = $valeurs['fonction_imagecreatefrom'];
  542. if (!function_exists($fonction_imagecreatefrom))
  543. return '';
  544. $srcImage = @$fonction_imagecreatefrom($image);
  545. if (!$srcImage) {
  546. spip_log("echec gd1/gd2");
  547. return;
  548. }
  549. // Initialisation de l'image destination
  550. if ($process == 'gd2' AND $destFormat != "gif")
  551. $destImage = ImageCreateTrueColor($destWidth, $destHeight);
  552. if (!$destImage)
  553. $destImage = ImageCreate($destWidth, $destHeight);
  554. // Recopie de l'image d'origine avec adaptation de la taille
  555. $ok = false;
  556. if (($process == 'gd2') AND function_exists('ImageCopyResampled')) {
  557. if ($format == "gif") {
  558. // Si un GIF est transparent,
  559. // fabriquer un PNG transparent
  560. $transp = imagecolortransparent($srcImage);
  561. if ($transp > 0) $destFormat = "png";
  562. }
  563. if ($destFormat == "png") {
  564. // Conserver la transparence
  565. if (function_exists("imageAntiAlias")) imageAntiAlias($destImage,true);
  566. @imagealphablending($destImage, false);
  567. @imagesavealpha($destImage,true);
  568. }
  569. $ok = @ImageCopyResampled($destImage, $srcImage, 0, 0, 0, 0, $destWidth, $destHeight, $srcWidth, $srcHeight);
  570. }
  571. if (!$ok)
  572. $ok = ImageCopyResized($destImage, $srcImage, 0, 0, 0, 0, $destWidth, $destHeight, $srcWidth, $srcHeight);
  573. // Sauvegarde de l'image destination
  574. $valeurs['fichier_dest'] = $vignette = "$destination.$destFormat";
  575. $valeurs['format_dest'] = $format = $destFormat;
  576. _image_gd_output($destImage,$valeurs);
  577. if ($srcImage)
  578. ImageDestroy($srcImage);
  579. ImageDestroy($destImage);
  580. }
  581. }
  582. $size = @getimagesize($vignette);
  583. // Gaffe: en safe mode, pas d'acces a la vignette,
  584. // donc risque de balancer "width='0'", ce qui masque l'image sous MSIE
  585. if ($size[0] < 1) $size[0] = $destWidth;
  586. if ($size[1] < 1) $size[1] = $destHeight;
  587. $retour['width'] = $largeur = $size[0];
  588. $retour['height'] = $hauteur = $size[1];
  589. $retour['fichier'] = $vignette;
  590. $retour['format'] = $format;
  591. $retour['date'] = @filemtime($vignette);
  592. // renvoyer l'image
  593. return $retour;
  594. }
  595. // Calculer le ratio
  596. // http://doc.spip.org/@image_ratio
  597. function _image_ratio ($srcWidth, $srcHeight, $maxWidth, $maxHeight) {
  598. $ratioWidth = $srcWidth/$maxWidth;
  599. $ratioHeight = $srcHeight/$maxHeight;
  600. if ($ratioWidth <=1 AND $ratioHeight <=1) {
  601. $destWidth = $srcWidth;
  602. $destHeight = $srcHeight;
  603. } else if ($ratioWidth < $ratioHeight) {
  604. $destWidth = $srcWidth/$ratioHeight;
  605. $destHeight = $maxHeight;
  606. }
  607. else {
  608. $destWidth = $maxWidth;
  609. $destHeight = $srcHeight/$ratioWidth;
  610. }
  611. return array (ceil($destWidth), ceil($destHeight),
  612. max($ratioWidth,$ratioHeight));
  613. }
  614. // Calculer le ratio ajuste sur la plus petite dimension
  615. // http://doc.spip.org/@ratio_passe_partout
  616. function ratio_passe_partout ($srcWidth, $srcHeight, $maxWidth, $maxHeight) {
  617. $ratioWidth = $srcWidth/$maxWidth;
  618. $ratioHeight = $srcHeight/$maxHeight;
  619. if ($ratioWidth <=1 AND $ratioHeight <=1) {
  620. $destWidth = $srcWidth;
  621. $destHeight = $srcHeight;
  622. } else if ($ratioWidth > $ratioHeight) {
  623. $destWidth = $srcWidth/$ratioHeight;
  624. $destHeight = $maxHeight;
  625. }
  626. else {
  627. $destWidth = $maxWidth;
  628. $destHeight = $srcHeight/$ratioWidth;
  629. }
  630. return array (ceil($destWidth), ceil($destHeight),
  631. min($ratioWidth,$ratioHeight));
  632. }
  633. // http://doc.spip.org/@process_image_reduire
  634. function process_image_reduire($fonction,$img,$taille,$taille_y,$force,$cherche_image,$process){
  635. $image = false;
  636. if (($process == 'AUTO') AND isset($GLOBALS['meta']['image_process']))
  637. $process = $GLOBALS['meta']['image_process'];
  638. # determiner le format de sortie
  639. $format_sortie = false; // le choix par defaut sera bon
  640. if ($process == "netpbm") $format_sortie = "jpg";
  641. else if ($process == 'gd1' OR $process == 'gd2') {
  642. $image = _image_valeurs_trans($img, "reduire-{$taille}-{$taille_y}",$format_sortie,$fonction);
  643. // on verifie que l'extension choisie est bonne (en principe oui)
  644. $gd_formats = explode(',',$GLOBALS['meta']["gd_formats"]);
  645. if (!in_array($image['format_dest'],$gd_formats)
  646. OR ($image['format_dest']=='gif' AND !function_exists('ImageGif'))
  647. ) {
  648. if ($image['format_source'] == 'jpg')
  649. $formats_sortie = array('jpg','png','gif');
  650. else // les gif sont passes en png preferentiellement pour etre homogene aux autres filtres images
  651. $formats_sortie = array('png','jpg','gif');
  652. // Choisir le format destination
  653. // - on sauve de preference en JPEG (meilleure compression)
  654. // - pour le GIF : les GD recentes peuvent le lire mais pas l'ecrire
  655. # bug : gd_formats contient la liste des fichiers qu'on sait *lire*,
  656. # pas *ecrire*
  657. $format_sortie = "";
  658. foreach ($formats_sortie as $fmt) {
  659. if (in_array($fmt, $gd_formats)) {
  660. if ($fmt <> "gif" OR function_exists('ImageGif'))
  661. $format_sortie = $fmt;
  662. break;
  663. }
  664. }
  665. $image = false;
  666. }
  667. }
  668. if (!$image)
  669. $image = _image_valeurs_trans($img, "reduire-{$taille}-{$taille_y}",$format_sortie,$fonction);
  670. if (!$image OR !$image['largeur'] OR !$image['hauteur']){
  671. spip_log("image_reduire_src:pas de version locale de $img");
  672. // on peut resizer en mode html si on dispose des elements
  673. if ($srcw = extraire_attribut($img, 'width')
  674. AND $srch = extraire_attribut($img, 'height')) {
  675. list($w,$h) = _image_ratio($srcw, $srch, $taille, $taille_y);
  676. return _image_tag_changer_taille($img,$w,$h);
  677. }
  678. // la on n'a pas d'infos sur l'image source... on refile le truc a css
  679. // sous la forme style='max-width: NNpx;'
  680. return inserer_attribut($img, 'style',
  681. "max-width: ${taille}px; max-height: ${taille_y}px");
  682. }
  683. // si l'image est plus petite que la cible retourner une copie cachee de l'image
  684. if (($image['largeur']<=$taille)&&($image['hauteur']<=$taille_y)){
  685. if ($image['creer']){
  686. @copy($image['fichier'], $image['fichier_dest']);
  687. }
  688. return _image_ecrire_tag($image,array('src'=>$image['fichier_dest']));
  689. }
  690. if ($image['creer']==false && !$force)
  691. return _image_ecrire_tag($image,array('src'=>$image['fichier_dest'],'width'=>$image['largeur_dest'],'height'=>$image['hauteur_dest']));
  692. if ($cherche_image){
  693. $cherche = cherche_image_nommee(substr($image['fichier'],0,-4), array($image["format_source"]));
  694. if (!$cherche) return $img;
  695. //list($chemin,$nom,$format) = $cherche;
  696. }
  697. if (in_array($image["format_source"],array('jpg','gif','png'))){
  698. $destWidth = $image['largeur_dest'];
  699. $destHeight = $image['hauteur_dest'];
  700. $logo = $image['fichier'];
  701. $date = $image["date_src"];
  702. $preview = _image_creer_vignette($image, $taille, $taille_y,$process,$force);
  703. if ($preview && $preview['fichier']) {
  704. $logo = $preview['fichier'];
  705. $destWidth = $preview['width'];
  706. $destHeight = $preview['height'];
  707. $date = $preview['date'];
  708. }
  709. // dans l'espace prive mettre un timestamp sur l'adresse
  710. // de l'image, de facon a tromper le cache du navigateur
  711. // quand on fait supprimer/reuploader un logo
  712. // (pas de filemtime si SAFE MODE)
  713. $date = test_espace_prive() ? ('?date='.$date) : '';
  714. return _image_ecrire_tag($image,array('src'=>"$logo$date",'width'=>$destWidth,'height'=>$destHeight));
  715. }
  716. else
  717. # SVG par exemple ? BMP, tiff ... les redacteurs osent tout!
  718. return $img;
  719. }
  720. //
  721. // Produire des fichiers au format .ico
  722. // avec du code recupere de :
  723. //
  724. //////////////////////////////////////////////////////////////
  725. /// phpThumb() by James Heinrich <info@silisoftware.com> //
  726. // available at http://phpthumb.sourceforge.net ///
  727. //////////////////////////////////////////////////////////////
  728. class phpthumb_functions {
  729. // http://doc.spip.org/@GetPixelColor
  730. function GetPixelColor(&$img, $x, $y) {
  731. if (!is_resource($img)) {
  732. return false;
  733. }
  734. return @ImageColorsForIndex($img, @ImageColorAt($img, $x, $y));
  735. }
  736. // http://doc.spip.org/@LittleEndian2String
  737. function LittleEndian2String($number, $minbytes=1) {
  738. $intstring = '';
  739. while ($number > 0) {
  740. $intstring = $intstring.chr($number & 255);
  741. $number >>= 8;
  742. }
  743. return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT);
  744. }
  745. // http://doc.spip.org/@GD2ICOstring
  746. function GD2ICOstring(&$gd_image_array) {
  747. foreach ($gd_image_array as $key => $gd_image) {
  748. $ImageWidths[$key] = ImageSX($gd_image);
  749. $ImageHeights[$key] = ImageSY($gd_image);
  750. $bpp[$key] = ImageIsTrueColor($gd_image) ? 32 : 24;
  751. $totalcolors[$key] = ImageColorsTotal($gd_image);
  752. $icXOR[$key] = '';
  753. for ($y = $ImageHeights[$key] - 1; $y >= 0; $y--) {
  754. for ($x = 0; $x < $ImageWidths[$key]; $x++) {
  755. $argb = phpthumb_functions::GetPixelColor($gd_image, $x, $y);
  756. $a = round(255 * ((127 - $argb['alpha']) / 127));
  757. $r = $argb['red'];
  758. $g = $argb['green'];
  759. $b = $argb['blue'];
  760. if ($bpp[$key] == 32) {
  761. $icXOR[$key] .= chr($b).chr($g).chr($r).chr($a);
  762. } elseif ($bpp[$key] == 24) {
  763. $icXOR[$key] .= chr($b).chr($g).chr($r);
  764. }
  765. if ($a < 128) {
  766. @$icANDmask[$key][$y] .= '1';
  767. } else {
  768. @$icANDmask[$key][$y] .= '0';
  769. }
  770. }
  771. // mask bits are 32-bit aligned per scanline
  772. while (strlen($icANDmask[$key][$y]) % 32) {
  773. $icANDmask[$key][$y] .= '0';
  774. }
  775. }
  776. $icAND[$key] = '';
  777. foreach ($icANDmask[$key] as $y => $scanlinemaskbits) {
  778. for ($i = 0; $i < strlen($scanlinemaskbits); $i += 8) {
  779. $icAND[$key] .= chr(bindec(str_pad(substr($scanlinemaskbits, $i, 8), 8, '0', STR_PAD_LEFT)));
  780. }
  781. }
  782. }
  783. foreach ($gd_image_array as $key => $gd_image) {
  784. $biSizeImage = $ImageWidths[$key] * $ImageHeights[$key] * ($bpp[$key] / 8);
  785. // BITMAPINFOHEADER - 40 bytes
  786. $BitmapInfoHeader[$key] = '';
  787. $BitmapInfoHeader[$key] .= "\x28\x00\x00\x00"; // DWORD biSize;
  788. $BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($ImageWidths[$key], 4); // LONG biWidth;
  789. // The biHeight member specifies the combined
  790. // height of the XOR and AND masks.
  791. $BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($ImageHeights[$key] * 2, 4); // LONG biHeight;
  792. $BitmapInfoHeader[$key] .= "\x01\x00"; // WORD biPlanes;
  793. $BitmapInfoHeader[$key] .= chr($bpp[$key])."\x00"; // wBitCount;
  794. $BitmapInfoHeader[$key] .= "\x00\x00\x00\x00"; // DWORD biCompression;
  795. $BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($biSizeImage, 4); // DWORD biSizeImage;
  796. $BitmapInfoHeader[$key] .= "\x00\x00\x00\x00"; // LONG biXPelsPerMeter;
  797. $BitmapInfoHeader[$key] .= "\x00\x00\x00\x00"; // LONG biYPelsPerMeter;
  798. $BitmapInfoHeader[$key] .= "\x00\x00\x00\x00"; // DWORD biClrUsed;
  799. $BitmapInfoHeader[$key] .= "\x00\x00\x00\x00"; // DWORD biClrImportant;
  800. }
  801. $icondata = "\x00\x00"; // idReserved; // Reserved (must be 0)
  802. $icondata .= "\x01\x00"; // idType; // Resource Type (1 for icons)
  803. $icondata .= phpthumb_functions::LittleEndian2String(count($gd_image_array), 2); // idCount; // How many images?
  804. $dwImageOffset = 6 + (count($gd_image_array) * 16);
  805. foreach ($gd_image_array as $key => $gd_image) {
  806. // ICONDIRENTRY idEntries[1]; // An entry for each image (idCount of 'em)
  807. $icondata .= chr($ImageWidths[$key]); // bWidth; // Width, in pixels, of the image
  808. $icondata .= chr($ImageHeights[$key]); // bHeight; // Height, in pixels, of the image
  809. $icondata .= chr($totalcolors[$key]); // bColorCount; // Number of colors in image (0 if >=8bpp)
  810. $icondata .= "\x00"; // bReserved; // Reserved ( must be 0)
  811. $icondata .= "\x01\x00"; // wPlanes; // Color Planes
  812. $icondata .= chr($bpp[$key])."\x00"; // wBitCount; // Bits per pixel
  813. $dwBytesInRes = 40 + strlen($icXOR[$key]) + strlen($icAND[$key]);
  814. $icondata .= phpthumb_functions::LittleEndian2String($dwBytesInRes, 4); // dwBytesInRes; // How many bytes in this resource?
  815. $icondata .= phpthumb_functions::LittleEndian2String($dwImageOffset, 4); // dwImageOffset; // Where in the file is this image?
  816. $dwImageOffset += strlen($BitmapInfoHeader[$key]);
  817. $dwImageOffset += strlen($icXOR[$key]);
  818. $dwImageOffset += strlen($icAND[$key]);
  819. }
  820. foreach ($gd_image_array as $key => $gd_image) {
  821. $icondata .= $BitmapInfoHeader[$key];
  822. $icondata .= $icXOR[$key];
  823. $icondata .= $icAND[$key];
  824. }
  825. return $icondata;
  826. }
  827. }
  828. ?>