После очередной «просьбы» гугла в сервисе PageSpeed Insights использовать современные форматы изображений, я решил оптимизировать изображения на одном из сайтов на Битрикс, добавив вывод слайдов в формате WebP. Для решения данной задачи я выбрал вариант использования библиотеки GD, коим и хочу поделиться. Так как эта библиотека является расширением для PHP, необходимо было убедиться, подключена ли она. Создал в корне сайта простой файл php:
<pre> <?php var_dump(gd_info()); ?> </pre>
и получил массив с неутешительным ответом.
["WebP Support"]=> bool(false)
Сайт, о котором я веду речь, расположен на виртуальном хостинге, поэтому какие-либо действия с настройками сервера проводить нет возможности, только через тех. поддержку. Забегая вперед скажу, что мне очень повезло, так как после вопроса в саппорт хостинга Бегет, мне сказали, что есть возможность перенести данный аккаунт на сервер с подключенной библиотекой. Уточнили удобное время для переноса аккаунта и после окончания работ я увидел желанное true. На этом предысторию закончил, пишем функции и выводим изображения в формате WebP.
Для начала я написал функцию, местами подсмотрел :), для конвертирования изображений из png и jpg в webp. Где её размещать, дело лично разработчика, у меня в папку php_interface добавлена папка inc и в ней все мои функции, подключенные в init.php. На случай, если GD библиотека «слетит», сделал проверку. Функция очень проста, я в нее передаю два параметра, тип файла и путь:
$gd_info = gd_info(); if($gd_info['WebP Support'] === true): function convertImageWebp($file_type, $read_from_path) { $save_to_path = $read_from_path . '.webp'; $output = ''; $file = $read_from_path; if($file_type == 'image/png') { $image = imagecreatefrompng($file); } elseif($file_type == 'image/jpeg') { $image = imagecreatefromjpeg($file); } ob_start(); imagejpeg($image,NULL,100); $cont = ob_get_contents(); ob_end_clean(); imagedestroy($image); $content = imagecreatefromstring($cont); imagewebp($content,$save_to_path); imagedestroy($content); if(filesize ( $save_to_path ) > 0) { $output = str_replace($_SERVER["DOCUMENT_ROOT"], '', $save_to_path); } return $output; } endif;
Я использую так называемый «ресайз изображений на лету», поэтому дальнейшие манипуляции в файле result_modifier.php необходимого шаблона. На этом сайте изображения выводятся в теге picture с использованием медиа-запросов, поэтому режем на три размера, проверяем функцию, конвертируем. Пример взят из шаблона слайдера:
if($arResult['ITEMS']) { foreach ($arResult['ITEMS'] as $cell => $arItem) { $file = CFile::ResizeImageGet($arItem["DETAIL_PICTURE"]["ID"], Array("width" =>1920 , "height" => 1080),BX_RESIZE_IMAGE_EXACT, true); $file_1920_780 = CFile::ResizeImageGet($arItem["DETAIL_PICTURE"]["ID"], Array("width" =>1920 , "height" => 780),BX_RESIZE_IMAGE_EXACT, true); $file_996_560 = CFile::ResizeImageGet($arItem["DETAIL_PICTURE"]["ID"], Array("width" =>996 , "height" => 560),BX_RESIZE_IMAGE_EXACT, true); $file_600_338 = CFile::ResizeImageGet($arItem["DETAIL_PICTURE"]["ID"], Array("width" =>600 , "height" => 338),BX_RESIZE_IMAGE_EXACT, true); $arResult['ITEMS'][$cell]['DETAIL_PICTURE']['WIDTH'] = $file['width']; $arResult['ITEMS'][$cell]['DETAIL_PICTURE']['HEIGHT'] = $file['height']; $arResult['ITEMS'][$cell]['DETAIL_PICTURE']['SRC'] = $file['src']; $arResult['ITEMS'][$cell]['DETAIL_PICTURE']['1920_780']['SRC'] = $file_1920_780['src']; $arResult['ITEMS'][$cell]['DETAIL_PICTURE']['996_560']['SRC'] = $file_996_560['src']; $arResult['ITEMS'][$cell]['DETAIL_PICTURE']['600_338']['SRC'] = $file_600_338['src']; if (function_exists('convertImageWebp')) { $file_type = $arItem['DETAIL_PICTURE']['CONTENT_TYPE']; $img_webp_1920_780 = convertImageWebp($file_type, $_SERVER["DOCUMENT_ROOT"] . $file_1920_780['src']); $img_webp_996_560 = convertImageWebp($file_type, $_SERVER["DOCUMENT_ROOT"] . $file_996_560['src']); $img_webp_600_338 = convertImageWebp($file_type, $_SERVER["DOCUMENT_ROOT"] . $file_600_338['src']); $arResult['ITEMS'][$cell]['DETAIL_PICTURE']['1920_780']['SRC_WEBP'] = $img_webp_1920_780; $arResult['ITEMS'][$cell]['DETAIL_PICTURE']['996_560']['SRC_WEBP'] = $img_webp_996_560; $arResult['ITEMS'][$cell]['DETAIL_PICTURE']['600_338']['SRC_WEBP'] = $img_webp_600_338; } } }
Выводим:
<picture> <source srcset="<?=$arItem['DETAIL_PICTURE']['1920_780']['SRC_WEBP']?>" type="image/webp" media="(min-width: 996px)"> <source srcset="<?=$arItem['DETAIL_PICTURE']['1920_780']["SRC"]?>" media="(min-width: 996px)"> <source srcset="<?=$arItem['DETAIL_PICTURE']['996_560']['SRC_WEBP']?>" type="image/webp" media="(min-width: 600px)"> <source srcset="<?=$arItem['DETAIL_PICTURE']['996_560']["SRC"]?>" media="(min-width: 600px)"> <source srcset="<?=$arItem["DETAIL_PICTURE"]['600_338']["SRC_WEBP"]?>" type="image/webp"> <img src="<?=$arItem["DETAIL_PICTURE"]['600_338']["SRC"]?>" alt="<?=$arItem["NAME"]?>" alt="<?=$arItem["NAME"]?>"> </picture>
Ну а для тех, у кого нет возможности или желания писать код, существует простое решение, которое не требует навыков программирования.
Готовый модуль OptiPic CDN – простое решение проблемы «Используйте современные форматы изображений» согласно рекомендациям Google Pagespeed Insights.
Он автоматически конвертирует изображения в современный формат Webp (для браузеров, которые поддерживают webp). А для браузеров, которые не поддерживают webp, OptiPic оптимизирует (сжимает) старые форматы png и jpeg. Дополнительными преимуществами OptiPic CDN является то, что он кэширует изображения в соответствии с требованиями Google, ускоряет их загрузку в браузере, а также защищает авторство картинок через мета-теги EXIF и IPTC.
Видео инструкция по установке и настройке модуля OptiPic CDN для Битрикс
Не увидел кеширования, по идеи всякий раз при обращении будет обработка картинки, будет здорово, если будет добавленно кеширование и когда картинка обработается то сохранится путь к ней в кеше, и при следующем запросе не будет вновь задействована процессора мощь, а взято все из кеша.
А так спасибо за решение, перешел к Вам из твитера прочитал статью.
Доброго дня.
Пытаюсь реализовать конвертацию, но ничего не выходит.
Делаю все так же:
1 Вынес функцию в отдельный файл
2 В init.php прописал путь
3 В result_modifier шаблона подключил класс через use, скопировал ваш код
4 Для вывода так же использовал ваш код
Но ничего не выходит, конвертация не выполняется. Права доступа подходят, все должно выполняться, но не работает ни в какую.
Доброго дня, Артём! После Вашего комментария проверил работу функции на нескольких сайтах, всё ок 🙂 Не видя Вашего кода даже не знаю что подсказать. Напишите в личку, попробуем разобраться что не так. Ну и var_dump частенько спасает в таких случаях 🙂
Здравствуйте. Функция отлично работает, кроме картинок в png с прозрачным фоном — фон становится черным. Это можно как-то вылечить?
Здравствуйте, Роман! Чтобы конвертировать PNG в WebP с прозрачностью, нужно немного переписать функцию,
заменить:
на: