* @author Jean-Pascal MILCENT * @author Aurelien PERONNET * @license GPL v3 * @license CECILL v2 * @copyright 1999-2014 Tela Botanica */ Class ImageRecreation { private $droits = 0755; private $formats = array('CRX2S','CRXS','CXS','CS','CRS','XS','S','M','L','XL','X2L','X3L'); const MODE_GD = 'gd'; const MODE_IMAGEMAGICK = 'imagemagick'; private $mode; private $verbose = true; public function __construct($config) { $this->config = $config; if (extension_loaded('imagick')) { $this->mode = self::MODE_IMAGEMAGICK; } else { $this->mode = self::MODE_GD; } } public function recreerMiniaturesRecursivement() { $this->itererRecursivement($this->config['cel']['chemin_images']); } public function regenererMiniaturesIntervalle($params) { $id_debut = $params[0]; $id_fin = $params[1]; if (is_numeric($id_debut) && is_numeric($id_fin)) { for ($i = $id_debut; $i <= $id_fin; $i++) {; $tab_param = array($i); $this->regenererMiniaturesPourId($tab_param); } } } /** * params[0] doit contenir un seul identifiant d'image; les miniatures * seront regénérée pour cette image */ public function regenererMiniaturesPourId($params) { $id = $params[0]; if (!is_numeric($id)) { return; } $dossier_fichier = $this->obtenirDossierPourFormat($id, 'O'); $nom_fichier = $this->convertirIdBddVersNomFichier($id, 'O'); $chemin_fichier = $dossier_fichier.'/'.$nom_fichier; if (file_exists($chemin_fichier)) { $infos_image_originale = $this->obtenirImageEtInfosPourChemin($chemin_fichier); // creation de miniatures pour chacuns des formats définis foreach ($this->formats as $format) { $this->creerEtStockerMiniatureFichierImageSelonFormat($id, $infos_image_originale, $format); }; } } public function itererRecursivement($dossier) { // on ne parse que le dossier des images originales $dossiers_a_exclure = $this->getFormats(); foreach (new DirectoryIterator($dossier) as $fichier_ou_dossier) { if ($fichier_ou_dossier->isDot()) { continue; } if (in_array($fichier_ou_dossier->getBasename(), $dossiers_a_exclure)) { continue; } if ($fichier_ou_dossier->isDir()) { $this->itererRecursivement($fichier_ou_dossier->getPathname()); } else { $nom_fichier = $fichier_ou_dossier->getFilename(); $infos_image_originale = $this->obtenirImageEtInfosPourChemin($fichier_ou_dossier->getPathname()); $id = $this->convertirBaseNomFichierVersIdBdd($nom_fichier, $this->formats); // creation de miniatures pour chacuns des formats définis foreach ($this->formats as $format) { $this->creerEtStockerMiniatureFichierImageSelonFormat($id, $infos_image_originale, $format); } } } } public function creerOuRenvoyerImage($id, $format) { $dossier = $this->obtenirDossierPourFormat($id, $format); $nom_fichier = $this->convertirIdBddVersNomFichier($id, $format); $chemin_image = $dossier.'/'.$nom_fichier; $image = false; if (!file_exists($chemin_image)) { $chemin_image_originale = $this->obtenirCheminImageOriginale($id); $infos_image_originale = $this->obtenirImageEtInfosPourChemin($chemin_image_originale); if($infos_image_originale) { // le verrou est là dans le (rare) cas où l'image est déjà en train // d'être générée par le script de création des miniatures ou bien // un autre instance de cette classe appelée par le web service $fp = fopen($chemin_image_originale, "r"); // si le fichier est verrouillé, flock attendra qu'il se libère $verrou = flock($fp, LOCK_EX); if(!file_exists($chemin_image)) { // si le fichier a été locké alors l'image était en train d'être générée // et donc il n'est pas nécéssaire de la créer (d'où le 2eme test sur file exists) $this->creerEtStockerMiniatureFichierImageSelonFormat($id, $infos_image_originale, $format); } $verrou = flock($fp, LOCK_UN); fclose($fp); $image = file_get_contents($chemin_image); } elseif ('O' === $format) { $image = new Imagick($chemin_image); $profiles = $image->getImageProfiles('icc', true); $image->stripImage(); if (!empty($profile)) { $image->profileImage('icc', $profiles['icc']); } $image = $image->getImageBlob(); } else { $image = file_get_contents($chemin_image); } return $image; } public function creerMiniatureImageSelonFormat($infos_image_originale, $format = 'O') { $image_redimensionnee = false; if ($format == 'O') { // format original : rien à faire $image_redimensionnee = $infos_image_originale['image']; } else { if ($this->estUnFormatRogne($format)) { if ($this->mode == self::MODE_IMAGEMAGICK) { // si l'on dispose de la librairie imageMagick // on applique l'algorithme d'auto détection de sujets // qui centre la miniature sur le sujet de l'image $image_redimensionnee = $this->opticrop($infos_image_originale, $format); } if ($image_redimensionnee === false) { // si l'on ne dispose que de gd ou bien que Imagick a échoué // la minature est une image redimensionnée rognée au centre $image_redimensionnee = $this->creerMiniatureCarreeRognee($infos_image_originale, $format); } } else if ($this->estUnFormatCarre($format)) { // le format carre et une image redimensionnée en gardant son ratio, insérée dans un carré blanc $image_redimensionnee = $this->creerMiniatureCarree($infos_image_originale, $format); } else { $image_redimensionnee = $this->creerMiniature($infos_image_originale, $format); } } return $image_redimensionnee; } /** * Déplace une image temporaire uploadée vers le répertoire de stockage d'images, * en enregistrant les métadonnées et tout le tintouin. * Si $conserverFichiersTemporaires vaut true, l'image est copiée et non déplacée. * * @param unknown $fichier * @param unknown $id * @param unknown $conserverFichiersTemporaires * @return Ambigous |boolean */ public function stockerFichierOriginal($fichier, $id, $conserverFichiersTemporaires=false) { $chemin_fichier_origine = is_array($fichier) ? $fichier['tmp_name'] : $fichier; $tailleFichierOrigine = filesize($chemin_fichier_origine); $chemin_base_fichier = $this->creerSiNecessaireEtRenvoyerCheminStockageFichierPourIdEtFormat($id, 'O'); $nom_fichier = $this->convertirIdBddVersNomFichier($id, 'O'); $chemin_fichier = $chemin_base_fichier.'/'.$nom_fichier; $deplacement_fichier = $this->stockerImageExterne($chemin_fichier_origine, $chemin_fichier, $conserverFichiersTemporaires); if ($tailleFichierOrigine == 0) { $erreur = 'ERREUR : fichier image original [' . $chemin_fichier . '] de taille nulle (0) \n' ; $this->logger('CEL_bugs',$erreur); return false; } if ($deplacement_fichier) { $infos_image_originale = $this->obtenirImageEtInfosPourChemin($chemin_fichier); $taux_compression = $this->renvoyerTauxCompressionPourPoids($infos_image_originale['poids_octets']); $ecritureOK = true; if ($taux_compression < 100 && $this->mode == self::MODE_IMAGEMAGICK) { $ecritureOK = $this->ecrireImageSurDisqueAvecMeta($chemin_fichier, $taux_compression); } if ($ecritureOK) { return $infos_image_originale; } else { $erreur = 'ERREUR : probleme durant la recompression du fichier image original \n' ; $this->logger('CEL_bugs',$erreur); return false ; } } else { $erreur = 'ERREUR : probleme durant le déplacement du fichier temporaire \n' ; $this->logger('CEL_bugs',$erreur); return false ; } } public function stockerFichierEtCreerMiniatures($fichier, $id) { $infos_image_originale_stockee = $this->stockerFichierOriginal($fichier, $id); if ($infos_image_originale_stockee) { $formats = $this->getFormats(); // creation de miniatures pour chacuns des formats définis foreach($formats as $format) { $this->creerEtStockerMiniatureFichierImageSelonFormat($id, $infos_image_originale_stockee, $format); } } else { $erreur = 'ERROR : impossible d\'obtenir les informations sur l\'image originale \n' ; $this->logger('CEL_bugs',$erreur); return false ; } return true ; } public function creerEtStockerMiniatureFichierImageSelonFormat($id ,$infos_image_originale, $format = 'O') { $image_redimensionnee = $this->creerMiniatureImageSelonFormat($infos_image_originale, $format); $taux_compression = $this->renvoyerTauxCompressionPourPoids($infos_image_originale['poids_octets']); $this->ecrireImageSurDisque($image_redimensionnee, $id, $format, $taux_compression); return true; } public function creerImageRedimensionnee($infos_image_originale, $hauteur_redimension, $largeur_redimension) { $image_redimensionnee = imagecreatetruecolor($largeur_redimension, $hauteur_redimension); imagecopyresampled($image_redimensionnee, $infos_image_originale['image'], 0, 0, 0, 0, $largeur_redimension, $hauteur_redimension, $infos_image_originale['largeur'], $infos_image_originale['hauteur'] ); return $image_redimensionnee; } public function creerMiniature($informations_images, $format) { $taille_reference_pour_format = $this->obtenirDimensionsPourFormat($format); $taille_image_redimensionnee = $this->calculerTailleImage($informations_images, $taille_reference_pour_format['hauteur']); $image_redimensionnee = $this->creerImageRedimensionnee($informations_images, $taille_image_redimensionnee['hauteur'], $taille_image_redimensionnee['largeur']); return $image_redimensionnee; } public function creerMiniatureCarree($informations_image, $format) { $taille_reference_pour_format = $this->obtenirDimensionsPourFormat($format); $cote_carre = $taille_reference_pour_format['largeur']; $image_redimensionnee_avec_rapport = $this->creerMiniature($informations_image, $format); $taille_redimensionnee_avec_rapport = $this->calculerTailleImage($informations_image, $taille_reference_pour_format['hauteur']); if ($this->estPaysage($informations_image)) { $debut_largeur_a_copier = 0 ; $debut_hauteur_a_copier = ($cote_carre - $taille_redimensionnee_avec_rapport['hauteur'])/2 ; } else { $debut_largeur_a_copier = ($cote_carre - $taille_redimensionnee_avec_rapport['largeur'])/2 ; $debut_hauteur_a_copier = 0 ; } $image_carre_blanc_cible = $this->renvoyerEtCreerImageCarreeBlancheSelonFormat($cote_carre); imagecopy($image_carre_blanc_cible, $image_redimensionnee_avec_rapport, $debut_largeur_a_copier ,$debut_hauteur_a_copier, 0, 0, $taille_redimensionnee_avec_rapport['largeur'], $taille_redimensionnee_avec_rapport['hauteur'] ); return $image_carre_blanc_cible; } public function creerMiniatureCarreeRognee($informations_image, $format) { $taille_reference_pour_format = $this->obtenirDimensionsPourFormat($format); $cote_carre = $taille_reference_pour_format['largeur']; $cote_carre_non_redimensionne = 0; if ($this->estPaysage($informations_image)) { $cote_carre_non_redimensionne = $informations_image['hauteur']; $debut_largeur_a_copier = ($informations_image['largeur'] / 2) - ($informations_image['hauteur'] / 2); $debut_hauteur_a_copier = 0; if($debut_largeur_a_copier <= 0) { $debut_largeur_a_copier = 0; } $nb_pixels_largeur_a_copier = $cote_carre_non_redimensionne; $nb_pixels_hauteur_a_copier = $cote_carre_non_redimensionne; } else { $cote_carre_non_redimensionne = $informations_image['largeur']; $debut_largeur_a_copier = 0 ; $debut_hauteur_a_copier = ($informations_image['hauteur'] / 2) - ($informations_image['largeur'] / 2); if($debut_hauteur_a_copier <= 0) { $debut_hauteur_a_copier = 0; } $nb_pixels_largeur_a_copier = $cote_carre_non_redimensionne; $nb_pixels_hauteur_a_copier = $cote_carre_non_redimensionne; } $image_carre_temporaire = imagecreatetruecolor($cote_carre_non_redimensionne, $cote_carre_non_redimensionne); imagecopyresampled($image_carre_temporaire, $informations_image['image'], 0, 0, $debut_largeur_a_copier, $debut_hauteur_a_copier, $cote_carre_non_redimensionne, $cote_carre_non_redimensionne, $nb_pixels_largeur_a_copier, $nb_pixels_hauteur_a_copier ); $image_redimensionnee = imagecreatetruecolor($cote_carre, $cote_carre); imagecopyresampled($image_redimensionnee, $image_carre_temporaire, 0, 0, 0, 0, $cote_carre, $cote_carre, $cote_carre_non_redimensionne, $cote_carre_non_redimensionne ); return $image_redimensionnee; } /** * Déplace un fichier temporaire vers une destination donnée. Si * $conserverFichiersTemporaires vaut true, le fichier est copié et non déplacé. * * @param unknown $chemin_fichier_temp * @param unknown $chemin_destination * @param string $conserverFichiersTemporaires * @return boolean */ public function stockerImageExterne($chemin_fichier_temp, $chemin_destination, $conserverFichiersTemporaires=false) { if ($conserverFichiersTemporaires === true) { // copie du fichier $deplacement = copy($chemin_fichier_temp, $chemin_destination); } else { if (is_uploaded_file($chemin_fichier_temp)) { $deplacement = move_uploaded_file($chemin_fichier_temp, $chemin_destination); } else { $deplacement = rename($chemin_fichier_temp, $chemin_destination); } } return $deplacement; } public function creerSiNecessaireEtRenvoyerCheminStockageFichierPourIdEtFormat($id, $format) { $chemin_sur_serveur_final = $this->obtenirDossierPourFormat($id, $format); if (!file_exists($chemin_sur_serveur_final)) { umask(0); if (!mkdir($chemin_sur_serveur_final, $this->droits, true)) { $erreur = 'ERROR : probleme durant l\'écriture du dossier '.$format.' \n' ; $this->logger('CEL_bugs', $erreur); return false; } } return $chemin_sur_serveur_final; } public function obtenirDossierPourFormat($id, $format) { $chemin_base = $this->config['cel']['chemin_images']; $chemin_sur_serveur = $chemin_base; $id = sprintf('%09s', $id); $id = wordwrap($id, 3 , '_', true); list($dossierNiveau1, $dossierNiveau2) = explode('_', $id); $chemin_sur_serveur_final = $chemin_sur_serveur.'/'.$dossierNiveau1.'/'.$dossierNiveau2.'/'.$format; return $chemin_sur_serveur_final; } public function obtenirCheminImageOriginale($id_image) { $nom = $this->convertirIdBddVersNomFichier($id_image, 'O'); $dossier = $this->obtenirDossierPourFormat($id_image,'O'); return $dossier.'/'.$nom; } public function obtenirImageEtInfosPourId($id_image) { $chemin_image_o = $this->obtenirCheminImageOriginale($id_image); return $this->obtenirImageEtInfosPourChemin($chemin_image_o); } public function obtenirImageEtInfosPourChemin($chemin_fichier) { $image_et_infos = false; if (file_exists($chemin_fichier)) { $image_et_infos = array(); list($image_et_infos['largeur'], $image_et_infos['hauteur'], $image_et_infos['imagetype']) = getimagesize($chemin_fichier); $image_et_infos['poids_octets'] = filesize($chemin_fichier); $image_et_infos['chemin'] = $chemin_fichier; switch (image_type_to_mime_type($image_et_infos['imagetype'])) { case 'image/jpeg': $image_et_infos['image'] = imagecreatefromjpeg($chemin_fichier); break; case 'image/png': $image_et_infos['image'] = imagecreatefrompng($chemin_fichier); break; default: // ni jpeg ni png donc pas supporté, ça dégage return false; } } return $image_et_infos; } public function obtenirDimensionsPourFormat($format) { $dimensions = array('largeur' => 0, 'hauteur' => 0); if (isset($this->config['cel']['format_'.$format])) { list($dimensions['largeur'], $dimensions['hauteur']) = explode('_', $this->config['cel']['format_'.$format]); } return $dimensions; } public function calculerTailleImage($informations_images, $taille_max) { $HL_redimension = array(); if ($this->estPaysage($informations_images)) { $rapport = $informations_images['hauteur']/$informations_images['largeur'] ; $HL_redimension['largeur'] = round($taille_max) ; $HL_redimension['hauteur'] = round($taille_max*$rapport) ; } else { // protection contre division par 0 - prob. symptôme d'un autre pb : image vide ou mal transmise, // voir TODO dans obtenirImageEtInfosPourChemin() $rapport = $informations_images['hauteur'] == 0 ? 0 : $informations_images['largeur'] / $informations_images['hauteur']; $HL_redimension['hauteur'] = round($taille_max) ; $HL_redimension['largeur'] = round($taille_max*$rapport) ; } return $HL_redimension; } public function getFormats() { return $this->formats; } public function estUnFormatCarre($format) { return (strpos($format,'C') === 0); } public function estUnFormatRogne($format) { return (strpos($format,'R') === 1); } public function estPaysage($informations_images) { return $informations_images['largeur'] > $informations_images['hauteur']; } public function estPortait($informations_images) { return $informations_images['largeur'] < $informations_images['hauteur']; } public function renvoyerTauxCompressionPourPoids($poids_octets) { $poids_max_octets = $this->config['cel']['taille_max']; $ratio_compression = 100 ; if ($poids_octets >= $poids_max_octets) { $ratio_compression = 75 ; } return $ratio_compression; } public function convertirIdBddVersNomFichier($id, $format, $extension = 'jpg') { // creation du format original $id_avec_zeros = sprintf('%09s', $id); $id_avec_zeros_underscores = wordwrap($id_avec_zeros, 3 , '_', true); // déterminationnage de l'extension $path = $this->obtenirDossierPourFormat($id, $format); foreach(['jpg', 'JPG', 'jpeg', 'JPEG', 'png', 'PNG'] as $ext) { if (file_exists($path.'/'.$id_avec_zeros_underscores.'_'.$format.'.'.$ext)) { $extension = $ext; break; } } $nom_fichier = $id_avec_zeros_underscores.'_'.$format.'.'.$extension; return $nom_fichier; } public function convertirBaseNomFichierVersIdBdd($nom_fichier, $formats) { $nom_fichier_sans_extension = trim($nom_fichier, '.jpg'); foreach ($formats as $format) { $nom_fichier_sans_extension = trim($nom_fichier_sans_extension, '_'.$format); } $id_image = str_replace('_', '', $nom_fichier_sans_extension); // suppression des 0 devant $id_image += 0; return $id_image; } public function ecrireImageSurDisque($image_binaire, $id, $format, $compression = 100) { umask(0); $chemin_sur_serveur_final = $this->creerSiNecessaireEtRenvoyerCheminStockageFichierPourIdEtFormat($id, $format); $nom_fichier = $this->convertirIdBddVersNomFichier($id, $format); if (file_exists($chemin_sur_serveur_final.'/'.$nom_fichier)) { unlink($chemin_sur_serveur_final.'/'.$nom_fichier); } // attention, ceci ne preserve pas les metadonnées imagejpeg($image_binaire, $chemin_sur_serveur_final.'/'.$nom_fichier, $compression); chmod($chemin_sur_serveur_final.'/'.$nom_fichier,$this->droits); } public function ecrireImageSurDisqueAvecMeta($chemin_image_a_stocker, $compression = 100) { try { $img = new Imagick($chemin_image_a_stocker); // l'utilisation d'image magick préserve les métadonnées lors d'une recompression $img->setformat('jpeg'); $img->setImageCompression(imagick::COMPRESSION_JPEG); $img->setCompressionQuality($compression); $img->writeImage($chemin_image_a_stocker); $img->destroy(); chmod($chemin_image_a_stocker, $this->droits); return true; } catch (ImagickException $e) { return false; } } public function renvoyerEtCreerImageCarreeBlancheSelonFormat($cote) { $image_blanche = imagecreatetruecolor($cote, $cote); $blanc = imagecolorallocate($image_blanche, 255, 255, 255); imagefilledrectangle($image_blanche, 0, 0, $cote, $cote, $blanc); return $image_blanche; } public function detruireImageEnMemoire($image) { imagedestroy($image); } /** * Supprime une image du disque, ainsi que tous les formats générés * * @param Integer $id * @return boolean true si tous les formats y compris l'original ont été détruits, false s'il en reste au moins un */ public function detruireImageSurDisque($id) { $formats = $this->getFormats(); // on detruit aussi l'image originale $formats[] = 'O'; $destruction_formats_fichier = true; // destructions de chacun des formats définis foreach($formats as $format) { $dossier_format = $this->obtenirDossierPourFormat($id, $format); $nom_fichier = $this->convertirIdBddVersNomFichier($id, $format); if (file_exists($dossier_format.'/'.$nom_fichier)) { $detruit = unlink($dossier_format.'/'.$nom_fichier); $destruction_formats_fichier = ($destruction_formats_fichier && $detruit); } } return $destruction_formats_fichier; } // recopie de Cel->logger() (pas d'extends pour ça) public function logger($index,$chaine) { if (!class_exists('Log')) { Log::getInstance(); } Log::setCheminLog($this->config['log']['cheminlog']); Log::setTimeZone($this->config['log']['timezone']); Log::setTailleMax($this->config['log']['taillemax']); Log::ajouterEntree($index,$chaine); } /* * edge-maximizing crop * determines center-of-edginess, then tries different-sized crops around it. * picks the crop with the highest normalized edginess. * see documentation on how to tune the algorithm * * $informations_image - le tableau d'informations sur l'image tel que renvoyé par la fonction obtenirImageEtInfosPourChemin * $format - le format (ex. : CS, XS, XL, CRS) */ public function opticrop($informations_image, $format) { umask(0); $erreur_ecriture = false; $nom_temp = md5(time()); $chemin_temp = $out = $this->config['cel']['chemin_stockage_temp'].'/'.$nom_temp; $dimension_vignettes = $this->obtenirDimensionsPourFormat($format); $largeur_vignette = $dimension_vignettes['largeur']; $hauteur_vignette = $dimension_vignettes['hauteur']; // source dimensions $largeur_image_originale = $informations_image['largeur']; $hauteur_image_originale = $informations_image['hauteur']; $chemin_image = $informations_image['chemin']; // parameters for the edge-maximizing crop algorithm $r = 1; // radius of edge filter $nk = 9; // scale count: number of crop sizes to try $gamma = 0.2; // edge normalization parameter -- see documentation $ar = $largeur_vignette/$hauteur_vignette; // target aspect ratio (AR) $ar0 = $largeur_image_originale/$hauteur_image_originale; // original aspect ratio (AR) //echo("$chemin_image: $largeur_image_originale x $hauteur_image_originale => $largeur_vignette x $hauteur_vignette"); try { $img = new Imagick($chemin_image); // ce machin jette une ImagickException si le fichier est vide $imgcp = clone $img; // compute center of edginess $img->edgeImage($r); $img->modulateImage(100,0,100); // grayscale $img->blackThresholdImage("#0f0f0f"); $retour_ecriture_img = $img->writeImage($out); if ($retour_ecriture_img !== true) { error_log("Erreur d'écriture Imagick : [" . $chemin_image . "] vers [" . $out . "]"); $erreur_ecriture = true; } // use gd for random pixel access $im = ImageCreateFromJpeg($out); if ($im === false) { error_log("GD ne peut pas lire l'image créée par Imagick : [" . $chemin_image . "] vers [" . $out . "]"); $erreur_ecriture = true; } } catch (ImagickException $e) { // En principe si on se trouve ici c'est que l'image est vide $erreur_ecriture = true; $image_sortie = false; } if (! $erreur_ecriture) { $xcenter = 0; $ycenter = 0; $sum = 0; $n = 100000; for ($k=0; $k<$n; $k++) { $i = mt_rand(0,$largeur_image_originale-1); $j = mt_rand(0,$hauteur_image_originale-1); $val = imagecolorat($im, $i, $j) & 0xFF; $sum += $val; $xcenter += ($i+1)*$val; $ycenter += ($j+1)*$val; } $xcenter /= $sum; $ycenter /= $sum; // crop source img to target AR if ($largeur_image_originale/$hauteur_image_originale > $ar) { // source AR wider than target // crop width to target AR $wcrop0 = round($ar*$hauteur_image_originale); $hcrop0 = $hauteur_image_originale; } else { // source AR wider than target // crop height to target AR $wcrop0 = $largeur_image_originale; $hcrop0 = round($largeur_image_originale/$ar); } // crop parameters for all scales and translations $params = array(); // crop at different scales $hgap = $hcrop0 - $hauteur_vignette; $hinc = ($nk == 1) ? 0 : $hgap / ($nk - 1); $wgap = $wcrop0 - $largeur_vignette; $winc = ($nk == 1) ? 0 : $wgap / ($nk - 1); // find window with highest normalized edginess $n = 10000; $maxbetanorm = 0; $maxfile = ''; $maxparam = array('w'=>0, 'h'=>0, 'x'=>0, 'y'=>0); for ($k = 0; $k < $nk; $k++) { $hcrop = round($hcrop0 - $k*$hinc); $wcrop = round($wcrop0 - $k*$winc); $xcrop = $xcenter - $wcrop / 2; $ycrop = $ycenter - $hcrop / 2; //echo("crop: $wcrop, $hcrop, $xcrop, $ycrop"); if ($xcrop < 0) $xcrop = 0; if ($xcrop+$wcrop > $largeur_image_originale) $xcrop = $largeur_image_originale-$wcrop; if ($ycrop < 0) $ycrop = 0; if ($ycrop+$hcrop > $hauteur_image_originale) $ycrop = $hauteur_image_originale-$hcrop; $beta = 0; for ($c=0; $c<$n; $c++) { $i = mt_rand(0,$wcrop-1); $j = mt_rand(0,$hcrop-1); $beta += imagecolorat($im, $xcrop+$i, $ycrop+$j) & 0xFF; } $area = $wcrop * $hcrop; $betanorm = $beta / ($n*pow($area, $gamma-1)); // echo("beta: $beta; betan: $betanorm"); // echo("image$k.jpg:
\n"); // best image found, save it if ($betanorm > $maxbetanorm) { $maxbetanorm = $betanorm; $maxparam['w'] = $wcrop; $maxparam['h'] = $hcrop; $maxparam['x'] = $xcrop; $maxparam['y'] = $ycrop; // $maxfile = $currfile; } } // écrasement de l'image par la version "croppée" $imgcp->cropImage($maxparam['w'], $maxparam['h'], $maxparam['x'], $maxparam['y']); // retailler correctement si au moins une des dimensions de l'image produite est // inférieure aux dimensions demandées $geo = $imgcp->getImageGeometry(); $ratio_la = $geo['width'] / $largeur_vignette; $ratio_ha = $geo['height'] / $hauteur_vignette; if ($ratio_la < 1 || $ratio_ha < 1) { // cas kipu - on agrandit au max la dimension ayant le ratio le plus faible // (= le plus d'écart avec la taille attendue) if ($ratio_la < $ratio_ha) { $imgcp->scaleImage($largeur_vignette, 0); } else { $imgcp->scaleImage(0, $hauteur_vignette); } // puis on recoupe en centrant à l'arrache - bizarre que le script ne fasse pas ça de base :-/ $geo = $imgcp->getImageGeometry(); $imgcp->cropImage($largeur_vignette, $hauteur_vignette, max(0, floor($geo['width'] / 2 - $largeur_vignette / 2)), max(0, floor($geo['height'] / 2 - $hauteur_vignette / 2))); } else { // cas général $imgcp->scaleImage($largeur_vignette, $hauteur_vignette, false); } $imgcp->writeImage($out); // return image chmod($out, 0777); $img->destroy(); $imgcp->destroy(); $image_sortie = ImageCreateFromJpeg($out); } else { // image n'a pas pu être croppée - on retourne l'originale //$image_sortie = ImageCreateFromJpeg($chemin_image); $image_sortie = false; } // destruction fichier temporaire dans tous les cas unlink($out); return $image_sortie; } }