Efficace image JPEG Redimensionnement en PHP

voix
78

Quel est le moyen le plus efficace pour redimensionner de grandes images en PHP?

Je suis actuellement en utilisant la GD fonction imagecopyresampled pour prendre des images haute résolution, et proprement les redimensionner à une taille pour l' affichage Web (environ 700 pixels de large par 700 pixels de haut).

Cela fonctionne très bien sur les petits (moins de 2 Mo) photos et toute l'opération de modification de taille prend moins d'une seconde sur le serveur. Cependant, le site finira par les photographes de services qui peuvent être télécharger des images jusqu'à 10 Mo en taille (ou des images jusqu'à 5000x4000 pixels en taille).

Faire ce genre d'opération de modification de taille avec de grandes images tend à augmenter l'utilisation de la mémoire par une marge très importante (images plus grandes peuvent spike l'utilisation de la mémoire pour le script 80 Mo passé). Est - il possible de faire cette opération de modification de taille plus efficace? Dois - je utiliser une bibliothèque d'images de remplacement comme ImageMagick ?

En ce moment, le code de modification de taille ressemble à ceci

function makeThumbnail($sourcefile, $endfile, $thumbwidth, $thumbheight, $quality) {
    // Takes the sourcefile (path/to/image.jpg) and makes a thumbnail from it
    // and places it at endfile (path/to/thumb.jpg).

    // Load image and get image size.
    $img = imagecreatefromjpeg($sourcefile);
    $width = imagesx( $img );
    $height = imagesy( $img );

    if ($width > $height) {
        $newwidth = $thumbwidth;
        $divisor = $width / $thumbwidth;
        $newheight = floor( $height / $divisor);
    } else {
        $newheight = $thumbheight;
        $divisor = $height / $thumbheight;
        $newwidth = floor( $width / $divisor );
    }

    // Create a new temporary image.
    $tmpimg = imagecreatetruecolor( $newwidth, $newheight );

    // Copy and resize old image into new image.
    imagecopyresampled( $tmpimg, $img, 0, 0, 0, 0, $newwidth, $newheight, $width, $height );

    // Save thumbnail into a file.
    imagejpeg( $tmpimg, $endfile, $quality);

    // release the memory
    imagedestroy($tmpimg);
    imagedestroy($img);
Créé 15/08/2008 à 20:55
source utilisateur
Dans d'autres langues...                            


9 réponses

voix
44

Les gens disent que ImageMagick est beaucoup plus rapide. Au mieux comparer simplement les deux bibliothèques et de mesurer que.

  1. Préparer 1000 images typiques.
  2. Écrire deux scripts - un pour GD, un pour ImageMagick.
  3. Exécutez les deux d'entre eux plusieurs fois.
  4. Comparer les résultats (temps d'exécution total, utilisation CPU et E / S, la qualité de l'image résultat).

Quelque chose que le meilleur tout le monde, ne pouvait pas être le meilleur pour vous.

De plus, à mon avis, ImageMagick a bien meilleure interface API.

Créé 15/08/2008 à 23:08
source utilisateur

voix
19

Voici un extrait des PHP.net docs que j'ai utilisé dans un projet et fonctionne très bien:

<?
function fastimagecopyresampled (&$dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h, $quality = 3) {
    // Plug-and-Play fastimagecopyresampled function replaces much slower imagecopyresampled.
    // Just include this function and change all "imagecopyresampled" references to "fastimagecopyresampled".
    // Typically from 30 to 60 times faster when reducing high resolution images down to thumbnail size using the default quality setting.
    // Author: Tim Eckel - Date: 09/07/07 - Version: 1.1 - Project: FreeRingers.net - Freely distributable - These comments must remain.
    //
    // Optional "quality" parameter (defaults is 3). Fractional values are allowed, for example 1.5. Must be greater than zero.
    // Between 0 and 1 = Fast, but mosaic results, closer to 0 increases the mosaic effect.
    // 1 = Up to 350 times faster. Poor results, looks very similar to imagecopyresized.
    // 2 = Up to 95 times faster.  Images appear a little sharp, some prefer this over a quality of 3.
    // 3 = Up to 60 times faster.  Will give high quality smooth results very close to imagecopyresampled, just faster.
    // 4 = Up to 25 times faster.  Almost identical to imagecopyresampled for most images.
    // 5 = No speedup. Just uses imagecopyresampled, no advantage over imagecopyresampled.

    if (empty($src_image) || empty($dst_image) || $quality <= 0) { return false; }
    if ($quality < 5 && (($dst_w * $quality) < $src_w || ($dst_h * $quality) < $src_h)) {
        $temp = imagecreatetruecolor ($dst_w * $quality + 1, $dst_h * $quality + 1);
        imagecopyresized ($temp, $src_image, 0, 0, $src_x, $src_y, $dst_w * $quality + 1, $dst_h * $quality + 1, $src_w, $src_h);
        imagecopyresampled ($dst_image, $temp, $dst_x, $dst_y, 0, 0, $dst_w, $dst_h, $dst_w * $quality, $dst_h * $quality);
        imagedestroy ($temp);
    } else imagecopyresampled ($dst_image, $src_image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
    return true;
}
?>

http://us.php.net/manual/en/function.imagecopyresampled.php#77679

Créé 15/08/2008 à 22:50
source utilisateur

voix
11

phpThumb utilise ImageMagick chaque fois que possible pour la vitesse (retombant à GD si nécessaire) et semble mettre en cache assez bien pour réduire la charge sur le serveur. Il est assez léger pour essayer (pour redimensionner une image, il suffit d' appeler phpThumb.php avec une requête GET qui inclut les noms de fichiers graphiques et les dimensions de sortie), de sorte que vous pouvez lui donner un coup de feu pour voir si elle répond à vos besoins.

Créé 15/08/2008 à 21:53
source utilisateur

voix
9

Pour de plus grandes images utilisent libjpeg pour redimensionner la charge d'image dans ImageMagick et réduisant ainsi de manière significative l'utilisation de la mémoire et l'amélioration des performances, il est impossible avec GD.

$im = new Imagick();
try {
  $im->pingImage($file_name);
} catch (ImagickException $e) {
  throw new Exception(_('Invalid or corrupted image file, please try uploading another image.'));
}

$width  = $im->getImageWidth();
$height = $im->getImageHeight();
if ($width > $config['width_threshold'] || $height > $config['height_threshold'])
{
  try {
/* send thumbnail parameters to Imagick so that libjpeg can resize images
 * as they are loaded instead of consuming additional resources to pass back
 * to PHP.
 */
    $fitbyWidth = ($config['width_threshold'] / $width) > ($config['height_threshold'] / $height);
    $aspectRatio = $height / $width;
    if ($fitbyWidth) {
      $im->setSize($config['width_threshold'], abs($width * $aspectRatio));
    } else {
      $im->setSize(abs($height / $aspectRatio), $config['height_threshold']);
    }
    $im->readImage($file_name);

/* Imagick::thumbnailImage(fit = true) has a bug that it does fit both dimensions
 */
//  $im->thumbnailImage($config['width_threshold'], $config['height_threshold'], true);

// workaround:
    if ($fitbyWidth) {
      $im->thumbnailImage($config['width_threshold'], 0, false);
    } else {
      $im->thumbnailImage(0, $config['height_threshold'], false);
    }

    $im->setImageFileName($thumbnail_name);
    $im->writeImage();
  }
  catch (ImagickException $e)
  {
    header('HTTP/1.1 500 Internal Server Error');
    throw new Exception(_('An error occured reszing the image.'));
  }
}

/* cleanup Imagick
 */
$im->destroy();
Créé 06/01/2011 à 10:15
source utilisateur

voix
8

De vous quesion, il semble que vous êtes un peu nouveau à GD, je vais partager quelques experence à moi, peut-être c'est un peu hors sujet, mais je pense que ce sera utile à quelqu'un de nouveau à GD comme vous:

Étape 1, fichier valider. Utilisez la fonction suivante pour vérifier si le $_FILES['image']['tmp_name']fichier est un fichier valide:

   function getContentsFromImage($image) {
      if (@is_file($image) == true) {
         return file_get_contents($image);
      } else {
         throw new \Exception('Invalid image');
      }
   }
   $contents = getContentsFromImage($_FILES['image']['tmp_name']);

Étape 2, obtenir le format de fichier Essayez la fonction suivante avec finfo extension pour vérifier le format de fichier du fichier (contenu). Vous diriez pourquoi ne pas utiliser simplement $_FILES["image"]["type"]pour vérifier le format de fichier? Parce qu'il SEULEMENT vérifier l' extension du fichier fichier non contenu, si quelqu'un renommer un fichier appelé à l' origine world.png à world.jpg , $_FILES["image"]["type"]retournera pas jpeg ou png, donc $_FILES["image"]["type"]peut retourner un résultat erroné.

   function getFormatFromContents($contents) {
      $finfo = new \finfo();
      $mimetype = $finfo->buffer($contents, FILEINFO_MIME_TYPE);
      switch ($mimetype) {
         case 'image/jpeg':
            return 'jpeg';
            break;
         case 'image/png':
            return 'png';
            break;
         case 'image/gif':
            return 'gif';
            break;
         default:
            throw new \Exception('Unknown or unsupported image format');
      }
   }
   $format = getFormatFromContents($contents);

Step.3, Get GD ressources Get GD ressources de contenu que nous avons avant:

   function getGDResourceFromContents($contents) {
      $resource = @imagecreatefromstring($contents);
      if ($resource == false) {
         throw new \Exception('Cannot process image');
      }
      return $resource;
   }
   $resource = getGDResourceFromContents($contents);

Étape 4, obtenir la dimension d'image Maintenant , vous pouvez obtenir la dimension d'image avec le code simple suivant:

  $width = imagesx($resource);
  $height = imagesy($resource);

Maintenant, Voyons voir quelle variable nous avons obtenu de l'image d' origine , alors:

       $contents, $format, $resource, $width, $height
       OK, lets move on

Étape 5, calculer les arguments d'image redimensionnées Cette étape est liée à votre question, le but de la fonction suivante est d'obtenir redimensionner des arguments pour la fonction GD imagecopyresampled(), le code est un peu long, mais il fonctionne très bien, il a même trois options: étirer, réduire et remplir.

étirer : la dimension deimage de sortie est la même que la nouvelle dimensionvous définissez. Ne garderrapport hauteur / largeur.

rétrécir : la dimension deimage de sortie ne dépasse pas la nouvelle dimensionvous donnez, etgarderhauteur deimage / largeur.

remplir : la dimension deimage de sortie sera la même que nouvelle dimensionvous donnez, il rogner et redimensionner l' image si nécessaire, etgarderimage rapport hauteur / largeur. Cette option est ce que vous avez besoin dans votre question.

   function getResizeArgs($width, $height, $newwidth, $newheight, $option) {
      if ($option === 'stretch') {
         if ($width === $newwidth && $height === $newheight) {
            return false;
         }
         $dst_w = $newwidth;
         $dst_h = $newheight;
         $src_w = $width;
         $src_h = $height;
         $src_x = 0;
         $src_y = 0;
      } else if ($option === 'shrink') {
         if ($width <= $newwidth && $height <= $newheight) {
            return false;
         } else if ($width / $height >= $newwidth / $newheight) {
            $dst_w = $newwidth;
            $dst_h = (int) round(($newwidth * $height) / $width);
         } else {
            $dst_w = (int) round(($newheight * $width) / $height);
            $dst_h = $newheight;
         }
         $src_x = 0;
         $src_y = 0;
         $src_w = $width;
         $src_h = $height;
      } else if ($option === 'fill') {
         if ($width === $newwidth && $height === $newheight) {
            return false;
         }
         if ($width / $height >= $newwidth / $newheight) {
            $src_w = (int) round(($newwidth * $height) / $newheight);
            $src_h = $height;
            $src_x = (int) round(($width - $src_w) / 2);
            $src_y = 0;
         } else {
            $src_w = $width;
            $src_h = (int) round(($width * $newheight) / $newwidth);
            $src_x = 0;
            $src_y = (int) round(($height - $src_h) / 2);
         }
         $dst_w = $newwidth;
         $dst_h = $newheight;
      }
      if ($src_w < 1 || $src_h < 1) {
         throw new \Exception('Image width or height is too small');
      }
      return array(
          'dst_x' => 0,
          'dst_y' => 0,
          'src_x' => $src_x,
          'src_y' => $src_y,
          'dst_w' => $dst_w,
          'dst_h' => $dst_h,
          'src_w' => $src_w,
          'src_h' => $src_h
      );
   }
   $args = getResizeArgs($width, $height, 150, 170, 'fill');

Étape 6, redimensionner l' image Utiliser $args, $width, $height, $formatet des ressources de $ que nous avons en haut dans la fonction suivante et obtenir la nouvelle ressource de l'image redimensionnée:

   function runResize($width, $height, $format, $resource, $args) {
      if ($args === false) {
         return; //if $args equal to false, this means no resize occurs;
      }
      $newimage = imagecreatetruecolor($args['dst_w'], $args['dst_h']);
      if ($format === 'png') {
         imagealphablending($newimage, false);
         imagesavealpha($newimage, true);
         $transparentindex = imagecolorallocatealpha($newimage, 255, 255, 255, 127);
         imagefill($newimage, 0, 0, $transparentindex);
      } else if ($format === 'gif') {
         $transparentindex = imagecolorallocatealpha($newimage, 255, 255, 255, 127);
         imagefill($newimage, 0, 0, $transparentindex);
         imagecolortransparent($newimage, $transparentindex);
      }
      imagecopyresampled($newimage, $resource, $args['dst_x'], $args['dst_y'], $args['src_x'], $args['src_y'], $args['dst_w'], $args['dst_h'], $args['src_w'], $args['src_h']);
      imagedestroy($resource);
      return $newimage;
   }
   $newresource = runResize($width, $height, $format, $resource, $args);

Étape 7, obtenir de nouveaux contenus , utilisez la fonction suivante pour obtenir le contenu de la nouvelle ressource GD:

   function getContentsFromGDResource($resource, $format) {
      ob_start();
      switch ($format) {
         case 'gif':
            imagegif($resource);
            break;
         case 'jpeg':
            imagejpeg($resource, NULL, 100);
            break;
         case 'png':
            imagepng($resource, NULL, 9);
      }
      $contents = ob_get_contents();
      ob_end_clean();
      return $contents;
   }
   $newcontents = getContentsFromGDResource($newresource, $format);

Étape 8 get extension , utilisez la fonction suivante pour obtenir l' extension de l' image du format (note, le format d'image ne correspond pas à l' extension de l' image):

   function getExtensionFromFormat($format) {
      switch ($format) {
         case 'gif':
            return 'gif';
            break;
         case 'jpeg':
            return 'jpg';
            break;
         case 'png':
            return 'png';
      }
   }
   $extension = getExtensionFromFormat($format);

Étape 9 Enregistrer l' image Si nous avons un utilisateur nommé Mike, vous pouvez faire ce qui suit, il enregistre dans le même dossier que ce script php:

$user_name = 'mike';
$filename = $user_name . '.' . $extension;
file_put_contents($filename, $newcontents);

Étape 10 détruire des ressources Ne pas oublier de détruire la ressource GD!

imagedestroy($newresource);

ou vous pouvez écrire tout votre code dans une classe, et il suffit d'utiliser les éléments suivants:

   public function __destruct() {
      @imagedestroy($this->resource);
   }

CONSEILS

Je recommande de ne pas convertir le format de fichier qui uploads, vous rencontrerez de nombreux problèmes.

Créé 30/10/2013 à 07:28
source utilisateur

voix
3

Je suggère que vous travaillez quelque chose le long de ces lignes:

  1. Effectuez une (getimagesize) sur le fichier téléchargé pour vérifier le type d'image et la taille
  2. Enregistrer une image JPEG téléchargée plus petite que 700x700px dans le dossier de destination « en l'état »
  3. Utilisez la bibliothèque GD pour les images de taille moyenne (voir cet article pour exemple de code: Redimensionner les images en utilisant PHP et GD Library )
  4. Utilisez ImageMagick pour les grandes images. Vous pouvez utiliser ImageMagick en arrière-plan si vous préférez.

Pour utiliser ImageMagick en arrière - plan, déplacez les fichiers téléchargés dans un dossier temporaire et planifier un travail CRON que tous les fichiers s « convertir » au format JPEG et les redimensionne en conséquence. Voir la syntaxe de commande à: traitement de la ligne ImageMagick-commande

Vous pouvez demander à l'utilisateur que le fichier est téléchargé et devrait être traitée. Le travail CRON pourrait être programmé pour exécuter tous les jours à un intervalle spécifique. L'image source peut être supprimée après le traitement pour assurer que l'image ne sont pas traitées deux fois.

Créé 04/04/2009 à 09:25
source utilisateur

voix
2

ImageMagick est multithread, donc il semble être plus rapide, mais il utilise en fait beaucoup plus de ressources que GD. Si vous avez exécuté plusieurs scripts PHP en parallèle en utilisant tous les GD alors qu'ils avaient battu ImageMagick vitesse pour des opérations simples. ExactImage est moins puissant que ImageMagick mais beaucoup plus rapide, mais pas disponible via PHP, vous devez l' installer sur le serveur et l' exécuter à travers exec.

Créé 30/11/2011 à 06:37
source utilisateur

voix
2

J'ai entendu de grandes choses à propos de la bibliothèque Imagick, malheureusement je ne pouvais pas l'installer sur mon ordinateur de travail et ni à la maison (et croyez-moi, je passais des heures et des heures sur toutes sortes de forums).

Postfaces, j'ai décidé d'essayer cette classe PHP:

http://www.verot.net/php_class_upload.htm

Il est assez cool et je peux redimensionner toutes sortes d'images (je peux les convertir en JPG aussi).

Créé 15/02/2011 à 14:21
source utilisateur

voix
1

Pour des images plus grandes utilisent phpThumb () . Voici comment l'utiliser: http://abcoder.com/php/problem-with-resizing-corrupted-images-using-php-image-functions/ . Il fonctionne également pour les grandes images corrompues.

Créé 05/06/2009 à 19:40
source utilisateur

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more