Site icon 8HOST.COM

Создание и использование изображений WebP для ускорения сайта

WebP — открытый формат сжатия изображений, разработанный Google в 2010 году на основе VP8. За годы его существования количество сайтов и приложений с использованием формата WebP значительно выросло. Оригинальный формат WebP поддерживают браузеры Google Chrome и Opera, на которые приходится около 74% всего трафика. Если на сайтах используются изображения WebP, пользователи могут получать доступ к ним гораздо быстрее. Также WebP планируется реализовать в Firefox.

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

В этом мануале вы научитесь использовать инструмент командной строки cwebp и преобразовывать изображения в WebP путем создания сценариев. Затем мы покажем, как использовать изображения в формате WebP на своем сайте.

Требования

WebP работает независимо от дистрибутива. В этом мануале мы покажем, как использовать WebP в Ubuntu 16.04 и CentOS 7. Для работы вам понадобится:

1: Установка cwebp и подготовка каталога

Для начала нужно установить программное обеспечение для преобразования изображений и создать каталоги с тестовыми изображениями.

В Ubuntu 16.04 можно установить cwebp, утилиту для сжатия изображений в .webp. Для этого введите:

sudo apt-get update
sudo apt-get install webp

В CentOS 7 введите эту команду:

sudo yum install libwebp-tools

Чтобы создать каталог с изображениями по имени webp в корневом каталоге Apache (/var/www/html), введите:

sudo mkdir /var/www/html/webp

Передайте права на каталог пользователю sudo (здесь мы условно назовем его 8host):

sudo chown 8host: /var/www/html/webp

Теперь для тестирования можно скачать с помощью wget бесплатные изображения JPEG и PNG. Инструмент wget в Ubuntu 16.04 установлен по умолчанию; в CentOS 7 его можно установить так:

sudo yum install wget

Загрузите картинки для тестирования:

wget -c "https://upload.wikimedia.org/wikipedia/commons/2/24/Junonia_orithya-Thekkady-2016-12-03-001.jpg?download" -O /var/www/html/webp/image1.jpg
wget -c "https://upload.wikimedia.org/wikipedia/commons/5/54/Mycalesis_junonia-Thekkady.jpg" -O /var/www/html/webp/image2.jpg
wget -c "https://cdn.pixabay.com/photo/2017/07/18/15/39/dental-care-2516133_640.png" -O /var/www/html/webp/logo.png

Примечание: Эти изображения можно использовать и распространять по лицензиям Attribution-ShareAlike license и Public Domain Dedication.

Большую часть работы мы будем выполнять в каталоге /var/www/html/webp. Перейдите в него:

cd /var/www/html/webp

Теперь у нас есть всё, чтобы начать преобразование изображений.

2: Сжатие изображений с помощью cwebp

Чтобы поместить на сайт изображения .webp, нужно сначала преобразовать наши тестовые изображения в формат .webp. Для этого мы используем cwebp. Общий синтаксис команды выглядит так:

cwebp image.jpg -o image.webp

Флаг -o указывает путь к файлу WebP.

Поскольку вы находитесь в каталоге /var/www/html/webp, команды для преобразования изображений image1.jpg в image1.webp и image2.jpg​​​ в ​​​image2.webp будут выглядеть так​​​​:

cwebp -q 100 image1.jpg -o image1.webp
cwebp -q 100 image2.jpg -o image2.webp

Если параметр -q (отвечающий за качество) имеет значение 100, при преобразовании сохраняется 100% качества изображения; если этот параметр не указан, используется значение по умолчанию 75.

Проверьте размер изображений JPEG и WebP, используя ls. Флаг -l показывает список в длинном формате, что включает размер файла, а флаг -h выводит результат в удобочитаемом формате:

ls -lh image1.jpg image1.webp image2.jpg image2.webp
-rw-r--r-- 1 8host 8host 7.4M Oct 28 23:36 image1.jpg
-rw-r--r-- 1 8host 8host 3.9M Feb 18 16:46 image1.webp
-rw-r--r-- 1 8host 8host  16M Dec 18  2016 image2.jpg
-rw-r--r-- 1 8host 8host 7.0M Feb 18 16:59 image2.webp

Вывод команды ls показывает, что размер image1.jpg составляет 7,4 Mбайт, а размер image1.webp – уже 3,9 Mбайт. То же касается и image2.jpg​​​​​​ (16 Mб) и image2.webp (7 Mб). Как видите, файлы webp почти в два раза меньше исходных.

Для сохранения полных исходных данных изображений при сжатии можно использовать вместо -q флаг -lossless. Это лучший способ сохранить качество файлов PNG. Для преобразования загруженного ранее файла PNG введите:

cwebp -lossless logo.png -o logo.webp

Следующая команда говорит, что размер файла WebP без потерь (60 Кб) все же почти в два раза меньше размера исходного файла PNG (116 Кб):

ls -lh logo.png logo.webp
-rw-r--r-- 1 8host 8host 116K Jul 18  2017 logo.png
-rw-r--r-- 1 8host 8host  60K Feb 18 16:42 logo.webp

Преобразованные изображения WebP в каталоге /var/www/html/webp почти вполовину меньше исходных файлов JPEG и PNG. В целом же степени сжатия могут отличаться в зависимости от разных факторов: уровень сжатия исходного файла, формат файла, тип преобразования (с потерями или без), процент качества и ОС. При преобразовании большего количества изображений вы можете увидеть различия коэффициентов, связанных с этими факторами.

3: Преобразование изображений JPEG и PNG в каталоге

Скрипт может сильно упростить процесс преобразования, поскольку не требует ручного вмешательства. Давайте напишем скрипт, который будет находить файлы JPEG и преобразовывать их в формат WebP, сохраняя 90% качества, а файлы PNG будет преобразовывать в WebP без потерь.

Откройте текстовый редактор и создайте скрипт webp-convert.sh в домашнем каталоге пользователя:

nano ~/webp-convert.sh

Первая строка скрипта выглядит так:

find $1 -type f -and \( -iname "*.jpg" -o -iname "*.jpeg" \)

Она состоит из таких компонентов:

Вторая строка скрипта будет отвечать за преобразование изображения в WebP с помощью параметра -exec. Общий синтаксис: -exec command {} \;​​. Вместо {} указываются все файлы, которые обрабатывает команда, а символ ; определяет, где заканчивается команда:

find $1 -type f -and \( -iname "*.jpg" -o -iname "*.jpeg" \) \
-exec bash -c 'commands' {} \;

В данном случае параметр -exec требует несколько команд для поиска и преобразования изображений:

Сценарий внутри ‘commands’ будет выполнять такие функции:

Этот небольшой скрипт выглядит так:

...
webp_path=$(sed 's/\.[^.]*$/.webp/' <<< "$0");
if [ ! -f "$webp_path" ]; then
cwebp -quiet -q 90 "$0" -o "$webp_path";
fi;

Этот скрипт включает в себя следующие элементы:

Учитывая небольшой скрипт вместо заполнителя ‘commands’, полный текст скрипта для преобразования изображений JPEG выглядит следующим образом:

# converting JPEG images
find $1 -type f -and \( -iname "*.jpg" -o -iname "*.jpeg" \) \
-exec bash -c '
webp_path=$(sed 's/\.[^.]*$/.webp/' <<< "$0");
if [ ! -f "$webp_path" ]; then
cwebp -quiet -q 90 "$0" -o "$webp_path";
fi;' {} \;

Для преобразования PNG в WebP мы будем использовать тот же подход, но с парой отличий: шаблон -iname  в команде find будет “*.png”, а команда преобразования использует параметр -lossless вместо -q.

Итоговый скрипт выглядит так:

#!/bin/bash
# converting JPEG images
find $1 -type f -and \( -iname "*.jpg" -o -iname "*.jpeg" \) \
-exec bash -c '
webp_path=$(sed 's/\.[^.]*$/.webp/' <<< "$0");
if [ ! -f "$webp_path" ]; then
cwebp -quiet -q 90 "$0" -o "$webp_path";
fi;' {} \;
# converting PNG images
find $1 -type f -and -iname "*.png" \
-exec bash -c '
webp_path=$(sed 's/\.[^.]*$/.webp/' <<< "$0");
if [ ! -f "$webp_path" ]; then
cwebp -quiet -lossless "$0" -o "$webp_path";
fi;' {} \;

Сохраните и закройте файл.

Теперь давайте проверим скрипт webp-convert.sh в деле на файлах из /var/www/html/webp. Сделайте файл скрипта исполняемым:

chmod a+x ~/webp-convert.sh

Запустите скрипт в каталоге с изображениями:

./webp-convert.sh /var/www/html/webp

Как видите, ничего не случилось ­– ведь ранее мы уже преобразовали эти изображения. Скрипт webp-convert преобразует файлы, если вы добавите в каталог новые файлы, у которых нет версии .webp, или если вы удалите версии .webp. Чтобы посмотреть, как это работает, давайте удалим все файлы .webp, которые мы создали раньше.

rm /var/www/html/webp/*.webp

После этого снова запустите скрипт:

./webp-convert.sh /var/www/html/webp

Команда ls подтвердит, что скрипт успешно выполнил свою работу:

ls -lh /var/www/html/webp
-rw-r--r-- 1 8host 8host 7.4M Oct 28 23:36 image1.jpg
-rw-r--r-- 1 8host 8host 3.9M Feb 18 16:46 image1.webp
-rw-r--r-- 1 8host 8host  16M Dec 18  2016 image2.jpg
-rw-r--r-- 1 8host 8host 7.0M Feb 18 16:59 image2.webp
-rw-r--r-- 1 8host 8host 116K Jul 18  2017 logo.png
-rw-r--r-- 1 8host 8host  60K Feb 18 16:42 logo.webp

4: Просмотр файлов изображений в каталоге

Теперь давайте создадим новый скрипт для просмотра изменений в каталоге и автоматического преобразования новых изображений.

Скрипт, который будет следить за каталогом изображений, может решить некоторые проблемы скрипта webp-convert.sh, которые могли возникнуть  в ходе его написания. Например, он не сможет узнать, переименовали ли мы изображение. Предположим, у вас есть изображение foo.jpg. Вы запускаете скрипт  webp-convert.sh, переименовываете файл в bar.jpg, а затем снова выполняете webp-convert.sh — в итоге у вас будут идентичные файлы с разными именами (foo.webp и bar.webp). Для решения этой проблемы давайте добавим новый скрипт с наблюдателями. Наблюдатели (или watchers) следят за конкретными файлами или каталогами и запускают команды в ответ на разные изменения.

Команда inotifywait настраивает наблюдатели (watchers) в скрипте. Эта команда входит в inotify-tools — пакет инструментов, который обеспечивает простой интерфейс подсистемы ядра inotify. Чтобы установить его в Ubuntu 16.04, введите:

sudo apt-get install inotify-tools

В CentOS 7 пакет ​​​inotify-tools можно найти в репозитории EPEL. Установите EPEL и пакет ​​​inotify-tools с помощью таких команд:

sudo yum install epel-release
sudo yum install inotify-tools

Затем создайте скрипт webp-watchers.sh в домашнем каталоге пользователя:

nano ~/webp-watchers.sh

Первая строка скрипта будет выглядеть так:

inotifywait -q -m -r --format '%e %w%f' -e close_write -e moved_from -e moved_to -e delete $1

Она включает следующие элементы:

Затем давайте добавим команду grep, чтобы определить, являются ли наши файлы изображениями JPEG или PNG. Параметр -i будет позволяет команде grep игнорировать регистр, -E включает расширенные регулярные выражения, а –line-buffered передает совпавшие строки в цикл while.

inotifywait -q -m -r --format '%e %w%f' -e close_write -e moved_from -e moved_to -e delete $1 | grep -i -E '\.(jpe?g|png)$' --line-buffered

Теперь мы создадим цикл while с командой read. Она будет обрабатывать событие, которое обнаружила команда inotifywait, и присваивать его переменной $operation, а путь файла — переменной $path:

...
| while read operation path; do
# commands
done;

Добавим этот цикл к остальному коду скрипта:

inotifywait -q -m -r --format '%e %w%f' -e close_write -e moved_from -e moved_to -e delete $1 \
| grep -i -E '\.(jpe?g|png)$' --line-buffered \
| while read operation path; do
# commands
done;

После проверки события циклом while команды внутри цикла сделают следующее (в зависимости от результата):

Внутри цикла есть три основных раздела. Переменная webp_path хранит путь к версии .webp  изображения:

...
webp_path="$(sed 's/\.[^.]*$/.webp/' <<< "$path")";

Затем скрипт проверяет, какое событие произошло:

...
if [ $operation = "MOVED_FROM" ] || [ $operation = "DELETE" ]; then
# commands to be executed if the file is moved or deleted
elif [ $operation = "CLOSE_WRITE,CLOSE" ] || [ $operation = "MOVED_TO" ]; then
# commands to be executed if a new file is created
fi;

Если файл был удален или перемещен, скрипт проверит, существует ли его версия .webp. Если да, он удалит ее с помощью rm:

if [ -f "$webp_path" ]; then
$(rm -f "$webp_path");
fi;

Сжатие новых файлов будет происходить следующим образом:

Давайте добавим в скрипт команды cwebp, которые будут выполнять эти действия:

...
if [ $(grep -i '\.png$' <<< "$path") ]; then
$(cwebp -quiet -lossless "$path" -o "$webp_path");
else      
$(cwebp -quiet -q 90 "$path" -o "$webp_path");
fi;

Полный код скрипта выглядит так:

#!/bin/bash
echo "Setting up watches.";
# watch for any created, moved, or deleted image files
inotifywait -q -m -r --format '%e %w%f' -e close_write -e moved_from -e moved_to -e delete $1 \
| grep -i -E '\.(jpe?g|png)$' --line-buffered \
| while read operation path; do
webp_path="$(sed 's/\.[^.]*$/.webp/' <<< "$path")";
if [ $operation = "MOVED_FROM" ] || [ $operation = "DELETE" ]; then # if the file is moved or deleted
if [ -f "$webp_path" ]; then
$(rm -f "$webp_path");
fi;
elif [ $operation = "CLOSE_WRITE,CLOSE" ] || [ $operation = "MOVED_TO" ]; then  # if new file is created
if [ $(grep -i '\.png$' <<< "$path") ]; then
$(cwebp -quiet -lossless "$path" -o "$webp_path");
else
$(cwebp -quiet -q 90 "$path" -o "$webp_path");
fi;
fi;
done;

Сохраните и закройте файл. Сделайте его исполняемым:

chmod a+x ~/webp-watchers.sh

Теперь давайте запустим этот скрипт в каталоге /var/www/html/webp в фоновом режиме, используя &. Также мы перенаправим стандартный вывод и стандартную ошибку в ~/output.log, чтобы эти данные хранились в легкодоступном месте:

./webp-watchers.sh /var/www/html/webp > output.log 2>&1 &

Ранее мы преобразовали файлы JPEG и PNG из каталога /var/www/html/webp в формат WebP, а также настроили наблюдатели для выполнения ряда действий в скрипте webp-watchers.sh. Теперь пора научиться использовать изображения WebP на сайте.

5: Обслуживание изображений WebP на сайте с помощью элементов HTML

Здесь вы узнаете, как показывать изображения WebP на вашем сайте с помощью HTML. На данный момент в каталоге /var/www/html/webp у вас есть версии .webp каждого тестового изображения JPEG и PNG . Мы можем отображать эти файлы в поддерживаемых браузерах с помощью элементов HTML5 (<picture>) или модуля mod_rewrite Apache. Здесь мы используем элементы HTML.

Элемент <picture> позволяет напрямую включить изображение в веб-страницы и задать несколько источников изображений. Если браузер поддерживает формат WebP, вместо оригинального файла он будет загружать версию .webp, что ускорит загрузку страниц. В целом  элемент <picture> широко поддерживается современными браузерами с поддержкой формата WebP.

Элемент <picture> – это контейнер с элементами <source> и <img>, указывающими на конкретные файлы. Если элемент <source> будет указывать на изображение .webp, браузер сможет его обработать. В противном случае браузер использует файл, заданный с помощью атрибута src в элементе <img>.

Давайте используем в элементе <source>. файл logo.png из каталога /var/www/html/webp, который мы преобразовали в logo.webp. Для отображения logo.webp в любом браузере, поддерживающем формат WebP, и logo.png в любом браузере, не поддерживающем WebP или элемент <picture>, можно использовать следующий код HTML.

Сначала создайте файл HTML в /var/www/html/webp/picture.html:

nano /var/www/html/webp/picture.html

Добавьте в него следующий код для отображения logo.webp с помощью элемента <picture>:

<picture>
<source srcset="logo.webp" type="image/webp">
<img src="logo.png" alt="Site Logo">
</picture>

Сохраните и закройте файл.

Для проверки перейдите в каталог http://your_server_ip/webp/picture.html. Вы должны увидеть свое изображение PNG.

Теперь давайте посмотрим, как автоматизировать этот процесс с помощью mod_rewrite.

6: Обслуживание изображений WebP с помощью mod_rewrite

Если вы хотите оптимизировать скорость загрузки сайта, но у вас очень много страниц или мало времени на редактирование HTML, вы можете использовать модуль mod_rewrite от Apache. Он позволяет автоматизировать процесс отображения файлов .webp в поддерживаемых браузерах.

Сначала создайте файл .htaccess в каталоге /var/www/html/webp с помощью следующей команды:

nano /var/www/html/webp/.htaccess

Директива ifModule проверяет, доступен ли модуль mod_rewrite; если он доступен, его можно активировать при помощи RewriteEngine On. Добавьте эти директивы в файл .htaccess:

<ifModule mod_rewrite.c>
RewriteEngine On
# further directives
</IfModule>

Веб-сервер сделает несколько проверок, чтобы определить, когда показывать файлы .webp пользователю. Когда браузер делает запрос, он включает в него заголовок, который указывает серверу, что именно может обрабатывать браузер. В случае с WebP браузер отправляет заголовок Accept, содержащий image/webp. Давайте проверим, отправляет ли браузер этот заголовок, с помощью директивы RewriteCond; она определяет критерии, которым нужно отвечать для выполнения правила RewriteRule:

...
RewriteCond %{HTTP_ACCEPT} image/webp

Необходимо отфильтровать все файлы, кроме изображений JPEG и PNG. Снова используйте RewriteCond, чтобы добавить регулярное выражение для соответствия запрошенной версии URI:

...
RewriteCond %{REQUEST_URI}  (?i)(.*)(\.jpe?g|\.png)$

Модификатор (?i) сделает выражение нечувствительным к регистру.

Чтобы проверить наличие версии .webp, снова используйте RewriteCond.

...
RewriteCond %{DOCUMENT_ROOT}%1.webp -f

Если все предыдущие условия выполнены, RewriteRule перенаправит запрошенный файл JPEG или PNG на соответствующий файл WebP. Обратите внимание, перенаправление происходит при помощи флага -R, а не перезаписи. Разница между перезаписью и перенаправлением заключается в том, что сервер будет направлять перезаписанный URI-адрес, не сообщая об этом браузеру. Например, URI-адрес будет показывать, что файл имеет расширение .png, но на самом деле это будет файл .webp. Добавьте RewriteRule в файл:

...
RewriteRule (?i)(.*)(\.jpe?g|\.png)$ %1\.webp [L,T=image/webp,R]

Теперь раздел mod_rewrite в файле .htaccess готов. Но что, если между вашим сервером и клиентом будет промежуточный сервер кэширования? Он может показать конечному пользователю неправильную версию файла. Именно поэтому стоит убедиться, что модуль mod_headers активирован, и отправить заголовок Vary: Accept. Заголовок Vary сообщает серверам кэширования (например, прокси-серверам), что тип контента документа варьируется в зависимости от возможностей браузера, запрашивающего этот документ. Ответ генерируется на основе заголовка Accept в запросе. Запрос с другим заголовком Accept получит другой ответ. Данный заголовок важен, поскольку не позволяет показывать кэшированные изображения WebP в неподдерживаемых браузерах:

...
<IfModule mod_headers.c>
Header append Vary Accept env=REDIRECT_accept
</IfModule>

Теперь в конце файла .htaccess задайте тип MIME изображений .webp как image/webp, используя директиву AddType. Это будет показывать изображения с правильным типом MIME:

...
AddType image/webp .webp

В итоге получится такой файл:

<ifModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_ACCEPT} image/webp
RewriteCond %{REQUEST_URI}  (?i)(.*)(\.jpe?g|\.png)$
RewriteCond %{DOCUMENT_ROOT}%1.webp -f
RewriteRule (?i)(.*)(\.jpe?g|\.png)$ %1\.webp [L,T=image/webp,R] </IfModule>
<IfModule mod_headers.c>

Header append Vary Accept env=REDIRECT_accept

</IfModule>
AddType image/webp .webp

Примечание: Этот файл .htaccess можно объединить с другим файлом .htaccess (при наличии такового). Если вы используете WordPress, вам следует скопировать этот файл .htaccess и вставить его в начало существующего файла.

Давайте на практике проверим, как это работает. Если вы следовали инструкциям в предыдущих разделах, у вас должны быть изображения logo.png и logo.webp в /var/www/html/webp. Сейчас мы используем простой элемент <img>, чтобы добавить изображение logo.png на страницу сайта. Создайте новый файл HTML:

nano /var/www/html/webp/img.html

Вставьте такой код:

<img src="logo.png" alt="Site Logo">

Сохраните и закройте файл.

При посещении страницы http://your_server_ip/webp/img.html в Chrome вы увидите, что изображение имеет формат .webp (чтобы убедиться в этом, откройте его в новой вкладке). В Firefox в автоматически получите версию .png.

Заключение

данном мануале мы рассмотрели основные методы работы с изображениями WebP. Вы узнали, как использовать инструмент cwebp для преобразования файлов, а также как показывать эти изображения пользователям: для этого есть два способа, элемент HTML5 <picture> и модуль Apache mod_rewrite.

Характеристики WebP и использование инструментов преобразования хорошо описаны в документации WebP.

Дополнительную информацию об использовании элемента <picture> вы найдете в документации по MDN.

Также вам может понадобиться документация mod_rewrite.