config = $config; $this->mode = self::MODE_GD; if (extension_loaded('imagick')) { putenv('MAGICK_TEMPORARY_PATH='.$this->config['cel_db']['chemin_stockage_temp']); $this->mode = self::MODE_IMAGEMAGICK; } } public function recreerMiniaturesRecursivement() { $this->itererRecursivement($this->config['cel_db']['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); } } } 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 creerMiniatureImageSelonFormat($infos_image_originale, $format = 'O') { 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); } else { // si l'on ne dispose que de gd // 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; } 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['hauteur'] - $cote_carre)/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['largeur'] - $cote_carre)/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; } public function stockerFichierEtCreerMiniatures($fichier, $id) { $chemin_base_fichier = $this->creerSiNecessaireEtRenvoyerCheminStockageFichierPourIdEtFormat($id, 'O'); $nom_fichier = $this->convertirIdBddVersNomFichier($id, 'O'); $chemin_fichier = $chemin_base_fichier.'/'.$nom_fichier; $deplacement_fichier = $this->stockerImageExterne($fichier['tmp_name'], $chemin_fichier); if ($deplacement_fichier) { $infos_image_originale = $this->obtenirImageEtInfosPourChemin($chemin_fichier); $taux_compression = $this->renvoyerTauxCompressionPourPoids($infos_image_originale['poids_octets']); if ($taux_compression < 100 && $this->mode == self::MODE_IMAGEMAGICK) { $this->ecrireImageSurDisqueAvecMeta($chemin_fichier, $taux_compression); } $infos_image_originale_stockee = $this->obtenirImageEtInfosPourChemin($chemin_fichier); $formats = $this->getFormats(); // creation de miniatures pour chacuns des formats définis foreach($formats as $format) { $this->creerEtStockerMiniatureFichierImageSelonFormat($id, $infos_image_originale_stockee, $format); } return true ; } else { $erreur = 'ERROR : probleme durant le déplacement du fichier temporaire \n' ; $this->logger('CEL_bugs',$erreur); return false ; } } public function stockerImageExterne($chemin_fichier_temp, $chemin_destination) { 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_db']['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']) = getimagesize($chemin_fichier); $image_et_infos['poids_octets'] = filesize($chemin_fichier); $image_et_infos['image'] = imagecreatefromjpeg($chemin_fichier); $image_et_infos['chemin'] = $chemin_fichier; } return $image_et_infos; } public function obtenirDimensionsPourFormat($format) { $dimensions = array('largeur' => 0, 'hauteur' => 0); if (isset($this->config['cel_db']['format_'.$format])) { list($dimensions['largeur'], $dimensions['hauteur']) = explode('_', $this->config['cel_db']['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 { $rapport = $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_db']['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) ; $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($image_a_stocker, $compression = 100) { $image_a_stocker = new Imagick($image_a_stocker); // l'utilisation d'image magick préserve les métadonnées lors d'une recompression $image_a_stocker->setformat("jpeg"); $image_a_stocker->setImageCompression(imagick::COMPRESSION_JPEG); $image_a_stocker->setCompressionQuality($compression); $image_a_stocker->writeImage($image_a_stocker); $image_a_stocker->destroy(); chmod($image_a_stocker,$this->droits); } 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); } public function detruireImageSurDisque($id) { $formats = $this->getFormats(); // on detruit aussi l'image originale $formats[] = 'O'; $destruction_formats_fichier = false; // destructions de chacuns 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)) { $destruction_formats_fichier = unlink($dossier_format.'/'.$nom_fichier); } else { $destruction_formats_fichier = true; } } return $destruction_formats_fichier; } /* * 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); $nom_temp = md5(time()); $chemin_temp = $out = $this->config['cel_db']['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']; //if ($largeur_vignette > $largeur_image_originale || $hauteur_vignette > $hauteur_image_originale) // die("Target dimensions must be smaller or equal to source dimensions."); // 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"); $img = new Imagick($chemin_image); $imgcp = clone $img; // compute center of edginess $img->edgeImage($r); $img->modulateImage(100,0,100); // grayscale $img->blackThresholdImage("#0f0f0f"); $img->writeImage($out); // use gd for random pixel access $im = ImageCreateFromJpeg($out); $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 { // 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; /*if (self::MODE_DEBUG) { // debug $currfile = '/home/aurelien/web/file_tmp/'."image$k.jpg"; $currimg = clone $img; $c= new ImagickDraw(); $c->setFillColor("red"); $c->circle($xcenter, $ycenter, $xcenter, $ycenter+4); $currimg->drawImage($c); $currimg->cropImage($wcrop, $hcrop, $xcrop, $ycrop); $currimg->writeImage($currfile); $currimg->destroy(); }*/ $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; } } // return image $imgcp->cropImage($maxparam['w'], $maxparam['h'], $maxparam['x'], $maxparam['y']); $imgcp->scaleImage($largeur_vignette, $hauteur_vignette); $imgcp->writeImage($out); chmod($out, 0777); $img->destroy(); $imgcp->destroy(); $image_sortie = ImageCreateFromJpeg($out); unlink($out); return $image_sortie; } } ?>