Преобразование и оптимизация изображений из командной строки

Преобразование и оптимизация изображений из командной строки

От автора: изображения занимают до 50% от общего размера средней веб-страницы. И если изображения не оптимизированы, пользователи в конечном итоге загружают дополнительные байты. Когда они загружают дополнительные байты, сайту не только требуется гораздо больше времени для загрузки, но и пользователи используют больше данных. И то, и другое можно решить, по крайней мере частично, путем оптимизации изображений перед их загрузкой.

Исследователи во всем мире заняты разработкой новых форматов изображений, которые обладают высоким визуальным качеством, несмотря на меньший размер по сравнению с другими форматами, такими как PNG или JPG. Хотя эти новые форматы все еще находятся в разработке и, обычно, имеют ограниченную поддержку браузера, один из них, WebP, привлекает большое внимание. И хотя на самом деле они не относятся к тому же классу, что и растровые изображения, SVG — это еще один формат, который многие из нас использовали в последние годы из-за их изначально легкого веса.

Есть множество способов сделать изображения меньшего размера и оптимизировать их. В этом руководстве мы напишем сценарии bash, которые создают и оптимизируют изображения в различных форматах изображений, ориентируясь на наиболее распространенные форматы, включая JPG, PNG, WebP и SVG. Идея состоит в том, чтобы оптимизировать изображения, прежде чем мы их обслуживаем, чтобы пользователи получали максимально визуально потрясающий опыт без излишнего увеличения количества байтов.

Преобразование и оптимизация изображений из командной строки

Наш целевой каталог изображений

Преобразование и оптимизация изображений из командной строки

Наш каталог оптимизированных изображений

В этом репозитории GitHub есть все изображения, которые мы используем, и вы можете ими пользоваться.

Настройка

Прежде чем мы начнем, давайте рассмотрим все по порядку. Опять же, мы пишем сценарии Bash, поэтому мы будем делать это в командной строке. Вот команды для всех связей, которые нам нужны, чтобы начать оптимизацию изображений:

sudo apt-get update
sudo apt-get install imagemagick webp jpegoptim optipng
npm install -g svgexport svgo

Изначально нужно узнать, с чем мы работаем, прежде чем мы начнем их использовать:

ImageMagick: работает со всеми видами растровых изображений

webp оптимизирует файлы WebP

JPEGoptim оптимизирует файлы JPG / JPEG

OptiPNG оптимизирует файлы PNG

SVGO и svgexport — оптимизируют ресурсы SVG

Итак, у нас есть изображения в каталоге original-images из репозитория GitHub.

Примечание. Перед продолжением настоятельно рекомендуется сделать резервную копию изображений. Мы собираемся запустить программы, которые изменяют эти изображения, и хотя мы не планируем использовать оригиналы, одна неверная команда может изменить их необратимым образом. Так что сделайте резервную копию всего, что вы планируете использовать в реальном проекте.

Организуйте изображения

И так, мы настроили все технические нюансы. Но прежде чем мы приступим к оптимизации всего, нам следует немного упорядочить файлы. Давайте разделим их на разные подкаталоги в зависимости от их типа MIME. Фактически, мы можем создать новый bash, который сделает это за нас!

Следующий код создает сценарий с именем organize-images.sh:

#!/bin/bash input_dir="$1" if [[ -z "$input_dir" ]]; then echo "Please specify an input directory." exit 1
fi for img in $( find $input_dir -type f -iname "*" );
do # get the type of the image img_type=$(basename `file --mime-type -b $img`) # create a directory for the image type mkdir -p $img_type # move the image into its type directory rsync -a $img $img_type
done

Это может сбить с толку, если вы новичок в написании сценариев, но на самом деле то, что он делает, довольно просто. Мы даем сценарию входную директорию, в которой он ищет изображения. Затем он переходит в этот входной каталог, ищет файлы изображений и определяет их MIME-тип. Наконец, он создает подкаталоги во входной папке для каждого типа MIME и помещает копию каждого изображения в соответствующий подкаталог. Запускаем!

bash organize-images.sh original-images

Каталог теперь выглядит так. Теперь, когда наши изображения упорядочены, мы можем перейти к созданию вариантов каждого изображения. Мы будем заниматься одним типом изображений за раз.

Конвертировать в PNG

В этом руководстве мы конвертируем три типа изображений в PNG: WebP, JPEG и SVG. Давайте начнем с написания сценария webp2png.sh, который конвертирует файлы WebP в файлы PNG.

#!/bin/bash # directory containing images
input_dir="$1" if [[ -z "$input_dir" ]]; then echo "Please specify an input directory." exit 1
fi # for each webp in the input directory
for img in $( find $input_dir -type f -iname "*.webp" );
do dwebp $img -o ${img%.*}.png
done

Вот что происходит:

input_dir=»$1″: сохраняет ввод командной строки в скрипт

if [[ -z «$input_dir» ]]; then: выполняет последующее условие, если входной каталог не определен

for img in $( find $input_dir -type f -iname «*.webp» );: перебирает каждый файл в каталоге с .webp расширением.

dwebp $img -o ${img%.*}.png: преобразует изображение WebP в вариант PNG.

bash webp2png.sh webp

Теперь у нас есть изображения PNG в каталоге webp. Затем давайте конвертируем файлы JPG / JPEG в PNG с помощью другого скрипта под названием jpg2png.sh:

#!/bin/bash # directory containing images
input_dir="$1" if [[ -z "$input_dir" ]]; then echo "Please specify an input directory." exit 1
fi # for each jpg or jpeg in the input directory
for img in $( find $input_dir -type f -iname "*.jpg" -o -iname "*.jpeg" );
do convert $img ${img%.*}.png
done

Для этого используется команда convert, предоставленная установленным нами пакетом ImageMagick. Как и в последнем скрипте, мы предоставляем входной каталог, содержащий изображения JPEG / JPG. Сценарий просматривает этот каталог и создает вариант PNG для каждого подходящего изображения. Если вы присмотритесь, мы добавили -o -iname «*.jpeg»в find. Это относится к Logical OR, который представляет собой сценарий, который находит все изображения с расширением .jpg или .jpeg.

Вот как мы его запускаем:

bash jpg2png.sh jpeg

Теперь, когда у нас есть варианты PNG из JPG, мы можем сделать то же самое и для файлов SVG:

#!/bin/bash # directory containing images
input_dir="$1" # png image width
width="$2" if [[ -z "$input_dir" ]]; then echo "Please specify an input directory." exit 1
elif [[ -z "$width" ]]; then echo "Please specify image width." exit 1
fi # for each svg in the input directory
for img in $( find $input_dir -type f -iname "*.svg" );
do svgexport $img ${img%.*}.png $width:
done

В этом сценарии появилась новая функция. Поскольку SVG — это масштабируемый формат, мы можем указать директиву width для увеличения или уменьшения SVG. Мы используем пакет svgexport, который установили ранее, для преобразования каждого файла SVG в PNG:

bash svg2png.sh svg+xml

Мы проделали здесь большую работу, создав несколько файлов PNG на основе других форматов изображений. Нам нужно проделать то же самое с остальными форматами изображений, прежде чем мы приступим к реальной задаче их оптимизации.

Конвертировать в JPG

Следуя примеру создания изображений PNG, мы конвертируем WebP, JPEG и SVG в JPG. Начнем с написания скрипта, png2jpg.sh, который преобразует PNG в SVG:

#!/bin/bash # directory containing images
input_dir="$1" # jpg image quality
quality="$2" if [[ -z "$input_dir" ]]; then echo "Please specify an input directory." exit 1
elif [[ -z "$quality" ]]; then echo "Please specify image quality." exit 1
fi # for each png in the input directory
for img in $( find $input_dir -type f -iname "*.png" );
do convert $img -quality $quality% ${img%.*}.jpg
done

Возможно, вы уже заметили закономерность в этих сценариях. Но этот вводит новую возможность, где мы можем установить директиву –quality для преобразования изображений PNG в изображения JPG. Остальное то же самое. И вот как мы его запускаем:

bash png2jpg.sh png 90

Теперь в нашем png каталоге есть изображения в формате JPG. Сделаем то же самое со сценарием webp2jpg.sh:

#!/bin/bash # directory containing images
input_dir="$1" # jpg image quality
quality="$2" if [[ -z "$input_dir" ]]; then echo "Please specify an input directory." exit 1
elif [[ -z "$quality" ]]; then echo "Please specify image quality." exit 1
fi # for each webp in the input directory
for img in $( find $input_dir -type f -iname "*.webp" );
do # convert to png first dwebp $img -o ${img%.*}.png # then convert png to jpg convert ${img%.*}.png -quality $quality% ${img%.*}.jpg
done

Опять же, это то же самое, что мы написали для преобразования WebP в PNG. Однако есть одна изюминка. Мы не можем преобразовать формат WebP напрямую в формат JPG. Следовательно, нам нужно проявить немного креатива и преобразовать WebP в PNG с помощью, dwebpа затем преобразовать PNG в JPG с помощью convert. Вот почему в for loop есть два разных шага. Запускаем:

bash webp2jpg.sh jpeg 90

Вуаля! Мы создали варианты JPG для наших изображений WebP. Теперь займемся преобразованием SVG в JPG:

#!/bin/bash # directory containing images
input_dir="$1" # jpg image width
width="$2" # jpg image quality
quality="$3" if [[ -z "$input_dir" ]]; then echo "Please specify an input directory." exit 1
elif [[ -z "$width" ]]; then echo "Please specify image width." exit 1
elif [[ -z "$quality" ]]; then echo "Please specify image quality." exit 1
fi # for each svg in the input directory
for img in $( find $input_dir -type f -iname "*.svg" );
do svgexport $img ${img%.*}.jpg $width: $quality%
done

Вы можете поспорить, думая, что видели этот сценарий раньше. Мы использовали тот же сценарий для создания изображений PNG из SVG. Единственное дополнение к этому скрипту — это то, что мы можем указать директиву quality для изображений JPG.

bash svg2jpg.sh svg+xml 512 90

Конвертировать в WebP

WebP — это формат изображений, разработанный для современных браузеров. На момент написания этой статьи он имел примерно 90%-ную поддержку браузеров, включая частичную поддержку в Safari. Самое большое преимущество WebP — это гораздо меньший размер файла по сравнению с другими форматами без ущерба для визуального качества. Это делает его хорошим форматом для пользователей.

Но хватит разговоров. Давайте напишем, png2webp.sh, который — как вы уже догадались — создает изображения WebP из файлов PNG:

#!/bin/bash # directory containing images
input_dir="$1" # webp image quality
quality="$2" if [[ -z "$input_dir" ]]; then echo "Please specify an input directory." exit 1
elif [[ -z "$quality" ]]; then echo "Please specify image quality." exit 1
fi # for each png in the input directory
for img in $( find $input_dir -type f -iname "*.png" );
do cwebp $img -q $quality -o ${img%.*}.webp
done

Это как раз обратный сценарий, который мы использовали для создания изображений PNG из файлов WebP. Вместо использования dwebp мы используем cwebp.

bash png2webp.sh png 90

У нас есть изображения WebP. Теперь конвертируем изображения JPG. Сложность в том, что нет возможности напрямую конвертировать файлы JPG в WebP. Итак, мы сначала конвертируем JPG в PNG, а затем конвертируем промежуточный PNG в WebP в jpg2webp.sh:

#!/bin/bash # directory containing images
input_dir="$1" # webp image quality
quality="$2" if [[ -z "$input_dir" ]]; then echo "Please specify an input directory." exit 1
elif [[ -z "$quality" ]]; then echo "Please specify image quality." exit 1
fi # for each webp in the input directory
for img in $( find $input_dir -type f -iname "*.jpg" -o -iname "*.jpeg" );
do # convert to png first convert $img ${img%.*}.png # then convert png to webp cwebp ${img%.*}.png -q $quality -o ${img%.*}.webp
done

Теперь мы можем использовать его вот так, чтобы получить наши WebP-варианты файлов JPG:

bash jpg2webp.sh jpeg 90

Объединение всего в один каталог

Теперь, когда мы закончили преобразование, мы на один шаг ближе к оптимизации нашей работы. Но сначала мы собираемся собрать все наши изображения в одном каталоге, чтобы их было легко оптимизировать с помощью меньшего количества команд.

Вот код, который создает новый сценарий bash с именем combine-images.sh:

#!/bin/bash input_dirs="$1"
output_dir="$2" if [[ -z "$input_dirs" ]]; then echo "Please specify an input directories." exit 1
elif [[ -z "$output_dir" ]]; then echo "Please specify an output directory." exit 1
fi # create a directory to store the generated images
mkdir -p $output_dir # split input directories comma separated string into an array
input_dirs=(${input_dirs//,/ }) # for each directory in input directory
for dir in "${input_dirs[@]}"
do # copy images from this directory to generated images directory rsync -a $dir/* $output_dir */
done

Первый параметр — это разделенный запятыми список входных каталогов, которые будут передавать изображения в целевой комбинированный каталог. Второй параметр определяет этот комбинированный каталог.

bash combine-images.sh jpeg,svg+xml,webp,png generated-images

Окончательный результат можно увидеть в репо.

Оптимизация SVG

Давайте начнем с оптимизации изображений SVG. Добавьте следующий код в optimize-svg.sh:

#!/bin/bash # directory containing images
input_dir="$1" if [[ -z "$input_dir" ]]; then
echo "Please specify an input directory."
exit 1
fi # for each svg in the input directory
for img in $( find $input_dir -type f -iname "*.svg" );
do svgo $img -o ${img%.*}-optimized.svg
done

Здесь мы используем пакет SVGO. У него есть много параметров, которые мы можем использовать, но для простоты мы придерживаемся поведения по умолчанию для оптимизации файлов SVG:

bash optimize-svg.sh generated-images

Преобразование и оптимизация изображений из командной строки

Это дает нам экономию 4 КБ для каждого изображения. Допустим, мы обслуживали 100 иконок SVG — сэкономили 400 КБ!

Оптимизация PNG

Давайте продолжим оптимизировать наши PNG-файлы, используя этот код для создания команды optimize-png.sh:

#!/bin/bash # directory containing images
input_dir="$1" if [[ -z "$input_dir" ]]; then echo "Please specify an input directory." exit 1
fi # for each png in the input directory
for img in $( find $input_dir -type f -iname "*.png" );
do optipng $img -out ${img%.*}-optimized.png
done

Здесь мы используем пакет OptiPNG для оптимизации изображений PNG. Сценарий ищет изображения PNG во входном каталоге и создает оптимизированную версию каждого из них, добавляя –optimized к имени файла. Есть один интересный аргумент -o, который мы можем использовать для определения уровня оптимизации. Значение по умолчанию — 2**, и значения варьируются от 0 до 7. Чтобы оптимизировать PNG, мы запускаем:

bash optimize-png.sh generated-images

Преобразование и оптимизация изображений из командной строки

Оптимизация PNG зависит от информации, хранящейся в изображении. Некоторые изображения можно значительно оптимизировать, в то время как для некоторых оптимизация практически отсутствует.

Как мы видим, OptiPNG отлично справляется с оптимизацией изображений. Мы можем поэкспериментировать с аргументом –o, чтобы найти подходящее значение, выбирая компромисс между качеством изображения и размером.

Оптимизация JPG

Мы подошли к финальной части! В заключение мы оптимизируем изображения JPG. Добавьте следующий код в optimize-jpg.sh:

#!/bin/bash # directory containing images
input_dir="$1" # target image quality
quality="$2" if [[ -z "$input_dir" ]]; then echo "Please specify an input directory." exit 1
elif [[ -z "$quality" ]]; then echo "Please specify image quality." exit 1
fi # for each jpg or jpeg in the input directory
for img in $( find $input_dir -type f -iname "*.jpg" -o -iname "*.jpeg" );
do cp $img ${img%.*}-optimized.jpg jpegoptim -m $quality ${img%.*}-optimized.jpg
done

Этот скрипт использует JPEG optim. Проблема с этим пакетом в том, что у него нет возможности указать выходной файл. Мы можем только оптимизировать файл изображения на месте. Мы можем решить это, сначала создав копию изображения, назвав ее как угодно, а затем оптимизируя копию, аргумент –m используется для определения качества изображения. Хорошо бы немного поэкспериментировать с этим, чтобы найти правильный баланс между качеством и размером файла.

bash optimize-jpg.sh generated-images 95

Преобразование и оптимизация изображений из командной строки

Заключение

С помощью нескольких скриптов мы можем выполнять сложные оптимизации изображений прямо из командной строки и использовать их в любом проекте, поскольку они установлены глобально. Мы можем настроить конвейеры CI / CD для создания различных вариантов каждого изображения и обслуживания их с использованием действующего HTML, API или даже создать наши собственные веб-сайты преобразования изображений.

Надеюсь, вы чему-то научились из этой статьи, так же как мне понравилось писать ее для вас. Удачного кодирования!

Автор: Ravgeet Dhillon

Источник: css-tricks.com

Редакция: Команда webformyself.