From d3135103957f35223c5c9509a0aaa8e9cba18a52 Mon Sep 17 00:00:00 2001 From: Struchkov Mark Date: Fri, 6 Sep 2024 00:21:20 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D1=81=D1=82=D0=B0=D1=82=D0=B5=D0=B9=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=20=D1=81=D0=B6=D0=B0=D1=82=D0=B8=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Преобразование изображений в Webp.md | 75 ++++++++++++------- .../Сжатие изображений без потери качества.md | 49 ++++++++++++ 2 files changed, 96 insertions(+), 28 deletions(-) diff --git a/dev/snippet/Преобразование изображений в Webp.md b/dev/snippet/Преобразование изображений в Webp.md index 3aa519f1..f10f6d91 100644 --- a/dev/snippet/Преобразование изображений в Webp.md +++ b/dev/snippet/Преобразование изображений в Webp.md @@ -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 изображение, если его нет, то возьмет основной изобращение. \ No newline at end of file +Данный `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, если и сжатого файла не будет, то отдаст не сжатое. \ No newline at end of file diff --git a/dev/snippet/Сжатие изображений без потери качества.md b/dev/snippet/Сжатие изображений без потери качества.md index 1e121b54..7e3742ca 100644 --- a/dev/snippet/Сжатие изображений без потери качества.md +++ b/dev/snippet/Сжатие изображений без потери качества.md @@ -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) \ No newline at end of file