Обновление статей про сжатие
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
Struchkov Mark 2024-09-06 00:21:20 +03:00
parent 25eb8ecf3d
commit d313510395
No known key found for this signature in database
GPG Key ID: A3F0AC3F0FA52F3C
2 changed files with 96 additions and 28 deletions

View File

@ -9,44 +9,58 @@ zero-link:
parents:
linked:
---
Следующий этап оптимизации изображений для сайта после [сжатия без потери качества](Сжатие%20изображений%20без%20потери%20качества.md) это преобразование всех изображений в формат WebP.
PNG и JPG являются хорошими форматами изображений, которые можно [сжать без потери качества](Сжатие%20изображений%20без%20потери%20качества.md). Однако, на сегодняшний день существует более современный формат WebP, который может показать еще более эффективные результаты при сжатии изображений, но с едва заметным ухудшением качества.
WebP - это формат сжатия изображений, разработанный компанией Google. Он использует современный алгоритм сжатия, который обеспечивает более эффективное сжатие, чем форматы JPEG и PNG, что может привести к быстрее загрузке веб-страниц и экономии интернет-трафика.
В [документации WebP](https://developers.google.com/speed/webp/docs/cwebp?hl=ru) перечислено множество параметров, которые повлияют на качество получаемого изображения. Вы можете провести экспериментальный подбор параметров онлайн на сайте [https://squoosh.app](https://squoosh.app/).
А вот и сам скрипт для преобразования в webp:
Я вы выбрал для себя следующий набор параметров:
```shell
#!/bin/bash
file=webp.flag
```bash
cwebp -mt -af -progress -m 6 -q 80 -pass 10 input.jpg -o output.webp
```
if [ -f "$file" ]; then
option="-newer $file"
fi
Это команда преобразует JPG файл `input.jpg` в файл изображения WebP с именем `output.webp`. Команда включает несколько опций, которые управляют процессом кодирования:
- `-mt` включает многопоточность, что может улучшить производительность  на многоядерных процессорах.
- `-af` включает автоматическую фильтрацию, которая применяет алгоритм фильтрации для повышения эффективности сжатия.
- `-progress` выводит показывает процент обработки файла.
- `-m 6` устанавливает максимальное количество сегментов, используемых в процессе кодирования, равным 6, что может повысить эффективность сжатия за счет увеличения времени кодирования.
- `-q 80` устанавливает коэффициент качества на `80`, который контролирует степень сжатия и влияет на визуальное качество выходного изображения.
- `-pass 10` устанавливает число проходов кодирования равным 10, что может повысить эффективность сжатия за счет увеличения времени кодирования.
find ./struchkov.dev/www/images/ -type f -iregex '.*\.\(jpg\|jpeg\|png\)' $option -exec sh -c '
webp_file="${1/\/images\//\/images\/webp\/}"
> [!WARNING]
> `-lossless` позволяет использовать сжатие без потерь. Но тогда ваше новое изображение может оказаться существенно тяжелее исходного.
Улучшим [скрипт сжатия изображений](Сжатие%20изображений%20без%20потери%20качества.md) и добавим преобразование в webp:
```bash
find ./images/comp -type f -iregex '.*\.\(jpg\|jpeg\|png\)' -not -iregex '.*no-comp\.\(jpg\|jpeg\|png\)' $option -exec sh -c '
webp_file="${1/\/images\/comp\//\/images\/webp\/}"
webp_dir="$(dirname "$webp_file")"
mkdir -p "$webp_dir"
cwebp -mt -af -progress -m 6 -q 85 -pass 10 "$1" -o "${webp_file%.*}.webp"
cwebp -mt -af -progress -m 6 -q 75 -pass 10 "$1" -o "${webp_file%.*}.webp"
' _ {} \;
touch "$file"
echo "$(date)" > "$file"
```
Также как и в первом скрипте, я использую файл-флаг, чтобы не преобразовывать файлы, которые уже преобразовывались.
Далее я беру папку `/struchkov.dev/www/images/`, в которой лежат исходные изображения и создаю новую папку `/struchkov.dev/www/images/webp`. Внутри папки `webp` структура папок и файлов такая же, как и в папке `images`. Только формат у файлов `.webp`.
За преобразование отвечает команда `cwebp`. Эта утилита сжимает изображения, но с потерями в качестве. Я подобрал оптимальные параметры сжатия, чтобы потеря качества была не заметна, но при этом изображения занимали меньше места.
```shell
cwebp -mt -af -progress -m 6 -q 85 -pass 10 "$1" -o "${webp_file%.*}.webp"
```
Подробнее об этих и других параметрах можно [почитать в документации](https://developers.google.com/speed/webp/docs/cwebp?hl=ru).
Мы берем сжатые изображения из папки `comp` и преобразуем их в WebP, складывая в отдельную папку `webp`. Если вы захотите использовать другие параметры сжатия, вы всегда сможете пересоздать изображения с новыми параметрами.
## Тесты преобразования
Продолжим наши эксперименты со сжатием. Теперь сожмем наши файл размером в 2,7 мб и 2.2 в формат WebP с разными параметрами качества:
- -q 90: Размер 325 кб.
- -q 85: Размер 267 кб.
- -q 80: Размер 229 кб.
- -q 75: Размер 200 кб.
- -q 70: Размер 191 кб.
- -q 60: Размер 176 кб.
- -q 50: Размер 163 кб.
- -q 40: Размер 147 кб.
- -q 30: Размер 129 кб.
- -q 20: Размер 115 кб.
- -q 10: Размер 90 кб.
- -q 1: Размер 70 кб. Для экстренных случаев. Например, вы заблудились в лесу и надо отправить фото по спутниковой сети 😅
## Nginx
Теперь сделаем так, чтобы при запросе jpg/png изображения отдавался аналогичный webp файл. Для этого в конфигурацию nginx добавляем:
Теперь мы научим nginx при запросе изображений сначала пытаться найти WebP файл, и только потом отдавать сжатый PNG/JPG, а если и сжатого нет, то отдавать обычный файл.
Для этого напишем следующий `location`:
```nginx
location ~* ^(/blog/ru/content/images/)(.+)\.(png|jpe?g)$ {
@ -58,4 +72,9 @@ location ~* ^(/blog/ru/content/images/)(.+)\.(png|jpe?g)$ {
}
```
`try_files` сначала попытается достать webp изображение, если его нет, то возьмет основной изобращение.
Данный `location` обрабатывает все запросы к адресам, которые начинаются с `/images/`, за которым следует любое количество символов, затем точка, а затем формат файла png/jpeg/jpg.
Для запросов, соответствующих этому шаблону, выполняются следующие действия:
- Директива `alias` указывает путь к локальной директории, из которой будут отдаваться файлы. В данном случае путь к директории `/images`.
- Директивы `set` назначают переменные, которые будут использоваться в последующих директивах. Переменная `$webp_image_subdir` устанавливается в `/webp/`, а переменная `$basename` устанавливается в захваченную подстроку шаблона регулярного выражения (т.е. имя файла без расширения).
- Директива `try_files` пытается отдать Webp-версию запрошенного файла изображения, добавляя к переменным `$webp_image_subdir` и `$basename` суффикс `.webp`. Если NGINX сможет найти Webp-версию запрашиваемого файла изображения, он отдаст его. Если он не может найти WebP-версию, то отдаст сжатый JPG/PNG, если и сжатого файла не будет, то отдаст не сжатое.

View File

@ -58,6 +58,55 @@ echo "$(date)" > $file
Для файлов JPEG используется `jpegoptim` для их оптимизации со сжатием без потерь (`--all-progressive --strip-all`).
После оптимизации всех подходящих изображений сценарий пересоздает файл `comp.flag`. Это гарантирует, что скрипт будет оптимизировать только те файлы, которые были изменены с момента последнего запуска.
## Тесты на сжатие
Возьмем два одинаковых изображения (3456 x 2234): одно форматом jpg и размером 2.2 мб, второе форматом png и размером 2,7 мб.
Запускаем скрипт и смотрим на результат сжатия.
```bash
** Processing: ./images/comp/image-two.png
3456x2234 pixels, 4x8 bits/pixel, RGB+alpha
Input IDAT size = 2664231 bytes
Input file size = 2666952 bytes
Trying:
zc = 9 zm = 9 zs = 0 f = 0 IDAT size = 2374591
zc = 9 zm = 8 zs = 0 f = 0 IDAT size = 2368803
zc = 9 zm = 9 zs = 0 f = 1 IDAT size = 2142264
zc = 9 zm = 8 zs = 0 f = 1 IDAT size = 2137390
zc = 9 zm = 9 zs = 1 f = 1 IDAT size = 2134232
zc = 9 zm = 8 zs = 1 f = 1 IDAT size = 2128765
zc = 9 zm = 9 zs = 0 f = 4 IDAT size = 2074935
zc = 9 zm = 8 zs = 0 f = 4 IDAT size = 2071117
zc = 9 zm = 9 zs = 1 f = 4 IDAT size = 2055799
zc = 9 zm = 8 zs = 1 f = 4 IDAT size = 2054390
zc = 9 zm = 9 zs = 0 f = 5 IDAT size = 2046026
zc = 9 zm = 8 zs = 0 f = 5 IDAT size = 2040193
zc = 9 zm = 9 zs = 1 f = 5 IDAT size = 2031130
zc = 9 zm = 8 zs = 1 f = 5 IDAT size = 2024568
Selecting parameters:
zc = 9 zm = 8 zs = 1 f = 5 IDAT size = 2024568
Output IDAT size = 2024568 bytes (639663 bytes decrease)
Output file size = 2025345 bytes (641607 bytes = 24.06% decrease)
2025345 2025345 100% ./images/comp/image-two.png (Bigger 2208631)
2025345 2025345 100%
Warning: versions are different between png.h and png.c
png.h version: 1.6.34
png.c version: 1.6.37
Recompressing IDAT chunks in ./images/comp/image-two.png
Total length of data found in critical chunks = 2024625
Best pngcrush method = 10 (ws 15 fm 6 zl 9 zs 1) = 2055326
CPU time decode 1.074758, encode 16.759768, other 0.018592, total 17.899076 sec
./images/comp/image-one.jpg 3456x2234 24bit N Exif XMP JFIF [OK] 2158567 --> 1947377 bytes (9.78%), optimized.
```
В результате мы смогли сжать png до 2.1 мб, а jpg до 1.9 мб. При этом сохранив исходный размер изображения и без потерь качества.
> [!NOTE]
> Лучшее, на мой взгляд, приложение для сжатия jpg это JPEGmini Pro. Имеет версию cli для серверов. Но к сожалению оно платное. Его результат сжатия 2.2 мб —> 959 кб.
## Дополнительные материалы
- [Преобразование изображений в Webp](Преобразование%20изображений%20в%20Webp.md)