Struchkov Mark
ad35bf983f
All checks were successful
continuous-integration/drone/push Build is passing
111 lines
7.5 KiB
Markdown
111 lines
7.5 KiB
Markdown
---
|
||
tags:
|
||
- maturity/🌱
|
||
date: 2023-11-20
|
||
zero-link:
|
||
- "[[../../meta/zero/00 Снипеты на bash|00 Снипеты на bash]]"
|
||
parents:
|
||
linked:
|
||
---
|
||
Размер изображений составляет существенную часть от размера страницы сайта. Поэтому часто я сжимаю изображения на своих сайтах. В этой заметке рассказываю какими способами я это делаю.
|
||
|
||
```shell
|
||
#!/bin/bash
|
||
file=comp.flag
|
||
|
||
if [ -f "$file" ]; then
|
||
option="-newer $file"
|
||
fi
|
||
|
||
find ./images/ -type f -not -path "./images/comp/*" ! -name "*-no-comp.*" $option -iname "*.png" -exec sh -c '
|
||
png_file="${1/\/images\//\/images\/comp\/}"
|
||
png_dir="$(dirname "$png_file")"
|
||
mkdir -p "$png_dir"
|
||
cp "$1" "${png_file}"
|
||
optipng -o7 "${png_file}"
|
||
advpng -z4 "${png_file}"
|
||
pngcrush -rem gAMA -rem alla -rem cHRM -rem iCCP -rem sRGB -rem time -ow "${png_file}"
|
||
' _ {} \;
|
||
|
||
find ./images/ -type f-not -path "./images/comp/*" ! -name "*-no-comp.*" $option -iregex '.*\.\(jpg\|jpeg\)' -exec sh -c '
|
||
jpg_file="${1/\/images\//\/images\/comp\/}"
|
||
jpg_dir="$(dirname "$jpg_file")"
|
||
mkdir -p "$jpg_dir"
|
||
cp "$1" "${jpg_file}"
|
||
jpegoptim --all-progressive "${jpg_file}"
|
||
' _ {} \;
|
||
|
||
touch $file
|
||
echo "$(date)" > $file
|
||
```
|
||
|
||
Этот скрипт сжимает изображения без потери качества. Он размещается рядом с каталогом `images`, в котором находятся ваши изображения. Разберемся, как он работает.
|
||
|
||
Сначала скрипт проверяет, существует ли в текущем каталоге файл `comp.flag`. Если файл существует, он устанавливает значение `-newer $file` в переменную `option`, которая будет использоваться в качестве фильтра для поиска только тех файлов, которые были изменены после даты создания файла `optimg.flag`. Если файл не существует, переменная `option` будет пустой.
|
||
|
||
Затем скрипт использует команду `find` для рекурсивного поиска файлов в каталоге `images` и его подкаталогах, которые:
|
||
- `-type f`. Являются обычными файлами.
|
||
- Имеют расширение имени файла `.png`, `.jpeg` или `.jpg`.
|
||
- `-not -path`_._ Не находятся в указанных каталогах_._ В данном случае это каталоги `./images/comp`. Мы будем складывать туда сжатые изображения, и мы не хотим заново по ним проходить поиском и сжимать снова.
|
||
- `! -name "-no-comp."`. Оставим возможность не сжимать изображение, если его имя заканчивается на `-no-comp`.
|
||
- Для каждого из этих файлов сценарий использует свою команду оптимизации.
|
||
|
||
Мы не будем затирать оригиналы изображений. Вместо этого мы создадим дополнительную папку `comp` в каталоге `images`, в которую и сложим преобразованные изображения. Создаваемая структура подкаталогов в `comp` будет повторять структуру подкатологов в `images`.
|
||
|
||
Для файлов PNG сначала используется `optipng` для сжатия с самым высоким уровнем оптимизации (`-o7`). Далее используем `advpng` для дальнейшего сжатия с уровнем сжатия 4 (`-z4`). И наконец `pngcrush` для удаления из файла определенных фрагментов, которые можно безопасно удалить для уменьшения размера файла.
|
||
|
||
Для файлов 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) |