Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

Изменение размеров изображений с помощью утилит из пакета ImageMagick

Оригинал: Resizing Images with ImageMagick
Автор: Dave Taylor
Дата публикации: 29 мая 2014 г.
Перевод: А.Панин
Дата перевода: 5 сентября 2015 г.

Изменение размеров изображений с помощью утилит из пакета ImageMagick

Разумеется, вы можете открыть любой графический редактор, такой, как GIMP и изменить размер вашего изображения, но что делать в том случае, если вы хотите изменить размеры 10, 50 или 200 изображений? Утилита convert из состава пакета ImageMagick - это то, что вам нужно.

В предыдущей статье серии я начал рассматривать методику работы с утилитами из пакета ImageMagick с использованием интерфейса командной строки, но мне пришлось отвлечься от написания статей серии и вплотную заняться сумасшедшим проектом миграции моего сайта AskDaveTaylor.com с одного сервера на другой с одновременным переходом к использованию отличного программного обеспечения. Я все еще исправляю ошибки и устраняю негативные последствия всего этого.

Моя прошлая статья сводилась к дискуссии о сценариях, которые оказались полезными в процессе миграции. Я все еще работаю над этими быстрыми, короткими сценариями, включая тот, что я разработал этим утром:

for entry in blog/*
do
  new=$(echo $entry | sed 's/blog\///')
  echo "Redirect 301 $entry $new"
done

Можете ли вы отследить операции, которые выполняются в данном цикле? Единственной сложной частью данного сценария является объявление new=, которое позволяет удалить префикс blog/ из имени файла, принятого в рамках объявления for; остальные операции достаточно очевидны.

Давайте займемся серьезными делами и вернемся к рассмотрению пакета утилит ImageMagick. Существует множество операций, которые вы можете выполнить с помощью утилит с интерфейсом командной строки из этого пакета. Но сначала позвольте мне напомнить о том, на чем я остановился в прошлой статье.

В прошлой статье я привел простой пример использования утилит с интерфейсом командной строки из пакета ImageMagic для получения размеров изображения и использования их для масштабирования изображения на странице HTML путем использования соответствующего тэга. Этот сценарий выглядел аналогичным образом:

#!/bin/sh
identify=/usr/bin/identify
scale=$1
image=$2   # необходим код для проверки корректности ввода

height=$($identify $image | cut -d\   -f3 | cut -dx -f1)
width=$($identify $image | cut -d\   -f3 | cut -dx -f2)
newwidth="$(echo $width \* $scale | bc | cut -d. -f1)"
newheight="$(echo $height \* $scale | bc | cut -d. -f1)"
echo "<img src=$image height=$newheight width=$newwidth>"
exit 0

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

Данный сценарий используется следующим образом:

$ scaledown.sh 0.5 pvp.jpg
<img src=pvp.jpg height=152 width=485>

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

Поэтому давайте займемся усовершенствованием данного сценария с целью создания новой уменьшенной в масштабе версии оригинального изображения наряду с его стандартным выводом.

Утилита covert

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

Утилита convert поддерживает огромное количество параметров командной строки, но в данном случае я буду использовать единственный аргумент -resize аналогичным образом:

$ convert pvp-big.jpg -resize 0.5 pvp-0.5.jpg
$ identify pvp-big.jpg pvp-0.5.jpg
pvp-big.jpg JPEG 970x305 970x305+0+0 8-bit DirectClass 127kb
pvp-0.5.jpg JPEG 1x1 1x1+0+0 8-bit DirectClass 1.1kb

Гм... вы ведь поняли, что случилось, не так ли? Размер изображения изменился с 970x305 до 1x1. Забавно.

Как же это получилось? Проблема в том, что я передал некорректный параметр аргумента -resize. Фактически после данного аргумента должен передаваться процентный показатель (что достаточно странно), поэтому как аргумент -resize 50%, так и аргумент -resize 50 отлично работают:

$ convert pvp-big.jpg -resize 50 pvp-50.jpg
$ convert pvp-big.jpg -resize 50% pvp-50%.jpg
$ identify pvp*
pvp-50.jpg[1] JPEG 50x16 50x16+0+0 8-bit DirectClass 2.01kb
pvp-50%.jpg[2] JPEG 485x153 485x153+0+0 8-bit DirectClass 44.7kb
pvp-big.jpg[3] JPEG 970x305 970x305+0+0 8-bit DirectClass 127kb

Вспомнив о математических действиях, несложно понять, что аргумент -resize 50 предназначен для изменения ширины изображения до 50 пикселей, причем высота будет изменена пропорционально до достаточного малого значения в 16 пикселей. Аргумент -resize 50%, в свою очередь, отлично подходит для решения поставленной задачи и позволяет изменить размер изображения до приемлемого размера в 485x153 пикселя.

Исходя из этого, пользователи сценария должны будут вводить корректный процентный показатель или подбирать приемлемый размер изображения. Для того, чтобы сделать сценарий более полезным, давайте также реализуем функцию добавления суффикса с указанием на новую геометрию изображения в имя результирующего файла (в том же формате ImageMagick "ширина x высота", в котором выводят соответствующие данные утилиты из пакета ImageMagick). Таким образом, в данном случае наша задача будет состоять в изменении размеров изображения pvp-big.jpg на 50% и сохранении результирующего файла под именем pvp-big.285x153.jpg.

Давайте задействуем утилиты из пакета ImageMagick вместо вызовов утилиты bc из оригинального сценария для выполнения всех рабочих операций в следующей последовательности:

  1. Преобразование изображения в изображение с измененным размером и сохранение последнего во временном файле.

  2. Вызов утилиты identify для получения размеров изображения из временного файла.

  3. Формирование нового имени файла с использованием данных геометрии изображения.

  4. Смена имени временного файла на сформированное имя с указанием на геометрию результирующего изображения.

Кажется нам придется выполнить гораздо меньше работы, чем было запланировано, ведь нам больше не придется выполнять каких-либо математических операций, что само по себе отлично!

Самой сложной операцией, требующей больше строк кода, чем операция преобразования файла, является операция формирования нового имени файла. Данная операция предусматривает формирование суффикса имени файла, разбор имени оригинального файла и формирование нового имени файла с суффиксом, содержащим информацию о геометрии изображения, посередине.

А это результат процесса разработки сценария (он достаточно длинный):

#!/bin/sh
convert=/usr/bin/convert
identify=/usr/bin/identify
resize=$1
source=$2
if [ -z "$resize" -o -z "$source" ] ; then
  echo "Использование: $0 изменение_размера исходный_файл"; ;exit 1
fi
if [ ! -r $source ] ; then
  echo "Ошибка: не удалось прочитать исходный файл $source" ; exit 1
fi
# давайте извлечем расширение файла
filetype=$(echo $source | rev | cut -d. -f1 | rev)
 
tempfile="resize.$filetype" # имя временного файла

# создание временного файла изображения нового размера
$convert $source -resize $resize $tempfile

# получение информации о геометрии, формирование имени результирующего файла
geometry=$($identify $tempfile | cut -d\   -f3 )

newfilebase=$(echo $source | sed "s/$filetype//")
newfilename=$newfilebase$geometry.$filetype

# переименование временного файла и окончание работы
mv $tempfile $newfilename

echo \*\* размер файла $source изменен до $resize. Результирующий файл = $newfilename

exit 0

Вот и весь сценарий. Он не является слишком сложным при построчном рассмотрении. Фактически, данный сценарий точно соответствует алгоритму из четырех операций, приведенному выше. Данный алгоритм практически точно дублируется в комментариях сценария.

Единственный нюанс заключается в последовательности формирования нового имени файла (newfilename), которая представлена простым объединением набора строковых переменных для объединения их значений.

Давайте запустим сценарий и посмотрим, что произойдет:

sh resize.sh 50% pvp.jpg
** размер файла pvp.jpg изменен до 50%. Результирующий файл = pvp.485x153.jpg

Давайте проявим скептицизм и проверим размеры результирующего файла изображения с помощью утилиты identify:

$ identify pvp.485x153.jpg
pvp.485x153.jpg JPEG 485x153 485x153+0+0 8-bit DirectClass 44.7kb

Превосходно. А теперь давайте обратим внимание на изменение более важного параметра, а именно, на сокращение размера файла изображения после уменьшения размера изображения на 50%.

$ ls -l pvp.jpg pvp.485x153.jpg
-rw-rw-r-- 1 taylor taylor  45751 окт  9 04:14 pvp.485x153.jpg
-rw-r--r-- 1 taylor taylor 130347 сен  5 08:20 pvp.jpg

Очевидная победа и новый полезный сценарий для нашей коллекции.

Разумеется, лучшая проверка корректности размещения параметров и быстрая проверка вхождения параметра изменения размера в диапазон разумных значений улучшили бы качество кода, но даже в данном виде сценарий вполне неплох и является достаточно полезным.

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