Налаштування автоматичної оптимізації медіафайлів 1С-Бітрікс

Наша компанія займається розробкою, підтримкою та обслуговуванням рішень на Бітрікс та Бітрікс24 будь-якої складності. Від простих односторінкових сайтів до складних інтернет-магазинів, CRM систем з інтеграцією 1С та телефонії. Досвід розробників підтверджено сертифікатами від вендора.
Пропоновані послуги
Показано 1 з 1 послугУсі 1626 послуг
Налаштування автоматичної оптимізації медіафайлів 1С-Бітрікс
Проста
~1 робочий день
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Розробка на базі Бітрікс, Бітрікс24, 1С для компанії Development of an Online
    585
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Розробка на базі 1С Підприємство для компанії МИРСАНБЕЛ
    751
  • image_crm_dolbimby_434_0.webp
    Розробка сайту на CRM Бітрікс24 для компанії DOLBIMBY
    657
  • image_crm_technotorgcomplex_453_0.webp
    Розробка на базі Бітрікс24 для компанії ТЕХНОТОРГКОМПЛЕКС
    989

Налаштування автоматичної оптимізації медіафайлів 1С-Бітрікс

Сторінка каталогу завантажує 40 зображень товарів загальною вагою 8 МБ. Google PageSpeed показує «Використовуйте зображення в сучасних форматах» та «Правильно задайте розмір зображень». Бітрікс зберігає оригінали в /upload/ та створює ресайзи через CFile::ResizeImageGet() — але формат залишається JPEG/PNG, і немає автоматичної конвертації в WebP. Налаштування автоматичної оптимізації — це кілька рівнів: ресайз під реальні розміри, конвертація в WebP, стиснення без втрат та віддача через CDN.

Рівень 1: ресайз при збереженні оригіналу

Стандартний CFile::ResizeImageGet() створює ресайз при першому запиті та кешує результат у /upload/resize_cache/. Основна проблема — оригінали зберігаються без стиснення, і менеджери завантажують фотографії з телефону розміром 5–10 МБ.

Стиснення при завантаженні через обробник події:

\Bitrix\Main\EventManager::getInstance()->addEventHandler(
    'main',
    'OnAfterFileSave',
    function (\Bitrix\Main\Event $event) {
        $file = $event->getParameter('FILE');

        // Обробляємо тільки зображення
        if (!in_array($file['CONTENT_TYPE'], ['image/jpeg', 'image/png', 'image/gif'])) {
            return;
        }

        $path = $_SERVER['DOCUMENT_ROOT'] . $file['SRC'];
        if (!file_exists($path)) {
            return;
        }

        // Стиснення через Imagick або GD
        \Local\Media\ImageOptimizer::compress($path, $file['CONTENT_TYPE']);
    }
);
// /local/lib/Media/ImageOptimizer.php
namespace Local\Media;

class ImageOptimizer
{
    public static function compress(string $path, string $contentType): void
    {
        if (!extension_loaded('imagick')) {
            self::compressWithGd($path, $contentType);
            return;
        }

        $img = new \Imagick($path);

        // Видаляємо зайві метадані (EXIF, ICC)
        $img->stripImage();

        // Обмежуємо максимальний розмір оригіналу
        $width  = $img->getImageWidth();
        $height = $img->getImageHeight();
        if ($width > 2000 || $height > 2000) {
            $img->resizeImage(2000, 2000, \Imagick::FILTER_LANCZOS, 1, true);
        }

        if ($contentType === 'image/jpeg') {
            $img->setImageCompression(\Imagick::COMPRESSION_JPEG);
            $img->setImageCompressionQuality(85);
        } elseif ($contentType === 'image/png') {
            $img->setImageCompression(\Imagick::COMPRESSION_ZIP);
            $img->setOption('png:compression-level', '9');
        }

        $img->writeImage($path);
        $img->destroy();
    }

    private static function compressWithGd(string $path, string $contentType): void
    {
        if ($contentType === 'image/jpeg') {
            $img = imagecreatefromjpeg($path);
            imagejpeg($img, $path, 85);
            imagedestroy($img);
        } elseif ($contentType === 'image/png') {
            $img = imagecreatefrompng($path);
            imagepng($img, $path, 9);
            imagedestroy($img);
        }
    }
}

Рівень 2: конвертація в WebP

WebP дає 25–35% виграш у розмірі порівняно з JPEG при співставній якості. Підтримка браузерами — 97%+ (всі сучасні). Стратегія: генеруємо WebP-версію поряд з оригіналом, nginx віддає WebP браузерам, що підтримують формат.

Генерація WebP при ресайзі:

// Перевизначаємо логіку ресайзу в /local/php_interface/init.php
\Bitrix\Main\EventManager::getInstance()->addEventHandler(
    'main',
    'OnAfterGetResizeImagePath',
    function (\Bitrix\Main\Event $event) {
        $result = $event->getParameter('RESULT');
        $src = $result['src'] ?? '';

        if (!$src || !preg_match('/\.(jpg|jpeg|png)$/i', $src)) {
            return;
        }

        $localPath = $_SERVER['DOCUMENT_ROOT'] . $src;
        $webpPath  = preg_replace('/\.(jpg|jpeg|png)$/i', '.webp', $localPath);

        if (!file_exists($webpPath) && file_exists($localPath)) {
            \Local\Media\WebpConverter::convert($localPath, $webpPath);
        }
    }
);
class WebpConverter
{
    public static function convert(string $sourcePath, string $destPath): bool
    {
        if (extension_loaded('imagick')) {
            $img = new \Imagick($sourcePath);
            $img->setImageFormat('webp');
            $img->setOption('webp:method', '6');
            $img->setImageCompressionQuality(82);
            $img->stripImage();
            $img->writeImage($destPath);
            $img->destroy();
            return true;
        }

        if (function_exists('imagewebp')) {
            $ext = strtolower(pathinfo($sourcePath, PATHINFO_EXTENSION));
            $img = match($ext) {
                'jpg', 'jpeg' => imagecreatefromjpeg($sourcePath),
                'png'         => imagecreatefrompng($sourcePath),
                default       => null,
            };
            if ($img) {
                imagewebp($img, $destPath, 82);
                imagedestroy($img);
                return true;
            }
        }

        return false;
    }
}

Nginx: віддача WebP браузерам з підтримкою

map $http_accept $webp_suffix {
    default "";
    "~*webp" ".webp";
}

server {
    location ~* ^(/upload/resize_cache/.+)\.(jpg|jpeg|png)$ {
        set $img_path $1.$2;
        set $webp_path $1.webp;

        # Віддаємо WebP, якщо підтримується і файл існує
        if ($webp_suffix = ".webp") {
            add_header Vary Accept;
            try_files $webp_path $img_path =404;
        }

        try_files $img_path =404;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
}

Рівень 3: lazy loading та responsive images

В шаблоні компонента каталогу додаємо loading="lazy" та srcset:

// В шаблоні компонента: template.php
$img  = \CFile::ResizeImageGet($element['PREVIEW_PICTURE'], ['width' => 300, 'height' => 300]);
$img2 = \CFile::ResizeImageGet($element['PREVIEW_PICTURE'], ['width' => 600, 'height' => 600]);
?>
<img
    src="<?= htmlspecialchars($img['src']) ?>"
    srcset="<?= htmlspecialchars($img['src']) ?> 300w, <?= htmlspecialchars($img2['src']) ?> 600w"
    sizes="(max-width: 768px) 300px, 600px"
    loading="lazy"
    width="300"
    height="300"
    alt="<?= htmlspecialchars($element['NAME']) ?>"
>

Масова оптимізація існуючих зображень

Оптимізатор вже завантажених файлів запускається як агент Бітрікс або через CLI:

// Агент: обробляє по 100 файлів за запуск
$files = \Bitrix\Main\FileTable::getList([
    'filter' => ['CONTENT_TYPE' => ['image/jpeg', 'image/png']],
    'limit'  => 100,
    'offset' => (int)\Bitrix\Main\Config\Option::get('local.media', 'optimize_offset', 0),
])->fetchAll();

foreach ($files as $file) {
    $path = \Bitrix\Main\IO\Path::combine(
        \Bitrix\Main\Application::getDocumentRoot(),
        $file['SUBDIR'], $file['FILE_NAME']
    );
    if (file_exists($path)) {
        \Local\Media\ImageOptimizer::compress($path, $file['CONTENT_TYPE']);
    }
}

\Bitrix\Main\Config\Option::set('local.media', 'optimize_offset',
    (int)\Bitrix\Main\Config\Option::get('local.media', 'optimize_offset', 0) + 100
);

Терміни налаштування

Стиснення при завантаженні + WebP-конвертація в nginx + lazy loading в шаблонах — 1–2 робочих дні. Плюс масова оптимізація існуючого upload/ — додатково 4–8 годин на розробку агента та запуск.