PHP yeniden boyutlandırma verimli JPEG Görüntü

13 Cevap php

PHP Büyük görüntüleri yeniden boyutlandırmak için en etkili yolu nedir?

Ben şu anda yüksek çözünürlüklü görüntü almak imagecopyresampled GD işlevini kullanarak ve temiz (uzun boylu 700 piksel kabaca 700 piksel genişliğinde) görüntüleme web için bir boyut onları aşağı yeniden boyutlandırmak ediyorum.

Bu küçük (2 MB altında) fotoğraflar ve tüm yeniden boyutlandırma işlemi sunucuda bir saniyeden daha kısa sürer harika çalışıyor. Ancak, sitenin olacak sonunda 10 MB boyutunda (veya 5000x4000 boyutunda piksele kadar görüntü) görüntüleri yükleyerek olabilir hizmet fotoğrafçılar.

Büyük görüntülerle yeniden boyutlandırma işlemi bu tür yapıyor (Büyük Resim 80 MB geçmiş komut dosyası için bellek kullanımını başak olabilir) çok büyük bir farkla bellek kullanımını artırmak eğilimindedir. Bu yeniden boyutlandırma işlemi daha verimli hale getirmek için herhangi bir yolu var mı? Böyle ImageMagick olarak alternatif bir görüntü kütüphanesi kullanıyor olmalıdır?

Şu anda, yeniden boyutlandırma kod şöyle

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);

13 Cevap

İnsanlar ImageMagick çok daha hızlı olduğunu söylüyorlar. En iyi ihtimalle sadece iki kitaplıkları karşılaştırmak ve ölçmek.

  1. 1000 tipik görüntüleri hazırlayın.
  2. Write two scripts -- one for GD, one for ImageMagick.
  3. Her ikisi de bir kaç kez çalıştırın.
  4. Compare results (total execution time, CPU and I/O usage, result image quality).

Başka iyi herkes, sizin için iyi bir şey olamazdı.

Ayrıca, benim görüşüme göre, ImageMagick çok daha iyi API arayüzü var.

Burada bir projede kullanılan ve çalışıyor ettik php.net dokümanlar bir parçacık bulunuyor:

<?
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

Hız için (gerekirse GD geri düşen) ve sunucu üzerindeki yükü azaltmak için oldukça iyi önbelleğe görünüyor mümkün phpThumb ImageMagick kullanır. (Sadece grafik dosya ve çıkış boyutları içeren bir GET sorgu ile phpThumb.php çağrı, bir görüntüyü yeniden boyutlandırmak) denemek için oldukça hafif, bu yüzden bunu sizin ihtiyaçlarınıza uygun olup olmadığını görmek için bir şans verebilir.

Büyük Resim Imagemagick görüntü yük boyutlandırmak için libjpeg kullanmak ve böylece önemli ölçüde bellek kullanımını azaltmak ve performansı artırmak için, GD ile mümkün değildir.

$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();

Ben bu satırlar boyunca bir şey çalışmanızı öneririz:

  1. Görüntü tipini ve boyutunu kontrol etmek için yüklenen dosya üzerinde bir getimagesize () gerçekleştir
  2. "Olduğu gibi" hedef klasör içinde 700x700px daha küçük herhangi yüklenen JPEG görüntü kaydetmek
  3. Orta boy görüntüler için GD kütüphanesi kullanımı (örnek kod için bu makaleye bakın: Resize Images Using PHP and GD Library)
  4. Büyük görüntüler için ImageMagick kullanın. İsterseniz arka planda ImageMagick kullanabilirsiniz.

Jpeg s tüm dosyaları "dönüştürmek" ve buna göre onları yeniden boyutlandırır, arka planda ImageMagick kullanmak geçici bir klasöre yüklenen dosyaları taşımak ve bir CRON işi zamanlamak. At komut sözdizimini görmek: imagemagick-command line processing

Bu dosya tarih ve işlenmiş olması planlanıyor ki kullanıcı isteyebilir. CRON işi belirli aralıklarla günlük çalıştırmak için planlanmış olabilir. Kaynak görüntü bir görüntü kez değil işlenir emin olmak için işledikten sonra silinmiş olabilir.

Büyük Resim kullanmak için phpThumb(). İşte bunu kullanmak için nasıl: http://abcoder.com/php/problem-with-resizing-corrupted-images-using-php-image-functions/. Bu da büyük bozuk görüntüler için çalışır.

Ben ne yazık ki benim iş bilgisayarı ve ne evde de yüklemek değil, Imagick kütüphane hakkında büyük şeyler duydum (ve bana güven, ben forumları her türlü saatler geçirdim).

Afterwords, ben bu PHP sınıfı denemeye karar verdim:

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

Bu oldukça serin ve (Ben de JPG çevirebiliriz) görüntüleri her türlü yeniden boyutlandırabilirsiniz.

ImageMagick okuyuculu, böylece daha hızlı gibi görünüyor, ama aslında GD çok daha fazla kaynak kullanır. Eğer birden fazla paralel PHP betikleri koştu durumunda bütün GD kullanarak daha sonra basit işlemler için hız ImageMagick döverdi. ExactImage PHP ile mevcut olmasa da, sunucuya yüklemek ve exec bunu üzerinden çalıştırmak zorunda olacak, çok daha hızlı Imagemagick daha az güçlü ancak.

Bu deneyin:

http://net.tutsplus.com/tutorials/php/image-resizing-made-easy-with-php/comment-page-3/

Resim boyutlandırma ve kırpma için büyük sınıf.

Actually I use this one: http://codeigniter.com/forums/viewthread/92118/#502552

Gerçekten iyi ve hızlı çalışıyor, ama ben büyük dosyalar üzerinde test etmedi.

CodeIgniter tabanlı görüntü boyutlandırma yardımcı, çok, genel durumda çalışmalıdır

http://treetwo.com/2010/03/16/codeigniter-image-helper/

Ive bu 1 fonksiyonu kolay ve basit kullanıyor

https://github.com/Nimrod007/PHP_image_resize/blob/master/smart_resize_image.function.php

Bu yardımcı olur umarım

From you quesion, it seems you are kinda new to GD, I will share some experence of mine, maybe this is a bit off topic, but I think it will be helpful to someone new to GD like you:

$ _FILES ['Resim'] ['tmp_name'] dosyası geçerli dosya ise Step 1, validate file. denetlemek için aşağıdaki işlevi kullanın:

   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']);

Step 2, get file format dosyası (içindekiler) dosya formatını kontrol etmek finfo uzantısı ile aşağıdaki işlevi deneyin. Sen neden sadece dosya formatını kontrol etmek için $ _FILES ["resim"] ["type"] kullanmayın söyleyebilirim? Birisi aslında world.jpg için World.png adında bir dosyayı yeniden adlandırmak eğer ONLY kontrol dosya uzantısı, dosya içeriklerini Çünkü, $ _FILES ["resim"] ["type"] yani, jpeg png değil dönecektir $ _FILES ["resim"] ["type"] yanlış sonuç döndürebilir.

   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 resource daha önce var içeriğinden GD kaynak alın:

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

Step 4, get image dimension Şimdi şu basit kod ile görüntü boyut alabilirsiniz:

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

Now, adlı biz sonra orijinal görüntüden ne var değişken görelim:

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

Step 5, calculate resized image arguments Bu adım, sorunun ilgili, aşağıdaki fonksiyon amaçlı), kod tür uzun, ama o inşaat büyük (imagecopyresampled GD işlevi için argümanlar yeniden boyutlandırmak elde etmektir, hatta üç seçenek vardır: , streç küçültmek ve doldurun.

stretch : çıktı Resmin boyutları ayarladığınız yeni boyut olarak aynıdır. Yükseklik / genişlik oranını tutmak olmaz.

shrink : çıktı Resmin boyutları Verdiğiniz yeni bir boyut aşan ve görüntü yükseklik / genişlik oranını tutmak olmaz.

fill : output image's dimension will be the same as new dimension you give, it will crop & resize image if needed, and keep image height/width ratio. This option is what you need in your 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');

Step 6, resize image $ args, biz aşağıdaki fonksiyon içine yukarıdan aldım ve boyutlandırılan görüntünün yeni kaynak almak $ genişliğini, yüksekliğini $ $ $ biçimini ve kaynak kullanın:

   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);

Step 7, get new contents, yeni GD kaynak içeriğini almak için aşağıdaki işlevi kullanın:

   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);

Step 8 get extension, görüntü formatı (not, görüntü formatı görüntü uzantısı eşit değildir) den uzatılmasını almak için aşağıdaki işlevi kullanın:

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

Biz mike adında bir kullanıcı varsa Step 9 save image, aşağıdakileri yapabilirsiniz bu php dosyası olarak aynı klasöre kaydeder:

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

Step 10 destroy resource GD kaynak yok unutmayın!

imagedestroy($newresource);

ya da bir sınıfın içine tüm kod yazmak ve sadece aşağıdakileri kullanabilirsiniz:

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

TIPS

I recommend not to convert file format that user upload, you will meet many problems, if you really want to, see the following:


Ancak, en kolay yolu GD Kütüphanesi yazılmış benim komut dosyası kullanmak için: GDEnhancer:

PNG, vb, ve dönüştürmek GIF herhangi olmayacaktır zaman dosya biçimi hakkında endişelenmenize gerek yok, ve istediğiniz herhangi bir dosya biçiminde kaydedebilirsiniz, script sizin için otomatik olarak dönüştürür, alfa kanalı verecek sorunlar. Ayrıca GD değil animasyonlu GIF animasyon tutmak.

Burada bir örnek kod:

<?php
use gdenhancer\GDEnhancer;
include_once '../gdenhancer/GDEnhancer.php'; //path of your GDEnhancer.php
$image = new GDEnhancer($tmp_name);
$image->backgroundResize(170, 150, 'fill'); //option 'shrink' or 'fill'
$save = $image->save();
$user_name = 'mike';
$filename = 'avatars/' . $user_name . '.' . $save['extension'];
file_put_contents($filename, $save['contents']);
?>

İşte Demo olduğunu


GD keskin bir öğrenme eğrisi vardır, öğrenmek ve tekrar kodunuzu test etmek gerekir, ayrıca, bir kaç hata onları kendinize düzeltmek zorunda, tho, gibi benzeri animasyon GIF destek vermeyen var :)

Eğer daha fazla sorunuz varsa, sadece ~ terk yorum