digital-garden/dev/snippet/Сжатие изображений без потери качества.md
Struchkov Mark ad35bf983f
All checks were successful
continuous-integration/drone/push Build is passing
Исправление даты
2024-09-08 00:56:18 +03:00

111 lines
7.5 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
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)