2015-03-20 17 views
10

Tôi đang sử dụng PHP Imagick để đổi kích thước hình ảnh khi chạy. Trang web có tính năng tải lên hình ảnh và chúng tôi không thể tin tưởng người dùng sử dụng trang web JPEGs thân thiện với web, như trong mass-import có rất nhiều hình ảnh 3 đến 5MB và thậm chí một số lớn như 13MB. Mỗi hình ảnh được biến thành hình thu nhỏ (200x200) và khi chuyển từ chế độ xem danh sách sang chế độ xem chi tiết, chỉ có một hình ảnh được hiển thị, vì vậy hiệu suất không phải là một vấn đề lớn mặc dù chúng tôi không thể hoàn toàn ném nó theo bên đường. Dưới đây là những gì chúng tôi đang thực hiện cho đến thời điểm này:Tối ưu hóa PHP Imagick JPEG

$iMagick = new Imagick($file); 
$iMagick->setImageResolution(72,72); 
$iMagick->resampleImage(72,72,imagick::FILTER_UNDEFINED,1); 
$geometry = $iMagick->getImageGeometry(); 
if ($geometry['height'] > 1920 || $geometry['width'] > 1080) { 
    $iMagick->scaleImage(1920, 0); 
    if($geometry['height'] > $resizeHeight) { 
     $iMagick->scaleImage(0, 1080); 
    } 
} 
$iMagick->setImageCompression(Imagick::COMPRESSION_JPEG); 
$iMagick->setImageCompressionQuality($compression); 
$iMagick->writeImage($file); 
$Imagick->clear(); 

Lưu ý phụ: Tôi vừa nhận ra lỗ hổng trong logic điều kiện của tôi ở đây về chiều cao/chiều rộng, vì vậy hãy bỏ qua điều đó trong thời gian này. Tôi sẽ sớm chỉnh sửa câu hỏi để phản ánh các so sánh điều kiện chính xác. Đối với những người không nắm bắt nó, nó thu nhỏ tất cả các hình ảnh thành 1920 rộng ngay cả khi nó được cho là mở rộng chiều cao, sau đó sau khi quy mô, nó định kích thước lại xuống 1080 height.

Hình ảnh tôi đã sử dụng để thử nghiệm bắt đầu dưới dạng hình ảnh 3MB 2398×2400. Chia tỷ lệ hình ảnh thành 1079x1080 kết quả bằng hình ảnh 1.5MB, sau đó thêm JPEG nén ở chất lượng 70 mang nó xuống 750KB. Sử dụng kraken.io hình ảnh có thể được nén xuống dưới 60KB. Có bất kỳ điều bổ sung nào tôi có thể thực hiện đối với tập lệnh này vì nó cần tối ưu hóa hình ảnh trong thời gian chạy không?

Tôi đã đọc các đề xuất để sử dụng libjpeg, được cài đặt nhưng tôi không thể tìm thấy bất kỳ tài liệu nào về chức năng nào cho phép hoặc nếu có cách nào để buộc Imagick sử dụng nó một cách cụ thể. Tôi thậm chí không chắc rằng Imagick không sử dụng nó rồi.

Edit: Giải pháp

function itm_optimizeImage($file, $compression = 70, $maxDimensions = ['width' => null, 'height' => null]) { 
    $save = false; 
    $fi = new finfo(FILEINFO_MIME); 
    $mime = explode(';', $fi->file($file)); 
    switch ($mime[0]) { 
     // possible to optimize other image types in the future 
     case 'image/jpeg': 
      try { 
       $iMagick = new Imagick($file); 
       if ($iMagick->getImageCompressionQuality() > $compression) { 
        $file = !itm_compressJPEG($file, $compression, $maxDimensions, $iMagick); 
       } 
      } 
      catch (Exception $e) { 
       error_log(__FUNCTION__ . " $path/$file failed: " . $e->getMessage()); 
       return false; 
      } 
      if ($file) { 
       $pathParts = pathinfo($file); 
       rename($file, $pathParts['dirname'] . '/' . $pathParts['filename'] . '.large.' . $pathParts['extension']); 
       $iMagick->writeImage($file); 
      } 
      $iMagick->clear(); 
      break; 
    } 

    return $file; 
} 

function itm_compressJPEG($file, $compression = 70, $maxDimensions = ['width' => null, 'height' => null], &$iMagick = null) { 
    try { 
     $iMagickCreated = true; 
     if ($iMagick) $iMagickCreated = false; 
     else $iMagick = new Imagick($file); 

     $iMagick->setImageResolution(72,72); 
     $iMagick->resampleImage(72,72,imagick::FILTER_UNDEFINED,1); 
     $geometry = $iMagick->getImageGeometry(); 
     if (($geometry['width']/$maxDimensions['width']) > ($geometry['height']/$maxDimensions['height'])) { 
      // scale by width 
      $iMagick->scaleImage($maxDimensions['width'], 0); 
     } else { 
      // scale by height 
      $iMagick->scaleImage(0, $maxDimensions['height']); 
     } 
     $iMagick->setImageCompression(Imagick::COMPRESSION_JPEG); 
     $iMagick->setImageCompressionQuality($compression); 
     $iMagick->setImageFormat('jpg'); 
     $iMagick->stripImage(); 

     if ($iMagickCreated) { 
      $pathParts = pathinfo($file); 
      rename($file, $pathParts['dirname'] . '/' . $pathParts['filename'] . '.large.' . $pathParts['extension']); 
      $iMagick->writeImage($file); 
      $Imagick->clear(); 
     } 
     return $file; 
    } 
    catch (Exception $e) { 
     error_log(__FUNCTION__ . " $path/$file failed: " . $e->getMessage()); 
     return false; 
    } 
} 
+0

60KB cho hình ảnh 1079x1080 có vẻ khá tốt. Tôi không nghĩ rằng bạn có thể làm cho nó nhỏ hơn nhiều mà không làm giảm kích thước pixel hoặc giảm nghiêm trọng chất lượng. – GolezTrol

+0

Vấn đề là tôi không nhận được bất cứ nơi nào gần đó với kịch bản của tôi. Hiện tại là ~ 750KB, 60KB là một so sánh (công cụ kraken.io có khả năng trên cùng một hình ảnh). Tôi không nhìn vào 60KB như một mục tiêu chính xác, nhưng dưới 200KB sẽ là tốt đẹp. – MaKR

Trả lời

9

Đặt setImageCompressionQuality đến một giá trị là 70 và thêm hai dòng sau sau khi nó.

$image->setImageFormat("jpg"); 
$image->stripImage(); 

Điều này sẽ làm giảm đáng kể kích thước của hình ảnh.

+1

Tôi đã sử dụng stripImage() trước đây và nó không có hiệu lực. Thêm setImageFormat ('jpg') mà không có stripImage() giảm kích thước thêm ~ 20KB (chúng tôi đã cố gắng lưu dữ liệu exif/meta nhưng nó phụ thành hiệu năng). Sử dụng cả hai cùng nhau kết quả cuối cùng của hình ảnh thử nghiệm này là 178KB, đó là về sự kết hợp hoàn hảo về chất lượng và nén. Cảm ơn! – MaKR

+1

Có ai có lời giải thích cho hành vi lạ được mô tả bởi @MaKR không? Tại sao nên setImageFormat ('jpg') ở tất cả nếu tên tập tin kết thúc bằng .jpg? Tại sao nên setImageCompression() cần thiết ở nơi đầu tiên? Có một lời giải thích cho tất cả những điều vô nghĩa của Imagick này không? – matteo

+0

Giải pháp tuyệt vời ... Tôi đã nén hình ảnh 5MB chỉ xuống 788KB, với các phương thức bổ sung này, các tệp này có kích thước KB hai chữ số. –