Оптимизация картинок сайта на PHP (Сжатие)

18:02 4.09.2017
Инструмент Google PageSpeed Insights рекомендует оптимизировать картинки, что находятся на сайте, сжать их на столько, сколько это возможно. Я решил написать сценарий, который будет сжимать картинки жертвуя качеством (качество можно настроить так, что потеря заметно не будет).

Для решения этого вопроса я выбрал класс Imagick: http://php.net/manual/ru/class.imagick.php.
Недостаток - работает только с JPEG форматом картинок, но думаю в дальнейшем буду дописывать и для других форматов. На данный момент формат PNG перевод в JPG.

Код оптимизатора картинок не большой (пока так):
$imagick = new Imagick($img);

$data = $imagick->identifyImage();
if ($data['mimetype'] == 'image/png')
{
	$imagick->setBackgroundColor('#FFFFFF');
	$imagick = $imagick->mergeImageLayers(Imagick::LAYERMETHOD_FLATTEN);

	unlink($img);
	$img = str_replace('.png', '.jpg', $img);
}

$imagick->setCompression(Imagick::COMPRESSION_JPEG);
$imagick->setImageCompressionQuality(75);
$imagick->writeImage('compress_' . $img);

Рассказываю, что тут происходит:
Первая строка: Создаем объект $imagick, чтобы работать с классом Imagick.
Третья строка: Определяем изображение и получаем все его атрибуты.
Четвертая строка: Тут проверяем "mimetype" изображения, ожидаем "image/png".
Следующие четыре строчки выполняются в случае, если "mimetype" оказалось "image/png":
Шестая строка: Устанавливаем фон белым, там, где он был прозрачным.
Седьмая строка: Сливаем слои.
Девятая строка: Удаляем оригинал картинки в формате PNG.
Десятая строка: Заменяем формат картинки с ".png" на ".jpg", в полном названии изображения.
Тринадцатая строка: Устанавливаем тип сжатия картинки.
Четырнадцатая строка: Устанавливаем качество картинки (от 0 до 100).
Пятнадцатая строка: Сохраняем новую картинку.

Если удалять оригинальную картинку не надо, то удалите или закомментируйте девятую строку (unlink($img);). Название нового файла можно изменить в пятнадцатой строке ('compress_' . $img).
11:24 5.09.2017
Сжимать картинку еще можно путем удаление метаданных. PHP + Imagick (пример):
$imagick = new Imagick($img);

$imagick->setCompression(imagick::COMPRESSION_JPEG);
$imagick->setCompressionQuality(100);
$imagick->stripImage();
$imagick->writeImage('compress_' . $img);

Все функции, что находятся в примере описаны в первом посте, кроме stripImage - эта функция снимает все профили и комментарии с фотографии: http://php.net/manual/ru/imagick.stripimage.php.

Код из первого поста и второго можно совместить, для этого в коде, что в первом посте, после строки:
$imagick->setImageCompressionQuality(75);

Добавляем:
$imagick->stripImage();

Готово.
11:46 8.11.2017
Приветствую, Slash. Благодарю за полезный скрипт. Мне как раз не хватало такого.

Пока думаю, как установить скрипт, возник вопрос, что будет с картинкой если она ранее была сжата ещё сильнее. Например, если скрипт обработает картинку, которая была сжата до него до уровнял 65%, не увеличится ли её объем.
18:41 8.11.2017
cefp сказал:
11:46 am, Ноябрь 8, 2017 (id: #1641)
Например, если скрипт обработает картинку, которая была сжата до него до уровнял 65%, не увеличится ли её объем.

Я думаю, что объем у картинки не увеличиться. Но и тут же, зачем еще раз сжимать картинку, которая уже сжата. Наверно, лучше ее не сжимать на второй раз, качество может получиться хуже. Разве, что удалить метаданные, если они еще не удалены.
16:49 11.11.2017
Я также думаю. Просто пользователи сайта могут загрузить сжатую картинку, а скрипт её еще раз сожмёт, изменив уровень сжатия. Интересно можно ли до сжатия проверять какой уровень сжатия исходной картинки. Думаю, что можно добавить условие сравнения объемов обработанной и исходной картинки или если объем не уменьшился, то оставлять картинку без изменений.

Я тем временем нашёл у себя в коде php, где происходит создание миниатюр к картинкам. И там тоже используется imagick, только не много в другом виде. Вот что получилось:

@passthru(escapeshellcmd($config['img_imagick']) . 'convert' . ((defined('PHP_OS') && preg_match('#^win#i', PHP_OS)) ? '.exe' : '') . ' -filter Triangle -define filter:support=2 -thumbnail OUTPUT_WIDTH -unsharp 0.25x0.08+8.3+0.045 -dither None -posterize 136 -quality 82 -define jpeg:fancy-upsampling=off -define png:compression-filter=5 -define png:compression-level=9 -define png:compression-strategy=1 -define png:exclude-chunk=all -interlace none -colorspace sRGB -geometry ' . $new_width . 'x' . $new_height . ' "' . str_replace('\\', '/', $source) . '" "' . str_replace('\\', '/', $destination) . '"');

Как видно в коде, я установил уровень сжатия 82.

До правки код выглядел так:
@passthru(escapeshellcmd($config['img_imagick']) . 'convert' . ((defined('PHP_OS') && preg_match('#^win#i', PHP_OS)) ? '.exe' : '') . ' -quality 85 -geometry ' . $new_width . 'x' . $new_height . ' "' . str_replace('\\', '/', $source) . '" "' . str_replace('\\', '/', $destination) . '"');


Заметил ещё кое-что. Сервис PageSpeed Insights в конце списка улучшений предлагает скачать картинки с наилучшим с его точки зрения сжатием. Если посмотреть на картинки, то видно, что PageSpeed сжимает их с искажением - на мелких красочных элементах падает насыщенность цвета.