mail@vecdev.ru

Уменьшение размера изображений в 1С-Битрикс через кеш. Метод CFile::ResizeImageGet.

Уменьшение размера изображений является, пожалуй, первым делом, которое нужно сделать для увеличения скорости загрузки сайта. Скорость загрузки сайта напрямую влияет на его позиции в поисковой системе. 1С Битрикс имеет встроенные инструменты для оптимизации изображений.

При использовании метода сжатия достаточно один раз загрузить страницу с ним, при этом сервер выполнит оптимизацию изображения в соответствии с заданными параметрами и сохранит его в кэш, чтобы в дальнейшем использовать кешированные изображения вместо необжатых файлов. 

Использование метода сжатия изображений

<?$renderImg = CFile::ResizeImageGet("ID_КАРТИНКИ", Array("width" => "НОВАЯ_ШИРИНА", "height" => "НОВАЯ ВЫСОТА"), BX_RESIZE_IMAGE_PROPORTIONAL, false); ?>
<img src="<?=$renderImg["src"]?>" alt="Описание картинки"/>

Объявляем переменную renderImg и передаем ей результат работы функции сжатия ResizeImageGet. В качестве параметров передаем функции ID картинки, массив с новыми размерами изображения и тип масштабирования.

Результатом работы функции будет готовая ссылка на кешированную версию исходного изображения, все что нам остается - вставить $renderImg["src"] (путь к картинке) в тег img (ниже будет несколько примеров использования).

Вместо "ID_КАРТИНКИ" может быть подставлено любое значение, например:

  • $arResult["PREVIEW_PICTURE"]
  • $arResult["DETAIL_PICTURE"]
  • $FILE = CFile::GetFileArray( $arResult["DISPLAY_PROPERTIES"]["КОД_СВОЙСТВА"]["VALUE"] );

Типы масштабирования

Лично я достаточно часто использую третий метод изменения размеров, он не обрезает картинку и почти никогда не портит её качество.

  • BX_RESIZE_IMAGE_EXACT - масштабирует в прямоугольник $arSize c сохранением пропорций, обрезая лишнее;
  • BX_RESIZE_IMAGE_PROPORTIONAL - масштабирует с сохранением пропорций, размер ограничивается $arSize;
  • BX_RESIZE_IMAGE_PROPORTIONAL_ALT - масштабирует с сохранением пропорций за ширину при этом принимается максимальное значение из высоты/ширины, размер ограничивается $arSize, улучшенная обработка вертикальных картинок.

Примеры использования


<?
//обрезаем картинку анонса новости
$renderImg = CFile::ResizeImageGet($arResult["PREVIEW_PICTURE"], Array("width" => 300, "height" => 200), BX_RESIZE_IMAGE_PROPORTIONAL_ALT, false); ?>
<img src="<?=$renderImg["src"]?>" alt="<?=$arResult["NAME"]?>"/>

<?
//обрезаем картинку свойства новости и вставляем её в background
$FILE = CFile::GetFileArray($arResult["DISPLAY_PROPERTIES"]["ATT_IMG"]["VALUE"]);
$renderImg = CFile::ResizeImageGet($FILE , Array("width" => 300, "height" => 200), BX_RESIZE_IMAGE_PROPORTIONAL_ALT, false); ?>
<div style="background: url('<?=$renderImg["src"]?>')"></div>

 

В итоге уменьшенные картинки попадут в папку /upload/resize_cache/путь и при повторных вызовах метод ResizeImageGet будет сразу возвращать путь к уменьшенной версии изображения.

Для достижения еще большей скорости загрузки можно сконвертировать все изображения (в том числе и закешированные уменьшенные версии) в формат WebP, о том как это сделать читайте в нашей статье.

Сжатие картинок прямо внутри статьи по его SRC

Отвечая на вопрос в комментариях "Подскажите, как обжать картинки по ссылке. Например у меня есть статья, где я использую теги <img src"">. Битрикс не дает такой возможности из коробки...", дополняю статью.

Есть решение даже поинтересней. Сделать, помимо вывода сжатой картинки взамен обычной, возможность открытия полноценной при нажатии, для этого необходимо подключить к сайту fanxyBox3 (лежит в открытом доступе, если надо скину ссылку на тот, который я использую).

Важно! Если вы не хотите (по каким-то причинам) оборачивать картинку в FancyBox, то нужно ей добавить класс not_resize. Это учтено в функции resizeImageCallback.


// Функция изменения размера встроенных изображений в тексте
function resizeInlineImages($detailText) {
    if (CModule::IncludeModule('main')) {
        // Если модуль 'main' подключен, то производим замену встроенных изображений в тексте
        $detailText = preg_replace_callback('/(<img[^>]+src="([^"]+)"[^>]*>)/i', 'resizeImageCallback', $detailText);
    }
    return $detailText; // Возвращаем обработанный текст
}

// Функция поиска ID файла по его пути в БД
function getFileIdBySrc($strFilename){
    $strUploadDir = '/'.\Bitrix\Main\Config\Option::get('main', 'upload_dir').'/'; // Получаем директорию для загрузки файлов из настроек Битрикса
    $strFile = substr($strFilename, strlen($strUploadDir)); // Обрезаем путь до файла, чтобы получить относительный путь
    $connection = \Bitrix\Main\Application::getConnection(); // Получаем объект соединения с БД от Битрикса
    $sqlHelper = $connection->getSqlHelper(); // Получаем помощника SQL для экранирования переменных (защита от SQL-инъекций)
    $strFile = $sqlHelper->forSql($strFile); // Экранируем переменную для безопасного включения в SQL-запрос
    $strSql = "SELECT ID FROM b_file WHERE CONCAT(SUBDIR, '/', FILE_NAME) = '{$strFile}'"; // Формируем SQL запрос. Теперь он безопасен от SQL-инъекций
    return $connection->query($strSql)->fetch()['ID']; // Выполняем запрос и возвращаем ID файла
}

// Функция обработки встроенных изображений в тексте с целью изменения их размера и обертывания в тег FancyBox
function resizeImageCallback($matches) {
    $imageSrc = $matches[2]; // Получаем путь к изображению из совпадения
    $fileID = getFileIdBySrc($imageSrc); // Получаем ID файла по его пути в БД
    if ($fileID) {
        // Если файл найден, то выполняем изменение его размера
        $resizedImage = CFile::ResizeImageGet($fileID, array('width' => 600, 'height' => 400), BX_RESIZE_IMAGE_PROPORTIONAL, true);
        if ($resizedImage && isset($resizedImage['src'])) {
            // Если удалось изменить размер файла, то заменяем исходный путь на новый и формируем тег
            $resizedImageTag = str_replace($imageSrc, $resizedImage['src'], $matches[1]);
            $itemClass = 'not_resize';
            if (str_contains($matches[1], $itemClass)) {
                // Если изображение имеет класс 'not_resize', то возвращаем его без изменений
                return $resizedImageTag;
            } else {
                // Иначе оборачиваем изображение в тег FancyBox
                return '<a class="image-block-contain" href="' . $imageSrc . '" data-fancybox="cd__images" rel="nofollow">' . $resizedImageTag . '</a>';
            }
        } else {
            // Если не удалось изменить размер файла, то возвращаем исходное изображение без изменений
            return $matches[1];
        }
    }
}

// использование функций:
$resizedDetailText = resizeInlineImages($arResult['DETAIL_TEXT']);

Как работает код сжатия изображений по их адресу

1. Функция resizeInlineImages($detailText) принимает детальное описание новости $arResult['DETAIL_TEXT'], которое содержит HTML-код. Затем с помощью регулярного выражения preg_replace_callback находятся все теги IMG в тексте, и для каждого изображения вызывается функция resizeImageCallback.

2. Функция resizeImageCallback($matches) вызывается для каждого тега IMG в тексте. Она принимает массив $matches, который содержит совпадения из регулярного выражения для тега IMG. Сначала функция получает путь к изображению из совпадения $matches[2]. Затем вызывается функция getFileIdBySrc, чтобы получить ID файла по его пути в базе данных. Если файл найден, то производится изменение размера изображения с помощью функции CFile::ResizeImageGet, чтобы получить уменьшенное изображение с заданными параметрами. Затем исходный путь к изображению заменяется на новый путь к уменьшенному изображению, и если изображение не имеет класса 'not_resize', оно оборачивается в тег FancyBox. Если изменение размера изображения не удалось или файл не найден в базе данных, то возвращается исходный тег IMG без изменений.

3. Функция getFileIdBySrc($strFilename) принимает путь к файлу по его SRC. Сначала она получает директорию для загрузки файлов из настроек Битрикса (папка upload по умолчанию). Затем она создает объект соединения с базой данных и получает помощника SQL для безопасной обработки переменных. Далее формируется SQL-запрос для поиска ID файла по его пути в базе данных, и запрос выполняется с помощью метода query объекта соединения. Функция возвращает ID файла, если он найден.

Частный разработчик сайтов Vector Dev
Комментарии