Оптимизация изображений «на лету» в Битрикс

Как правило, одним из важных пунктов при проверке сайта через Google Page Speed является оптимизация изображений на сайте. В основном контент-менеджеры, клиенты или сами разработчики загружают на сайт изображения «как есть», хотя в них содержится куча лишней информации, которую можно безболезненно удалить и качество при этом не пострадает. Загружать по одной картинке или даже пачкой на сторонний ресурс, выкачивать их и грузить на сайт долго и муторно. Есть способ поинтереснее. 

Инструменты для оптимизации изображений

Я рассматривал 2 самых распространённых расширения файлов: jpg (jpeg) и png. О них и напишу ниже.

Оптимизация jpg (jpeg).

Опытным путём выяснилось, что тот же google пользуется модулем ImageMagick, которым оснащено большинство серверов ведущих хостеров. Если использовать свой сервер, то поставить его так же не составит труда. Все подробности об этом модуле можно посмотреть на php.net.

2 важных фактора, которые влияют на оптимизацию jpg — это качество и так называемая цветовая субдискретизация.

Для установки качества есть функция Imagick::setImageCompressionQuality(int $quality), тут всё просто — передаём целое число, чем меньше, тем хуже качество. Для субдискретизации оптимальными параметрами для меня оказались ‘2×2’, ‘1×1’, ‘1×1’.  Параметры так же нужно «скормить» IMagick: Imagick::setSamplingFactors (array $factors).

Оптимизация png.

Самым популярной утилитой для оптимизации png оказалась «pngcrush». Она же была на сервере, с которым я работал. Если в работе использовать выделенный сервер, то лучше применить утилиту «pngquant», которая показывает более высокие результаты сжатия.

Ничего нативного для php и этих утилит я не нашёл, по этому применил связку функции exec и консольный команды.

События для оптимизации

Меня интересовало 2 события: загрузки картинки на сервер и ресайз картинки на сайте. Для первого случая отлично подходит событие «OnFileSave«, а для второго «OnAfterResizeImage».

Событие загрузки изображения на сервер

    /**
     * @param array  $fileInfo
     * @param string $fileName
     * @param string $module
     *
     * @return void
     */
    public static function optimizeSavedFile(array $fileInfo, string $fileName, string $module)
    {
        switch ($module) {
            case 'iblock':
            case 'medialibrary':
                break;

            default:
                return;
        }

        if (strpos($fileInfo['type'], 'image') === false) {
            return;
        }

         $fileInfo = (new ImageOptimizer())->optimizeSavedFile($fileInfo); // тут у меня определяется тип файла и какое качество будет применено для сжатия
    }

Событие отображения изображения на сайте

Здесь всё проще, чем в предыдущем событии.

    /**
     * @param array  $fileInfo
     * @param array  $additionalFileInfo
     * @param array  $callbackData
     * @param string $cacheImageFile
     * @param string $cacheImageFileTmp
     * @param array  $imageSizeInfo
     *
     * @return void
     */
    public static function optimizeImageResize(
        array $fileInfo,
        array $additionalFileInfo,
        &$callbackData,
        string &$cacheImageFile,
        string &$cacheImageFileTmp,
        &$imageSizeInfo
    )
    {
        if (is_array($imageSizeInfo)) {
            $imageSizeInfo[2] = (new ImageOptimizer())->optimizeImageResize($cacheImageFile);
        }
    }

Оптимизация

Наконец-то можно поговорить об оптимизации. Как я писал выше, для оптимизации png и jpg один и тот же инструмент не подойдёт — нужно определить с каким расширением имеем дело. Эту часть я опущу т.к. по определению расширения файла полно инфы в интернете.

Оптимизируем jpg (jpeg)

Пример функции оптимизации:

   /**
     * @param string $image
     *
     * @return int
     */
    public function optimize(string $image): int
    {
        try {
            $imagick = new Imagick(realpath($image));

            $imagick->setSamplingFactors(['2x2', '1x1', '1x1']);
            $imagick->setImageCompressionQuality($this->getQuality());
        } catch (ImagickException $exception) {
            AddMessage2Log('Ошибка при попытке оптимизации изображения (Imagick)');
            AddMessage2Log($exception);

            return filesize($image);
        }

        $imagick->writeImage($image);

        return (new Imagick($image))->getImageLength();
    }

Оптимизация png

Проиллюстрирую на примере pngcrush.

    /**
     * @param string $image
     *
     * @return int
     */
    public function optimize(string $image): int
    {
        exec("pngcrush -rem allb -brute -reduce -ow {$image}");

        return (new SplFileInfo($image))->getSize();
    }

Вот, собственно, и всё.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *