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