2015-03-20 31 views
10

Używam do zmiany rozmiaru zdjęć w czasie wykonywania. Witryna ma funkcję przesyłania obrazów i nie możemy ufać, że użytkownik może korzystać z funkcji przyjaznej dla WWW. Jest to JPEGs, ponieważ w przypadku mass-import istnieje wiele obrazów 3 do 5MB, a nawet kilka tak dużych jak 13MB. Każdy obraz zostaje zamieniony w miniaturę (200x200), a podczas przechodzenia z widoku listy do widoku szczegółowego wyświetlany jest tylko jeden obraz, więc wydajność nie jest ogromną sprawą, chociaż nie możemy całkowicie wyrzucić go z drogi. Oto, co robimy dotąd: uwagaPHP Imagick Optymalizacja 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(); 

Side: Właśnie sobie sprawę błąd w moim warunkowym logiki tutaj o wysokość/szerokość, więc ignorować faktu, że w chwili obecnej. Wkrótce zredaguję to pytanie, aby odzwierciedlić prawidłowe porównanie warunków. Dla tych, którzy go nie złapali, skalowanie wszystkich obrazów jest szerokie, nawet jeśli ma skalować wysokość, a następnie po skalowaniu z powrotem do rozmiaru 1080 height.

Obraz użyty do przetestowania rozpoczyna się jako obraz 3MB 2398×2400. Skalowanie go do wartości 1079x1080 powoduje wyświetlenie obrazu , a następnie dodanie kompresji JPEG w jakości 70 powoduje jej zmniejszenie do 750KB. Za pomocą pliku kraken.io obraz udało się skompresować do wartości poniżej 60 KB. Czy istnieją dodatkowe rzeczy, które mogę zrobić w tym skrypcie, ponieważ musi on zoptymalizować obraz w czasie wykonywania?

Przeczytałem sugestie dotyczące użycia libjpeg, która jest zainstalowana, ale nie mogę znaleźć żadnej dokumentacji na temat tego, jakie funkcje ona obsługuje lub czy istnieje sposób zmuszenia Imagick do użycia go w konkretny sposób. Nie jestem nawet pewien, czy Imagick go już nie używa.

Edit: Rozwiązanie

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

60 KB na obraz o rozmiarach 1079 x 1080 wydaje się być całkiem przyzwoity. Nie sądzę, że można go zmniejszyć o wiele mniej bez zmniejszenia wymiarów pikseli lub poważnie obniżenia jakości. – GolezTrol

+0

Problem polega na tym, że nie zbliżam się do tego w moim scenariuszu. W chwili obecnej jest to ~ 750KB, 60KB było porównaniem (czym narzędzie kraken.io było w stanie zrobić na tym samym obrazie). Nie szukam 60KB jako dokładnego celu, ale poniżej 200KB byłoby miłe. – MaKR

Odpowiedz

9

Ustaw setImageCompressionQuality do wartości 70 i dodać te dwie linie po niej.

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

Spowoduje to radykalne zmniejszenie rozmiaru zdjęć.

+1

Użyłem wcześniej stripImage() i nie przyniosło to efektu. Dodanie setImageFormat ('jpg') bez stripImage() zmniejszyło rozmiar o ~ 20KB więcej (próbowaliśmy zapisać dane exif/meta, ale jest ono drugorzędne względem wydajności). Przy użyciu obu razem końcowy wynik tego obrazu testowego wyniósł 178 KB, co stanowi idealne połączenie jakości i kompresji. Dzięki! – MaKR

+1

Czy ktoś ma wyjaśnienie dziwnego zachowania opisanego przez @MaKR? Dlaczego funkcja "ImpgFormat" ("jpg") powinna być w ogóle potrzebna, jeśli nazwa pliku kończy się na .jpg? Dlaczego w pierwszej kolejności trzeba było ustawićImageCompression()? Czy istnieje wyjaśnienie dla wszystkich tych nonsensów z Imagick? – matteo

+0

Doskonałe rozwiązanie ... Kompresowałem obrazy 5MB tylko do 788KB, dzięki tym dodatkowym metodom pliki są w dwucyfrowych rozmiarach KB. –