Конвертация изображений PNG в JPG - это довольно тривиальный процесс, который можно выполнить сотней различных способов. Но что если изображений 20 000, и они разбросаны по папкам? В таком случае придётся немного напрячься и сконструировать команды для автоматической конвертации.
Начальные условия: 20 000 файлов PNG изображений, которые разбросаны по папкам и часть из них имеют исполинские размеры 5 000 на 5 000 пикселей.
Задача: конвертировать все файлы PNG в JPG с качеством 70% и уменьшить изображения до 1 500 пикселей, если они больше этого значения по ширине или высоте.
Инструменты: терминал на ПК с Linux (пробовал на Mint и CentOS) и установленным пакетом ImageMagic и jpegoptim. Первым пакетом будем изменять размеры и преобразовывать PNG в JPG, а вторым ухудшать качество и удалять метаданные.
Начинаем решать задачку. Сначала перейдём в папку, выше которой по дереву находятся все изображения. Для этого воспользуемся командой cd (укажите свой путь):
cd /путь/к/папке/с/изображениями/
Мы перешли в родительскую папку, внутри которой лежат все изображения. Теперь выполняем следующую команду:
find . -name "*.png" -exec mogrify -background white -flatten -format jpg {} \; -exec rm -v {} \;
Эта команда делает сразу несколько действий:
- find . -name "*.png" -exec mogrify ... {} - находит все файлы с расширением png и благодаря ключу exec передаёт пути этих файлов {} на вход в команду mogrify.
- mogrify -background white -flatten -format jpg {} - эта команда изменяет формат изображения по адресу {}, который получен от функции поиска. Параметр "background white" говорит о том, что если в PNG будет использоваться прозрачные пиксели, то они будут заменены на белые (без ключа "flatten" не работает). Ключ "format jpg" говорит о том, что надо изменить формат файла на jpg.
- -exec rm -v {} \; - эта команда удаляет файл png. Она нужна, ведь mogrify при изменении формата не удаляет файл исходник. Поэтому если не сделать это самостоятельно, то рядом с PNG файлами просто появятся JPG копии.
Запускаем команду, ждём окончания. По мере выполнения команды можно увидеть надписи "файл ***.png удалён". В конце у нас останутся только JPG файлы во всех папках.
Теперь необходимо изменить размер всех файлов, ширина или высота которых больше 5 000 пикселей. Так как подобная задача по конвертации изображений часто используется для веб, то выберем более адекватные значения. К примеру, уменьшим все изображения до ширины или высоты в 1500 пикселей, если они больше этого значения. Для этого выполним команду:
find . -name "*.jpg" -exec echo "'{}'" \; | xargs identify -format '%w %h %i\n' | awk '$1 > 1000 || $2 > 1000 {sub(/^[^ ]* [^ ]* /, ""); print}' | tr '\n' '\0' | xargs -0 mogrify -resize 1000x1000
К сожалению, mogrify изменяет размеры всех картинок без разбора. То есть если ему попадётся файл с маленькой картинкой 100 на 100 пикселей, то он увеличит её до требуемого значения. Поэтому нам нужно, чтобы в mogrify попадали только большие картинки, которые превышают 1500 пикселей. Для этого пришлось воспользоваться утилитой identify, которая определяет ширину и высоту картинки. Команда самостоятельно решает, передавать ли в mogrify это изображение или нет. Разберём подробнее всю команду:
- find . -name "*.jpg" -exec echo "'{}'" \; - функция поиска изображений в формате jpg и выдачи пути к нему {} в команду echo
- | xargs identify -format '%w %h %i\n' - конвейер "|" (вертикальная черта) и xargs передаёт вывод предыдущей команды в утилиту identify, которая анализирует изображение и печатает ширину "%w", высоту "%h" и путь к файлу "%i"
- | awk '$1 > 1500 || $2 > 1500 {sub(/^[^ ]* [^ ]* /, ""); print}' - сравнивает ширину и высоту со значением 1500. Если какое-либо значение превышает это, то удаляет размеры из строки, оставляя путь к файлу и печатает его
- | tr '\n' '\0' - обрезает нулевой бит и перенос строки, подготавливая для передачи на вход в mogrify
- | xargs -0 mogrify -resize 1500x1500 - изменяет размер изображения
Обратите внимание, что при выполнении команды не происходит никакого вывода в терминал.
После завершения изменения размеров остаётся только изменить качество изображений. Для этого воспльзуемся пакетом jpegoptim:
find . -name "*.jpg" -exec jpegoptim {} --strip-all --all-progressive --max=70 \;
Логика команды похожа на все предыдущие:
- find . -name "*.jpg" -exec jpegoptim {}... - находим путь к файлу jpg (путь находится в {}), отправляем этот путь на вход в jpegoptim
- jpegoptim {} --strip-all --all-progressive --max=70 \; - используем ключ "strip-all" для удаления метаданных изображений, чтобы уменьшить размер файлов. Ключ "max=70" означает, что ограничиваем качество JPG на 70%. Ключ "--all-progressive" означает сделать прогрессивное изображение, которое в отличии от простого загружается не сверху вниз, а сразу полностью, но качество изображения зависит от степени загрузки (только начали загружать - плохое качество, а загрузили полностью - отличное).
Зачем конвертировать PNG в JPG
После преобразования файлов из PNG в JPG их размер уменьшается в десятки раз. А после уменьшения качества JPG до 70% размер файлов уменьшается ещё на 30 - 80 процентов без видимого ухудшения картинки.
Из жизни
Как уже писал ранее, работаю в хостинге MouseDC.ru. Поэтому, зная статистику, скажу, что большинство владельцев сайтов не понимают, что чем меньше "весит" картинка на сайте, тем быстрее она загружается посетителю сайта. А чем быстрее посетитель увидит её, тем меньше вероятность, что он уйдёт с сайта.
Один клиент на хостинге загружал изображения только в формате PNG в свой интернет магазин. Причём некоторые файлы изображений имели размер 10 мегабайт и разрешение больше 5 тысяч пикселей в ширину и высоту. В итоге клиент забил такими PNG все свои 20 гигабайт диска виртуального хостинга и обратился к техподдержке. После конвертации всех файлов сайт начал занимать меньше 4 гигабайт. Так получилось освободить почти 17 гигабайт места хостинга без большой боли... и ещё пришлось написать SQL запрос для изменения путей к файлом в базе данных, но это уже тема для другой статьи...
Добрый день!
Подскажите, пожалуйста, если задачу немного модифицировать и изложить так:
==есть условные 500 файлов jpg в одной папке; требуется конвертировать их в tiff, а затем - в один, многостраничный PDF. ==
Можно ли это (и, если да, то как) сделать средствами Linux?
Заранее благодарен.
Если правильно помню, для этого можно использовать"convert" из пакета imagemagick. Сначала установите его:
apt install imagemagick
А затем для конвертации надо выполнить примерно такую команду:
convert файл_исходный.jpg файл_конечный.tif
А для сбора нескольких jpg один PDF сделать так:
convert 1.jpg 2.jpg 3.jpg конечный_файл.pdf
* стоит уточнить синтаксис и порядок аргументов в документации imagemagick
Спасибо!
Установлю, буду изучать 🙂