X-Git-Url: http://git.heureux-cyclage.org/?a=blobdiff_plain;f=www%2Fecrire%2Finc%2Ffiltres_images_lib_mini.php;fp=www%2Fecrire%2Finc%2Ffiltres_images_lib_mini.php;h=03620a1cc15b2677f9711c8ac3670baaa1417073;hb=a33c2ba9d919664b3bb0f565f8e9a8b9d8530cdb;hp=0000000000000000000000000000000000000000;hpb=8945248b3d948385798d9aa355c70e7089aca2b3;p=lhc%2Fweb%2Fclavette_www.git diff --git a/www/ecrire/inc/filtres_images_lib_mini.php b/www/ecrire/inc/filtres_images_lib_mini.php new file mode 100644 index 0000000..03620a1 --- /dev/null +++ b/www/ecrire/inc/filtres_images_lib_mini.php @@ -0,0 +1,1150 @@ +. + * @param string $effet + * Les nom et paramètres de l'effet à apporter sur l'image + * (par exemple : reduire-300-200). + * @param bool|string $forcer_format + * Un nom d'extension spécifique demandé (par exemple : jpg, png, txt... + * par défaut false : GD se débrouille seule). + * @param array $fonction_creation + * Un tableau à 2 éléments. Le premier (string) indique le nom du + * filtre de traitement demandé (par exemple : image_reduire) ; le + * second (array) est lui-même un tableau reprenant la valeur de $img + * et chacun des paramètres passés au filtre. + * @param bool $find_in_path + * false (par défaut) indique que l'on travaille sur un fichier + * temporaire (.src) ; true, sur un fichier définitif déjà existant. + * @return bool|string|array + * false si pas de tag =$date_src) + $creer = false; + } + else if (@file_exists($f = "$fichier_dest.src") + AND lire_fichier($f,$valeurs) + AND $valeurs=unserialize($valeurs) + AND $valeurs["date"]>=$date_src) + $creer = false; + } + if ($creer) { + if (!@file_exists($fichier)) { + if (!@file_exists("$fichier.src")) { + spip_log("Image absente : $fichier"); + return false; + } + # on reconstruit l'image source absente a partir de la chaine des .src + reconstruire_image_intermediaire($fichier); + } + } + + if ($creer) + spip_log("filtre image ".($fonction_creation?reset($fonction_creation):'')."[$effet] sur $fichier","images"._LOG_DEBUG); + + // TODO: si une image png est nommee .jpg, le reconnaitre avec le bon $f + $ret["fonction_imagecreatefrom"] = "_imagecreatefrom".$term_fonction; + $ret["fichier"] = $fichier; + $ret["fonction_image"] = "_image_image".$terminaison_dest; + $ret["fichier_dest"] = $fichier_dest; + $ret["format_source"] = ($terminaison != 'jpeg' ? $terminaison : 'jpg'); + $ret["format_dest"] = $terminaison_dest; + $ret["date_src"] = $date_src; + $ret["creer"] = $creer; + $ret["class"] = extraire_attribut($img, 'class'); + $ret["alt"] = extraire_attribut($img, 'alt'); + $ret["style"] = extraire_attribut($img, 'style'); + $ret["tag"] = $img; + if ($fonction_creation){ + $ret["reconstruction"] = $fonction_creation; + # ecrire ici comment creer le fichier, car il est pas sur qu'on l'ecrira reelement + # cas de image_reduire qui finalement ne reduit pas l'image source + # ca evite d'essayer de le creer au prochain hit si il n'est pas la + #ecrire_fichier($ret['fichier_dest'].'.src',serialize($ret),true); + } + + $ret = pipeline('image_preparer_filtre',array( + 'args'=>array( + 'img'=>$img, + 'effet'=>$effet, + 'forcer_format'=>$forcer_format, + 'fonction_creation'=>$fonction_creation, + 'find_in_path'=>$find_in_path, + ), + 'data'=>$ret) + ); + + // une globale pour le debug en cas de crash memoire + $GLOBALS["derniere_image_calculee"] = $ret; + + if (!function_exists($ret["fonction_imagecreatefrom"])) return false; + return $ret; +} + +/** + * Crée une image depuis un fichier ou une URL + * Utilise les fonctions spécifiques GD. + * + * @param string $filename + * Le path vers l'image à traiter (par exemple : IMG/distant/jpg/image.jpg + * ou local/cache-vignettes/L180xH51/image.jpg). + * @return ressource + * Une ressource de type Image GD. + */ +function _imagecreatefromjpeg($filename){ + $img = @imagecreatefromjpeg($filename); + if (!$img) { + spip_log("Erreur lecture imagecreatefromjpeg $filename",_LOG_CRITIQUE); + erreur_squelette("Erreur lecture imagecreatefromjpeg $filename"); + $img = imagecreate(10,10); + } + return $img; +} + +/** + * Crée une image depuis un fichier ou une URL + * Utilise les fonctions spécifiques GD. + * + * @param string $filename + * Le path vers l'image à traiter (par exemple : IMG/distant/png/image.png + * ou local/cache-vignettes/L180xH51/image.png). + * @return ressource + * Une ressource de type Image GD. + */ +function _imagecreatefrompng($filename){ + $img = @imagecreatefrompng($filename); + if (!$img) { + spip_log("Erreur lecture imagecreatefrompng $filename",_LOG_CRITIQUE); + erreur_squelette("Erreur lecture imagecreatefrompng $filename"); + $img = imagecreate(10,10); + } + return $img; +} + +/** + * Crée une image depuis un fichier ou une URL + * Utilise les fonctions spécifiques GD. + * + * @param string $filename + * Le path vers l'image à traiter (par exemple : IMG/distant/gif/image.gif + * ou local/cache-vignettes/L180xH51/image.gif). + * @return ressource + * Une ressource de type Image GD. + */ +function _imagecreatefromgif($filename){ + $img = @imagecreatefromgif($filename); + if (!$img) { + spip_log("Erreur lecture imagecreatefromgif $filename",_LOG_CRITIQUE); + erreur_squelette("Erreur lecture imagecreatefromgif $filename"); + $img = imagecreate(10,10); + } + return $img; +} + +/** + * Affiche ou sauvegarde une image au format PNG + * Utilise les fonctions spécifiques GD. + * + * @param ressource $img + * Une ressource de type Image GD. + * @param string $fichier + * Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.png). + * @return bool + * false si l'image créée a une largeur nulle ou n'existe pas ; + * true si une image est bien retournée. + */ +function _image_imagepng($img, $fichier) { + if (!function_exists('imagepng')) return false; + $tmp = $fichier.".tmp"; + $ret = imagepng($img,$tmp); + + if(file_exists($tmp)){ + $taille_test = getimagesize($tmp); + if ($taille_test[0] < 1) return false; + + spip_unlink($fichier); // le fichier peut deja exister + @rename($tmp, $fichier); + return $ret; + } + return false; +} + +/** + * Affiche ou sauvegarde une image au format GIF + * Utilise les fonctions spécifiques GD. + * + * @param ressource $img + * Une ressource de type Image GD. + * @param string $fichier + * Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.gif). + * @return bool + * false si l'image créée a une largeur nulle ou n'existe pas; + * true si une image est bien retournée. + */ +function _image_imagegif($img,$fichier) { + if (!function_exists('imagegif')) return false; + $tmp = $fichier.".tmp"; + $ret = imagegif($img,$tmp); + + if(file_exists($tmp)){ + $taille_test = getimagesize($tmp); + if ($taille_test[0] < 1) return false; + + spip_unlink($fichier); // le fichier peut deja exister + @rename($tmp, $fichier); + return $ret; + } + return false; +} + +/** + * Affiche ou sauvegarde une image au format JPG + * Utilise les fonctions spécifiques GD. + * + * @param ressource $img + * Une ressource de type Image GD. + * @param string $fichier + * Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.jpg). + * @param int $qualite + * Le niveau de qualité du fichier résultant : de 0 (pire qualité, petit + * fichier) à 100 (meilleure qualité, gros fichier). Par défaut, prend la + * valeur (85) de la constante _IMG_GD_QUALITE (modifiable depuis + * mes_options.php). + * @return bool + * false si l'image créée a une largeur nulle ou n'existe pas ; + * true si une image est bien retournée. + */ +function _image_imagejpg($img,$fichier,$qualite=_IMG_GD_QUALITE) { + if (!function_exists('imagejpeg')) return false; + $tmp = $fichier.".tmp"; + $ret = imagejpeg($img,$tmp, $qualite); + + if(file_exists($tmp)){ + $taille_test = getimagesize($tmp); + if ($taille_test[0] < 1) return false; + + spip_unlink($fichier); // le fichier peut deja exister + @rename($tmp, $fichier); + return $ret; + } + return false; +} + +/** + * Crée un fichier-image au format ICO + * Utilise les fonctions de la classe phpthumb_functions. + * + * @param ressource $img + * Une ressource de type Image GD. + * @param string $fichier + * Le path vers l'image (ex : local/cache-vignettes/L180xH51/image.jpg). + * @return bool + * true si le fichier a bien été créé ; false sinon. + */ +function _image_imageico($img, $fichier) { + $gd_image_array = array($img); + + return ecrire_fichier($fichier, phpthumb_functions::GD2ICOstring($gd_image_array)); +} + +/** + * Finalise le traitement GD + * Crée un fichier_image temporaire .src ou vérifie que le fichier_image + * définitif a bien été créé. + * + * @param ressource $img + * Une ressource de type Image GD. + * @param array $valeurs + * Un tableau des informations (tailles, traitement, path...) accompagnant + * l'image. + * @param int $qualite + * N'est utilisé que pour les images jpg. + * Le niveau de qualité du fichier résultant : de 0 (pire qualité, petit + * fichier) à 100 (meilleure qualité, gros fichier). Par défaut, prend la + * valeur (85) de la constante _IMG_GD_QUALITE (modifiable depuis + * mes_options.php). + * @return bool + * true si le traitement GD s'est bien finalisé ; + * false sinon. + */ +function _image_gd_output($img,$valeurs, $qualite=_IMG_GD_QUALITE){ + $fonction = "_image_image".$valeurs['format_dest']; + $ret = false; + #un flag pour reperer les images gravees + $lock = + !statut_effacer_images_temporaires('get') // si la fonction n'a pas ete activee, on grave tout + OR (@file_exists($valeurs['fichier_dest']) AND !@file_exists($valeurs['fichier_dest'].'.src')); + if ( + function_exists($fonction) + && ($ret = $fonction($img,$valeurs['fichier_dest'],$qualite)) # on a reussi a creer l'image + && isset($valeurs['reconstruction']) # et on sait comment la resonctruire le cas echeant + && !$lock + ) + if (@file_exists($valeurs['fichier_dest'])){ + // dans tous les cas mettre a jour la taille de l'image finale + list ($valeurs["hauteur_dest"],$valeurs["largeur_dest"]) = taille_image($valeurs['fichier_dest']); + $valeurs['date'] = @filemtime($valeurs['fichier_dest']); // pour la retrouver apres disparition + ecrire_fichier($valeurs['fichier_dest'].'.src',serialize($valeurs),true); + } + return $ret; +} + +// http://doc.spip.org/@reconstruire_image_intermediaire +function reconstruire_image_intermediaire($fichier_manquant){ + $reconstruire = array(); + $fichier = $fichier_manquant; + while ( + !@file_exists($fichier) + AND lire_fichier($src = "$fichier.src",$source) + AND $valeurs=unserialize($source) + AND ($fichier = $valeurs['fichier']) # l'origine est connue (on ne verifie pas son existence, qu'importe ...) + ) { + spip_unlink($src); // si jamais on a un timeout pendant la reconstruction, elle se fera naturellement au hit suivant + $reconstruire[] = $valeurs['reconstruction']; + } + while (count($reconstruire)){ + $r = array_pop($reconstruire); + $fonction = $r[0]; + $args = $r[1]; + call_user_func_array($fonction, $args); + } + // cette image intermediaire est commune a plusieurs series de filtre, il faut la conserver + // mais l'on peut nettoyer les miettes de sa creation + ramasse_miettes($fichier_manquant); +} + +// http://doc.spip.org/@ramasse_miettes +function ramasse_miettes($fichier){ + if (!lire_fichier($src = "$fichier.src",$source) + OR !$valeurs=unserialize($source)) return; + spip_unlink($src); # on supprime la reference a sa source pour marquer cette image comme non intermediaire + while ( + ($fichier = $valeurs['fichier']) # l'origine est connue (on ne verifie pas son existence, qu'importe ...) + AND (substr($fichier,0,strlen(_DIR_VAR))==_DIR_VAR) # et est dans local + AND (lire_fichier($src = "$fichier.src",$source)) # le fichier a une source connue (c'est donc une image calculee intermediaire) + AND ($valeurs=unserialize($source)) # et valide + ) { + # on efface le fichier + spip_unlink($fichier); + # mais laisse le .src qui permet de savoir comment reconstruire l'image si besoin + #spip_unlink($src); + } +} + +// http://doc.spip.org/@image_graver +function image_graver($img){ + // appeler le filtre post_image_filtrer qui permet de faire + // des traitements auto a la fin d'une serie de filtres + $img = pipeline('post_image_filtrer',$img); + + $fichier = extraire_attribut($img, 'src'); + if (($p=strpos($fichier,'?'))!==FALSE) + $fichier=substr($fichier,0,$p); + if (strlen($fichier) < 1) + $fichier = $img; + # si jamais le fichier final n'a pas ete calcule car suppose temporaire + if (!@file_exists($fichier)) + reconstruire_image_intermediaire($fichier); + ramasse_miettes($fichier); + return $img; // on ne change rien +} + +// Transforme une image a palette indexee (256 couleurs max) en "vraies" couleurs RGB +// Existe seulement pour compatibilite avec PHP < 5.5 +// http://doc.spip.org/@imagepalettetotruecolor +if (!function_exists("imagepalettetotruecolor")) { +function imagepalettetotruecolor(&$img) { + if ($img AND !imageistruecolor($img) AND function_exists('imagecreatetruecolor')) { + $w = imagesx($img); + $h = imagesy($img); + $img1 = imagecreatetruecolor($w,$h); + //Conserver la transparence si possible + if(function_exists('ImageCopyResampled')) { + if (function_exists("imageAntiAlias")) imageAntiAlias($img1,true); + @imagealphablending($img1, false); + @imagesavealpha($img1,true); + @ImageCopyResampled($img1, $img, 0, 0, 0, 0, $w, $h, $w, $h); + } else { + imagecopy($img1,$img,0,0,0,0,$w,$h); + } + + $img = $img1; + } +} +} + +// http://doc.spip.org/@image_tag_changer_taille +function _image_tag_changer_taille($tag,$width,$height,$style=false){ + if ($style===false) $style = extraire_attribut($tag,'style'); + // enlever le width et height du style + $style = preg_replace(",(^|;)\s*(width|height)\s*:\s*[^;]+,ims","",$style); + if ($style AND $style{0}==';') $style=substr($style,1); + // mettre des attributs de width et height sur les images, + // ca accelere le rendu du navigateur + // ca permet aux navigateurs de reserver la bonne taille + // quand on a desactive l'affichage des images. + $tag = inserer_attribut($tag,'width',$width); + $tag = inserer_attribut($tag,'height',$height); + + // Ancien style inline pour IE6 mais qui casse la possibilité de surcharger en CSS + //$style = "height:".$height."px;width:".$width."px;".$style; + + // attributs deprecies. Transformer en CSS + if ($espace = extraire_attribut($tag, 'hspace')){ + $style = "margin:${espace}px;".$style; + $tag = inserer_attribut($tag,'hspace',''); + } + $tag = inserer_attribut($tag,'style',$style, true, $style ? false : true); + return $tag; +} + +// function d'ecriture du de la balise img en sortie des filtre image +// reprend le tag initial et surcharge les tags modifies +function _image_ecrire_tag($valeurs,$surcharge=array()){ + $valeurs = pipeline('image_ecrire_tag_preparer',$valeurs); + + $tag = str_replace(">","/>",str_replace("/>",">",$valeurs['tag'])); // fermer les tags img pas bien fermes; + + // le style + $style = $valeurs['style']; + if (isset($surcharge['style'])){ + $style = $surcharge['style']; + unset($surcharge['style']); + } + + // traiter specifiquement la largeur et la hauteur + $width = $valeurs['largeur']; + if (isset($surcharge['width'])){ + $width = $surcharge['width']; + unset($surcharge['width']); + } + $height = $valeurs['hauteur']; + if (isset($surcharge['height'])){ + $height = $surcharge['height']; + unset($surcharge['height']); + } + + $tag = _image_tag_changer_taille($tag,$width,$height,$style); + // traiter specifiquement le src qui peut etre repris dans un onmouseout + // on remplace toute les ref a src dans le tag + $src = extraire_attribut($tag,'src'); + if (isset($surcharge['src'])){ + $tag = str_replace($src,$surcharge['src'],$tag); + // si il y a des & dans src, alors ils peuvent provenir d'un & + // pas garanti comme methode, mais mieux que rien + if (strpos($src,'&') !== false) + $tag = str_replace(str_replace("&","&",$src),$surcharge['src'],$tag); + $src = $surcharge['src']; + unset($surcharge['src']); + } + + $class = $valeurs['class']; + if (isset($surcharge['class'])){ + $class = $surcharge['class']; + unset($surcharge['class']); + } + if(strlen($class)) + $tag = inserer_attribut($tag,'class',$class); + + if (count($surcharge)) + foreach($surcharge as $attribut=>$valeur) + $tag = inserer_attribut($tag,$attribut,$valeur); + + $tag = pipeline('image_ecrire_tag_finir', + array( + 'args' => array( + 'valeurs' => $valeurs, + 'surcharge' => $surcharge, + ), + 'data' => $tag + ) + ); + + return $tag; +} + +function _image_creer_vignette($valeurs, $maxWidth, $maxHeight, $process='AUTO', $force=false, $test_cache_only = false) { + // ordre de preference des formats graphiques pour creer les vignettes + // le premier format disponible, selon la methode demandee, est utilise + $image = $valeurs['fichier']; + $format = $valeurs['format_source']; + $destdir = dirname($valeurs['fichier_dest']); + $destfile = basename($valeurs['fichier_dest'],".".$valeurs["format_dest"]); + + $format_sortie = $valeurs['format_dest']; + + // liste des formats qu'on sait lire + $img = isset($GLOBALS['meta']['formats_graphiques']) + ? (strpos($GLOBALS['meta']['formats_graphiques'], $format)!==false) + : false; + + // si le doc n'est pas une image, refuser + if (!$force AND !$img) return; + $destination = "$destdir/$destfile"; + + // chercher un cache + $vignette = ''; + if ($test_cache_only AND !$vignette) return; + + // utiliser le cache ? + if (!$test_cache_only) + if ($force OR !$vignette OR (@filemtime($vignette) < @filemtime($image))) { + + $creation = true; + // calculer la taille + if (($srcWidth=$valeurs['largeur']) && ($srcHeight=$valeurs['hauteur'])){ + if (!($destWidth=$valeurs['largeur_dest']) || !($destHeight=$valeurs['hauteur_dest'])) + list ($destWidth,$destHeight) = _image_ratio($valeurs['largeur'], $valeurs['hauteur'], $maxWidth, $maxHeight); + } + elseif ($process == 'convert' OR $process == 'imagick') { + $destWidth = $maxWidth; + $destHeight = $maxHeight; + } else { + spip_log("echec $process sur $image"); + return; + } + + // Si l'image est de la taille demandee (ou plus petite), simplement + // la retourner + if ($srcWidth + AND $srcWidth <= $maxWidth AND $srcHeight <= $maxHeight) { + $vignette = $destination.'.'.$format; + @copy($image, $vignette); + } + // imagemagick en ligne de commande + else if ($process == 'convert') { + define('_CONVERT_COMMAND', 'convert'); + define ('_RESIZE_COMMAND', _CONVERT_COMMAND.' -quality '._IMG_CONVERT_QUALITE.' -resize %xx%y! %src %dest'); + $vignette = $destination.".".$format_sortie; + $commande = str_replace( + array('%x', '%y', '%src', '%dest'), + array( + $destWidth, + $destHeight, + escapeshellcmd($image), + escapeshellcmd($vignette) + ), + _RESIZE_COMMAND); + spip_log($commande); + exec($commande); + if (!@file_exists($vignette)) { + spip_log("echec convert sur $vignette"); + return; // echec commande + } + } + else + // imagick (php4-imagemagick) + if ($process == 'imagick') { + + $vignette = "$destination.".$format_sortie; + + $imagick = new Imagick(); + $imagick->readImage($image); + $imagick->resizeImage($destWidth, $destHeight, Imagick::FILTER_LANCZOS, 1 );//, IMAGICK_FILTER_LANCZOS, _IMG_IMAGICK_QUALITE / 100); + $imagick->writeImage($vignette); + + if (!@file_exists($vignette)) { + spip_log("echec imagick sur $vignette"); + return; + } + } + else + // netpbm + if ($process == "netpbm") { + define('_PNMSCALE_COMMAND', 'pnmscale'); // chemin a changer dans mes_options + if (_PNMSCALE_COMMAND == '') return; + $vignette = $destination.".".$format_sortie; + $pnmtojpeg_command = str_replace("pnmscale", "pnmtojpeg", _PNMSCALE_COMMAND); + if ($format == "jpg") { + + $jpegtopnm_command = str_replace("pnmscale", "jpegtopnm", _PNMSCALE_COMMAND); + exec("$jpegtopnm_command $image | "._PNMSCALE_COMMAND." -width $destWidth | $pnmtojpeg_command > $vignette"); + if (!($s = @filesize($vignette))) + spip_unlink($vignette); + if (!@file_exists($vignette)) { + spip_log("echec netpbm-jpg sur $vignette"); + return; + } + } else if ($format == "gif") { + $giftopnm_command = str_replace("pnmscale", "giftopnm", _PNMSCALE_COMMAND); + exec("$giftopnm_command $image | "._PNMSCALE_COMMAND." -width $destWidth | $pnmtojpeg_command > $vignette"); + if (!($s = @filesize($vignette))) + spip_unlink($vignette); + if (!@file_exists($vignette)) { + spip_log("echec netpbm-gif sur $vignette"); + return; + } + } else if ($format == "png") { + $pngtopnm_command = str_replace("pnmscale", "pngtopnm", _PNMSCALE_COMMAND); + exec("$pngtopnm_command $image | "._PNMSCALE_COMMAND." -width $destWidth | $pnmtojpeg_command > $vignette"); + if (!($s = @filesize($vignette))) + spip_unlink($vignette); + if (!@file_exists($vignette)) { + spip_log("echec netpbm-png sur $vignette"); + return; + } + } + } + // gd ou gd2 + else if ($process == 'gd1' OR $process == 'gd2') { + if (_IMG_GD_MAX_PIXELS && $srcWidth*$srcHeight>_IMG_GD_MAX_PIXELS){ + spip_log("vignette gd1/gd2 impossible : ".$srcWidth*$srcHeight."pixels"); + return; + } + $destFormat = $format_sortie; + if (!$destFormat) { + spip_log("pas de format pour $image"); + return; + } + + $fonction_imagecreatefrom = $valeurs['fonction_imagecreatefrom']; + if (!function_exists($fonction_imagecreatefrom)) + return ''; + $srcImage = @$fonction_imagecreatefrom($image); + if (!$srcImage) { + spip_log("echec gd1/gd2"); + return; + } + + // Initialisation de l'image destination + if ($process == 'gd2' AND $destFormat != "gif") + $destImage = ImageCreateTrueColor($destWidth, $destHeight); + if (!$destImage) + $destImage = ImageCreate($destWidth, $destHeight); + + // Recopie de l'image d'origine avec adaptation de la taille + $ok = false; + if (($process == 'gd2') AND function_exists('ImageCopyResampled')) { + if ($format == "gif") { + // Si un GIF est transparent, + // fabriquer un PNG transparent + $transp = imagecolortransparent($srcImage); + if ($transp > 0) $destFormat = "png"; + } + if ($destFormat == "png") { + // Conserver la transparence + if (function_exists("imageAntiAlias")) imageAntiAlias($destImage,true); + @imagealphablending($destImage, false); + @imagesavealpha($destImage,true); + } + $ok = @ImageCopyResampled($destImage, $srcImage, 0, 0, 0, 0, $destWidth, $destHeight, $srcWidth, $srcHeight); + } + if (!$ok) + $ok = ImageCopyResized($destImage, $srcImage, 0, 0, 0, 0, $destWidth, $destHeight, $srcWidth, $srcHeight); + + // Sauvegarde de l'image destination + $valeurs['fichier_dest'] = $vignette = "$destination.$destFormat"; + $valeurs['format_dest'] = $format = $destFormat; + _image_gd_output($destImage,$valeurs); + + if ($srcImage) + ImageDestroy($srcImage); + ImageDestroy($destImage); + } + } + $size = @getimagesize($vignette); + // Gaffe: en safe mode, pas d'acces a la vignette, + // donc risque de balancer "width='0'", ce qui masque l'image sous MSIE + if ($size[0] < 1) $size[0] = $destWidth; + if ($size[1] < 1) $size[1] = $destHeight; + + $retour['width'] = $largeur = $size[0]; + $retour['height'] = $hauteur = $size[1]; + + $retour['fichier'] = $vignette; + $retour['format'] = $format; + $retour['date'] = @filemtime($vignette); + + // renvoyer l'image + return $retour; +} + +// Calculer le ratio +// http://doc.spip.org/@image_ratio +function _image_ratio ($srcWidth, $srcHeight, $maxWidth, $maxHeight) { + $ratioWidth = $srcWidth/$maxWidth; + $ratioHeight = $srcHeight/$maxHeight; + + if ($ratioWidth <=1 AND $ratioHeight <=1) { + $destWidth = $srcWidth; + $destHeight = $srcHeight; + } else if ($ratioWidth < $ratioHeight) { + $destWidth = $srcWidth/$ratioHeight; + $destHeight = $maxHeight; + } + else { + $destWidth = $maxWidth; + $destHeight = $srcHeight/$ratioWidth; + } + return array (ceil($destWidth), ceil($destHeight), + max($ratioWidth,$ratioHeight)); +} + +// Calculer le ratio ajuste sur la plus petite dimension +// http://doc.spip.org/@ratio_passe_partout +function ratio_passe_partout ($srcWidth, $srcHeight, $maxWidth, $maxHeight) { + $ratioWidth = $srcWidth/$maxWidth; + $ratioHeight = $srcHeight/$maxHeight; + + if ($ratioWidth <=1 AND $ratioHeight <=1) { + $destWidth = $srcWidth; + $destHeight = $srcHeight; + } else if ($ratioWidth > $ratioHeight) { + $destWidth = $srcWidth/$ratioHeight; + $destHeight = $maxHeight; + } + else { + $destWidth = $maxWidth; + $destHeight = $srcHeight/$ratioWidth; + } + return array (ceil($destWidth), ceil($destHeight), + min($ratioWidth,$ratioHeight)); +} + +// http://doc.spip.org/@process_image_reduire +function process_image_reduire($fonction,$img,$taille,$taille_y,$force,$cherche_image,$process){ + $image = false; + if (($process == 'AUTO') AND isset($GLOBALS['meta']['image_process'])) + $process = $GLOBALS['meta']['image_process']; + # determiner le format de sortie + $format_sortie = false; // le choix par defaut sera bon + if ($process == "netpbm") $format_sortie = "jpg"; + else if ($process == 'gd1' OR $process == 'gd2') { + $image = _image_valeurs_trans($img, "reduire-{$taille}-{$taille_y}",$format_sortie,$fonction); + + // on verifie que l'extension choisie est bonne (en principe oui) + $gd_formats = explode(',',$GLOBALS['meta']["gd_formats"]); + if (!in_array($image['format_dest'],$gd_formats) + OR ($image['format_dest']=='gif' AND !function_exists('ImageGif')) + ) { + if ($image['format_source'] == 'jpg') + $formats_sortie = array('jpg','png','gif'); + else // les gif sont passes en png preferentiellement pour etre homogene aux autres filtres images + $formats_sortie = array('png','jpg','gif'); + // Choisir le format destination + // - on sauve de preference en JPEG (meilleure compression) + // - pour le GIF : les GD recentes peuvent le lire mais pas l'ecrire + # bug : gd_formats contient la liste des fichiers qu'on sait *lire*, + # pas *ecrire* + $format_sortie = ""; + foreach ($formats_sortie as $fmt) { + if (in_array($fmt, $gd_formats)) { + if ($fmt <> "gif" OR function_exists('ImageGif')) + $format_sortie = $fmt; + break; + } + } + $image = false; + } + } + + if (!$image) + $image = _image_valeurs_trans($img, "reduire-{$taille}-{$taille_y}",$format_sortie,$fonction); + + if (!$image OR !$image['largeur'] OR !$image['hauteur']){ + spip_log("image_reduire_src:pas de version locale de $img"); + // on peut resizer en mode html si on dispose des elements + if ($srcw = extraire_attribut($img, 'width') + AND $srch = extraire_attribut($img, 'height')) { + list($w,$h) = _image_ratio($srcw, $srch, $taille, $taille_y); + return _image_tag_changer_taille($img,$w,$h); + } + // la on n'a pas d'infos sur l'image source... on refile le truc a css + // sous la forme style='max-width: NNpx;' + return inserer_attribut($img, 'style', + "max-width: ${taille}px; max-height: ${taille_y}px"); + } + + // si l'image est plus petite que la cible retourner une copie cachee de l'image + if (($image['largeur']<=$taille)&&($image['hauteur']<=$taille_y)){ + if ($image['creer']){ + @copy($image['fichier'], $image['fichier_dest']); + } + return _image_ecrire_tag($image,array('src'=>$image['fichier_dest'])); + } + + if ($image['creer']==false && !$force) + return _image_ecrire_tag($image,array('src'=>$image['fichier_dest'],'width'=>$image['largeur_dest'],'height'=>$image['hauteur_dest'])); + + if (in_array($image["format_source"],array('jpg','gif','png'))){ + $destWidth = $image['largeur_dest']; + $destHeight = $image['hauteur_dest']; + $logo = $image['fichier']; + $date = $image["date_src"]; + $preview = _image_creer_vignette($image, $taille, $taille_y,$process,$force); + + if ($preview && $preview['fichier']) { + $logo = $preview['fichier']; + $destWidth = $preview['width']; + $destHeight = $preview['height']; + $date = $preview['date']; + } + // dans l'espace prive mettre un timestamp sur l'adresse + // de l'image, de facon a tromper le cache du navigateur + // quand on fait supprimer/reuploader un logo + // (pas de filemtime si SAFE MODE) + $date = test_espace_prive() ? ('?'.$date) : ''; + return _image_ecrire_tag($image,array('src'=>"$logo$date",'width'=>$destWidth,'height'=>$destHeight)); + } + else + # SVG par exemple ? BMP, tiff ... les redacteurs osent tout! + return $img; +} + +/** + * Produire des fichiers au format .ico + * avec du code recupere de : + * phpThumb() by James Heinrich + * available at http://phpthumb.sourceforge.net + * + * Class phpthumb_functions + */ +class phpthumb_functions { + + /** + * @param ressource $img + * @param int $x + * @param int $y + * @return array|bool + */ + public static function GetPixelColor(&$img, $x, $y) { + if (!is_resource($img)) { + return false; + } + return @ImageColorsForIndex($img, @ImageColorAt($img, $x, $y)); + } + + /** + * @param int $number + * @param int $minbytes + * @return string + */ + public static function LittleEndian2String($number, $minbytes=1) { + $intstring = ''; + while ($number > 0) { + $intstring = $intstring.chr($number & 255); + $number >>= 8; + } + return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT); + } + + /** + * @param array $gd_image_array + * @return string + */ + public static function GD2ICOstring(&$gd_image_array) { + foreach ($gd_image_array as $key => $gd_image) { + + $ImageWidths[$key] = ImageSX($gd_image); + $ImageHeights[$key] = ImageSY($gd_image); + $bpp[$key] = ImageIsTrueColor($gd_image) ? 32 : 24; + $totalcolors[$key] = ImageColorsTotal($gd_image); + + $icXOR[$key] = ''; + for ($y = $ImageHeights[$key] - 1; $y >= 0; $y--) { + for ($x = 0; $x < $ImageWidths[$key]; $x++) { + $argb = phpthumb_functions::GetPixelColor($gd_image, $x, $y); + $a = round(255 * ((127 - $argb['alpha']) / 127)); + $r = $argb['red']; + $g = $argb['green']; + $b = $argb['blue']; + + if ($bpp[$key] == 32) { + $icXOR[$key] .= chr($b).chr($g).chr($r).chr($a); + } elseif ($bpp[$key] == 24) { + $icXOR[$key] .= chr($b).chr($g).chr($r); + } + + if ($a < 128) { + @$icANDmask[$key][$y] .= '1'; + } else { + @$icANDmask[$key][$y] .= '0'; + } + } + // mask bits are 32-bit aligned per scanline + while (strlen($icANDmask[$key][$y]) % 32) { + $icANDmask[$key][$y] .= '0'; + } + } + $icAND[$key] = ''; + foreach ($icANDmask[$key] as $y => $scanlinemaskbits) { + for ($i = 0; $i < strlen($scanlinemaskbits); $i += 8) { + $icAND[$key] .= chr(bindec(str_pad(substr($scanlinemaskbits, $i, 8), 8, '0', STR_PAD_LEFT))); + } + } + + } + + foreach ($gd_image_array as $key => $gd_image) { + $biSizeImage = $ImageWidths[$key] * $ImageHeights[$key] * ($bpp[$key] / 8); + + // BITMAPINFOHEADER - 40 bytes + $BitmapInfoHeader[$key] = ''; + $BitmapInfoHeader[$key] .= "\x28\x00\x00\x00"; // DWORD biSize; + $BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($ImageWidths[$key], 4); // LONG biWidth; + // The biHeight member specifies the combined + // height of the XOR and AND masks. + $BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($ImageHeights[$key] * 2, 4); // LONG biHeight; + $BitmapInfoHeader[$key] .= "\x01\x00"; // WORD biPlanes; + $BitmapInfoHeader[$key] .= chr($bpp[$key])."\x00"; // wBitCount; + $BitmapInfoHeader[$key] .= "\x00\x00\x00\x00"; // DWORD biCompression; + $BitmapInfoHeader[$key] .= phpthumb_functions::LittleEndian2String($biSizeImage, 4); // DWORD biSizeImage; + $BitmapInfoHeader[$key] .= "\x00\x00\x00\x00"; // LONG biXPelsPerMeter; + $BitmapInfoHeader[$key] .= "\x00\x00\x00\x00"; // LONG biYPelsPerMeter; + $BitmapInfoHeader[$key] .= "\x00\x00\x00\x00"; // DWORD biClrUsed; + $BitmapInfoHeader[$key] .= "\x00\x00\x00\x00"; // DWORD biClrImportant; + } + + + $icondata = "\x00\x00"; // idReserved; // Reserved (must be 0) + $icondata .= "\x01\x00"; // idType; // Resource Type (1 for icons) + $icondata .= phpthumb_functions::LittleEndian2String(count($gd_image_array), 2); // idCount; // How many images? + + $dwImageOffset = 6 + (count($gd_image_array) * 16); + foreach ($gd_image_array as $key => $gd_image) { + // ICONDIRENTRY idEntries[1]; // An entry for each image (idCount of 'em) + + $icondata .= chr($ImageWidths[$key]); // bWidth; // Width, in pixels, of the image + $icondata .= chr($ImageHeights[$key]); // bHeight; // Height, in pixels, of the image + $icondata .= chr($totalcolors[$key]); // bColorCount; // Number of colors in image (0 if >=8bpp) + $icondata .= "\x00"; // bReserved; // Reserved ( must be 0) + + $icondata .= "\x01\x00"; // wPlanes; // Color Planes + $icondata .= chr($bpp[$key])."\x00"; // wBitCount; // Bits per pixel + + $dwBytesInRes = 40 + strlen($icXOR[$key]) + strlen($icAND[$key]); + $icondata .= phpthumb_functions::LittleEndian2String($dwBytesInRes, 4); // dwBytesInRes; // How many bytes in this resource? + + $icondata .= phpthumb_functions::LittleEndian2String($dwImageOffset, 4); // dwImageOffset; // Where in the file is this image? + $dwImageOffset += strlen($BitmapInfoHeader[$key]); + $dwImageOffset += strlen($icXOR[$key]); + $dwImageOffset += strlen($icAND[$key]); + } + + foreach ($gd_image_array as $key => $gd_image) { + $icondata .= $BitmapInfoHeader[$key]; + $icondata .= $icXOR[$key]; + $icondata .= $icAND[$key]; + } + + return $icondata; + } + +} + +?>