Командная строка в Linux обладает необычайно широким диапазоном возможностей, но так как она имеет текстовый интерфейс, то не позволяет выполнять сколько-нибудь сложную обработку графики. Или это не так?
Оказывается, практически в любом окружении командной строки, от OSX до Linux и многих других систем, доступен необычайно мощный пакет утилит командной строки, ImageMagick. Чтобы опробовать сценарии в этой главе, вам придется загрузить и установить пакет с сайта http://www.imagemagick.org/ или воспользоваться системным диспетчером пакетов, таким как apt, yum или brew, если вы этого не сделали, когда знакомились со сценарием № 91 из главы 13.
Так как утилиты предназначены для работы в командной строке, они занимают очень мало дискового пространства, что-то около 19 Мбайт (для Windows-версии). Вы можете также получить исходный код пакета, если хотите посмотреть, как выглядит внутри такое мощное и гибкое программное обеспечение. И снова открытое ПО побеждает.
Команда file позволяет определять типы файлов и в некоторых случаях даже размеры изображений. Но очень часто она терпит неудачу:
$ file * | head -4
100_0399.png: PNG image data, 1024 x 768, 8-bit/color RGBA, non-interlaced
8t grade art1.jpeg: JPEG image data, JFIF standard 1.01
99icon.gif: GIF image data, version 89a, 143 x 163
Angel.jpg: JPEG image data, JFIF standard 1.01
Файлы PNG и GIF не вызывают проблем, но как быть с не менее распространенными файлами JPEG? Команда file не смогла определить размеры изображений. Какая досада!
Давайте устраним эту проблему с помощью сценария (листинг 14.1), который использует инструмент identify из пакета ImageMagick, чтобы точно определить размеры изображения.
Листинг 14.1. Сценарий imagesize
#!/bin/bash
# imagesize -- выводит информацию о файле изображения и определяет размеры,
# используя утилиту identify из пакета ImageMagick.
for name
do
identify -format "%f: %G with %k colors.\n" "$name"
done
exit 0
Когда инструмент identify вызывается с флагом -verbose, он извлекает огромный объем информации о каждом анализируемом изображении, как показано ниже, где исследуется один из файлов в формате PNG:
$ identify -verbose testimage.png
Image: testimage.png
Format: PNG (Portable Network Graphics)
Class: DirectClass
Geometry: 1172x158+0+0
Resolution: 72x72
Print size: 16.2778x2.19444
Units: Undefined
--опущено--
Profiles:
Profile-icc: 3144 bytes
IEC 61966-2.1 Default RGB colour space - sRGB
Artifacts:
verbose: true
Tainted: False
Filesize: 80.9KBB
Number pixels: 185KB
Pixels per second: 18.52MB
User time: 0.000u
Elapsed time: 0:01.009
Version: ImageMagick 6.7.7-10 2016-06-01 Q16 http://www.imagemagick.org
$
Это очень большой объем данных. Намного больше, чем можно было представить. Но без флага -verbose вывод выглядит весьма туманным:
$ identify testimage.png
testimage.png PNG 1172x158 1172x158+0+0 8-bit DirectClass 80.9KB 0.000u
0:00.000
Нам хотелось бы получить что-то среднее, и в такой ситуации может пригодиться строка формата. Давайте рассмотрим внимательнее листинг 14.1, сфокусировав все внимание на единственной значимой строке .
Строка формата -format поддерживает почти 30 спецификаторов, позволяющих извлекать конкретные данные из одного или нескольких файлов изображений в строго определенном формате. В данном сценарии мы выбрали %f, чтобы получить имя файла, %G — чтобы получить ширину и высоту, и %k — чтобы получить максимальное количество цветов, используемых в изображении.
Более подробную информацию о спецификаторах строки формата -format можно найти по адресу: http://www.imagemagick.org/script/escape.php.
Всю работу выполняет ImageMagick, поэтому данный сценарий в основном лишь кодирует желаемый формат вывода. Информация извлекается из изображений легко и просто, как показывает листинг 14.2.
Листинг 14.2. Запуск сценария imagesize
$ imagesize * | head -4
100_0399.png: 1024x768 with 120719 colors.
8t grade art1.jpeg: 480x554 with 11548 colors.
dticon.gif: 143x163 with 80 colors.
Angel.jpg: 532x404 with 80045 colors.
$
В настоящий момент мы видим размеры изображений в пикселях и количество используемых цветов, но также было бы полезно знать размеры файлов. Однако любую дополнительную информацию сложно читать, если не предусмотреть ее форматирование.
Если вы надеетесь сохранить в неприкосновенности свои изображения и другой контент, публикуемый в сети, вы неизбежно будете разочарованы. Все, что опубликовано в сети, доступно любому для копирования, даже если вы защитили доступ к своим материалам паролем, включили предупреждение об авторских правах или даже добавили на сайт код, не позволяющий сохранять изображения. Даже чтобы показать изображение на экране, необходимо, чтобы оно оказалось в памяти, а эту память можно скопировать с помощью инструментов захвата экрана.
Но не все потеряно. У вас есть два способа защитить свои изображения в сети. Первый — публиковать только изображения маленьких размеров. Загляните на сайты профессиональных фотографов и вы увидите, что мы имеем в виду. Обычно на них публикуются только миниатюры, потому что фотографы хотят зарабатывать на больших изображениях.
Второй способ — использование водяных знаков, хотя некоторые художники и отказываются добавлять любую идентификационную информацию непосредственно на фотографии. Тем не менее с помощью ImageMagick легко можно добавить водяные знаки, как показано в листинге 14.3, даже в большое количество файлов сразу.
Листинг 14.3. Сценарий watermark
#!/bin/bash
# watermark -- добавляет указанный текст в виде водяных знаков в заданное
# изображение, сохраняя результат в файле с именем image+wm.
wmfile="/tmp/watermark.$$.png"
fontsize="44" # Должен быть начальным аргументом.
trap "$(which rm) -f $wmfile" 0 1 15 # Не оставлять временный файл.
if [ $# -ne 2 ] ; then
echo "Usage: $(basename $0) imagefile \"watermark text\"" >&2
exit 1
fi
if [ ! -r "$1" ] ; then
echo "$(basename $0): Can't read input image $1" >&2
exit 1
fi
# Для начала получить размеры изображения.
dimensions="$(identify -format "%G" "$1")"
# Создать временный слой для водяного знака.
convert -size $dimensions xc:none -pointsize $fontsize -gravity south \
-draw "fill black text 1,1 '$2' text 0,0 '$2' fill white text 2,2 '$2'" \
$wmfile
# Теперь объединить временный слой и исходный файл.
suffix="$(echo $1 | rev | cut -d. -f1 | rev)"
prefix="$(echo $1 | rev | cut -d. -f2- | rev)"
newfilename="$prefix+wm.$suffix"
composite -dissolve 75% -gravity south $wmfile "$1" "$newfilename"
echo "Created new watermarked image file $newfilename."
exit 0
Вся запутанность кода здесь объясняется использованием ImageMagick. Да, этот пакет многое умеет, но даже полная документация, где описаны все тонкости, не упрощает работу с ним. Но трудности не должны вас пугать, потому что потрясающие возможности различных инструментов ImageMagick стоят того.
Первый шаг — получить размеры изображения , чтобы создать точно таких же размеров слой с водяными знаками. В противном случае изображение будет испорчено!
Спецификатор "%G" возвращает ширину и высоту, которые затем передаются программе convert для создания нового холста. Строку с вызовом convert мы скопировали из документации ImageMagick, потому что она действительно слишком хитрая, чтобы ее можно написать с нуля. (Чтобы узнать больше о языке параметров команды convert -draw, попробуйте воспользоваться поисковой системой. Или можете просто скопировать наш код!)
Имя нового файла должно состоять из имени исходного файла с дополнением "+wm", и именно это делают три строки в . Команда rev переворачивает входную строку задом наперед, а следующая команда cut -d. -f1 просто возвращает расширение файла, поскольку мы не знаем, сколько точек присутствует в имени файла. Затем расширение снова переворачивается и добавляется после "+wm.".
В заключение вызывается утилита composite , объединяющая элементы и создающая изображение с водяными знаками. Вы можете поэкспериментировать с разными значениями -dissolve, чтобы отрегулировать прозрачность дополнительного слоя.
Сценарий принимает два аргумента: имя файла с изображением и текст, который должен быть нанесен на него. Если текст содержит несколько слов, не забудьте заключить его в кавычки, как показано в листинге 14.4, чтобы сценарий правильно воспринял фразу целиком.
Листинг 14.4. Запуск сценария watermark
$ watermark test.png "(C) 2016 by Dave Taylor"
Created new watermarked image file test+wm.png.
Результат показан на рис. 14.1.
Рис. 14.1. Изображение с нанесенными водяными знаками
Если вы столкнетесь с ошибкой unable to read font (невозможно прочитать шрифт), скорее всего, в вашей системе отсутствует пакет Ghostscript (в OS X он устанавливается по умолчанию). Чтобы устранить проблему, установите Ghostscript с помощью своего диспетчера пакетов. Например, в OS X это можно сделать следующей командой:
$ brew install ghostscript
Размер шрифта, используемого для нанесения водяных знаков, должен быть функцией от размеров изображения. Если изображение имеет ширину 280 пикселей, шрифт размером в 44 пункта окажется слишком большим, но, если изображение имеет ширину 3800 пикселей, тот же шрифт окажется слишком мелким. Можно также позволить пользователю самому выбирать подходящий размер шрифта или местоположение текста, добавив в сценарий поддержку соответствующих параметров.
ImageMagick в состоянии определять шрифты, присутствующие в вашей системе, поэтому вполне можно разрешить пользователю указывать шрифт по его названию.
Часто бывает желательно добавить вокруг изображения бордюр или причудливую рамку. Пакет ImageMagick предоставляет массу возможностей для этого через утилиту convert. Проблема, как и с остальными утилитами из пакета, в том, что документация к ImageMagick недостаточно ясно описывает, как пользоваться этим инструментом.
Например, ниже приводится выдержка из документации с описанием параметра -frame:
Часть аргумента geometry с размерами определяет дополнительные ширину и высоту, которые будут добавлены к размерам изображения. Если смещения в аргументе geometry не заданы, тогда добавляется бордюр со сплошной заливкой. Смещения x и y, если они заданы, определяют ширину и высоту бордюра, которые отводятся для формирования фаски, внешней (x пикселей) и внутренней (y пикселей).
Получили?
Возможно, вам станет понятнее после разбора практического примера. Именно эту цель преследует функция usage() в сценарии, представленном в листинге 14.5.
Листинг 14.5. Сценарий frameit
#!/bin/bash
# frameit -- упрощает добавление графической рамки вокруг
# изображения, используя ImageMagick.
usage()
{
cat << EOF
Usage: $(basename $0) -b border -c color imagename
or $(basename $0) -f frame -m color imagename
In the first case, specify border parameters as size x size or
percentage x percentage followed by the color desired for the
border (RGB or color name).
In the second instance, specify the frame size and offset,
followed by the matte color.
EXAMPLE USAGE:
$(basename $0) -b 15x15 -c black imagename
$(basename $0) -b 10%x10% -c gray imagename
$(basename $0) -f 10x10+10+0 imagename
$(basename $0) -f 6x6+2+2 -m tomato imagename
EOF
exit 1
}
#### ГЛАВНЫЙ БЛОК КОДА
# Большая его часть занимается парсингом начальных аргументов!
while getopts "b:c:f:m:" opt; do
case $opt in
b ) border="$OPTARG"; ;;
c ) bordercolor="$OPTARG"; ;;
f ) frame="$OPTARG"; ;;
m ) mattecolor="$OPTARG"; ;;
? ) usage; ;;
esac
done
shift $(($OPTIND - 1)) # Употребить все проанализированные аргументы.
if [ $# -eq 0 ] ; then # Изображения не указаны?
usage
fi
# Что требуется добавить? Бордюр или рамку?
if [ ! -z "$bordercolor" -a ! -z "$mattecolor" ] ; then
echo "$0: You can't specify a color and matte color simultaneously." >&2
exit 1
fi
if [ ! -z “$frame” -a ! -z “$border” ] ; then
echo “$0: You can’t specify a border and frame simultaneously.” >&2
exit 1
fi
if [ ! -z “$border” ] ; then
args=”-bordercolor $bordercolor -border $border”
else
args=”-mattecolor $mattecolor -frame $frame”
fi
for name
do
suffix="$(echo $name | rev | cut -d. -f1 | rev)"
prefix="$(echo $name | rev | cut -d. -f2- | rev)"
newname="$prefix+f.$suffix"
echo "Adding a frame to image $name, saving as $newname"
convert $name $args $newname
done
exit 0
Если не считать использования команды getopts для анализа сложных параметров, которую мы уже исследовали, этот сценарий действует достаточно прямолинейно. Основная работа в нем выполняется в нескольких последних строках. В цикле for создается имя нового файла, включающее "+f" в конце (но перед расширением, определяющим тип файла).
Например, для имени файла abandoned-train.png в переменную suffix будет записано расширение png, а в переменную prefix — имя abandoned-train. Обратите внимание на пропажу точки (.) — она возвращается на место во время сборки нового имени файла . После этого остается только вызвать программу convert со всеми параметрами .
Укажите тип желаемой рамки — с помощью параметра -frame (для придания 3-мерного вида) или -border (простой бордюр) — и ее размеры, предпочтительный цвет для бордюра или лицевой поверхности рамки, а также имя исходного файла (или файлов). Например, как показано в листинге 14.6.
Листинг 14.6. Запуск сценария frameit
$ frameit -f 15%x15%+10+10 -m black abandoned-train.png
Adding a frame to image abandoned-train.png, saving as abandoned-train+f.png
Результат этого вызова показан на рис. 14.2.
Рис. 14.2. 3-мерная рамка матового стекла в музейном стиле
Если забыть указать один из параметров, ImageMagick выведет типичное туманное сообщение:
$ frameit -f 15%x15%+10+10 alcatraz.png
Adding a frame to image alcatraz.png, saving as alcatraz+f.png
convert: option requires an argument '-mattecolor’ @ error/convert.c/
ConvertImageCommand/1936.
Добавление в сценарий дополнительных проверок на возможные ошибки, чтобы оградить пользователя от подобной абракадабры, стало бы неплохим усовершенствованием, как вы думаете?
Этот сценарий может неправильно работать с файлами, если их имена содержат пробелы. Конечно, пробелов вообще не должно быть в именах файлов, которые используются веб-сервером, тем не менее, вам стоило бы исправить сценарий, чтобы устранить этот недостаток.
Нас удивляет, насколько часто возникает эта проблема: кто-то или включает в веб-страницу чрезмерно большие изображения, или посылает по электронной почте фотографии, превосходящие по своим размерам экран компьютера. Это не только неприятно, но и влечет напрасный расход пропускной способности и вычислительных ресурсов.
Сценарий, продемонстрированный ниже, создает миниатюры из любых изображений, позволяя указать точную высоту и ширину или просто задать размеры, в которые должно уложиться уменьшенное изображение с сохранением пропорций. Именно для создания миниатюр официально предназначается замечательная утилита mogrify:
$ mkdir thumbs
$ mogrify -format gif -path thumbs -thumbnail 100x100 *.jpg
Обратите внимание, что всегда желательно создавать миниатюры в параллельном каталоге, а не там, где находятся исходные изображения. Фактически, утилита mogrify может оказаться довольно опасной при неправильном использовании, так как способна уничтожить все исходные изображения в каталоге, затерев их уменьшенными версиями. Чтобы не было причин для беспокойства, команда mogrify создает миниатюры с размерами 100 × 100 в подкаталоге thumbs, попутно преобразуя их из формата JPEG в формат GIF.
Это удобно, но лишь в отдельных случаях. Давайте создадим более универсальный сценарий для создания миниатюр, представленный в листинге 14.7. Его можно использовать и для решения многих других задач, связанных с уменьшением изображений.
Листинг 14.7. Сценарий thumbnails
#!/bin/bash
# thumbnails -- создает миниатюры из указанных графических файлов,
# точно указанных размеров или не превышающих указанные размеры, когда
# требуется сохранить пропорции.
convargs="-unsharp 0x.5 -resize"
count=0; exact=""; fit=""
usage()
{
echo "Usage: $0 (-e|-f) thumbnail-size image [image] [image]" >&2
echo "-e resize to exact dimensions, ignoring original proportions" >&2
echo "-f fit image into specified dimensions, retaining proportion" >&2
echo "-s strip EXIF information (make ready for web use)" >&2
echo " please use WIDTHxHEIGHT for requested size (e.g., 100x100)"
exit 1
}
#############
## НАЧАЛО ОСНОВНОГО СЦЕНАРИЯ
if [ $# -eq 0 ] ; then
usage
fi
while getopts "e:f:s" opt; do
case $opt in
e ) exact="$OPTARG"; ;;
f ) fit="$OPTARG"; ;;
s ) strip="-strip"; ;;
? ) usage; ;;
esac
done
shift $(($OPTIND - 1)) # Употребить все проанализированные аргументы.
rwidth="$(echo $exact $fit | cut -dx -f1)" # Затребованная ширина.
rheight="$(echo $exact $fit | cut -dx -f2)" # Затребованная высота.
for image
do
width="$(identify -format "%w" "$image")"
height="$(identify -format "%h" "$image")"
# Создать миниатюру для изображения $image, с шириной $width и высотой $height
if [ $width -le $rwidth -a $height -le $rheight ] ; then
echo "Image $image is already smaller than requested dimensions. Skipped."
else
# Сконструировать новое имя файла.
suffix="$(echo $image | rev | cut -d. -f1 | rev)"
prefix="$(echo $image | rev | cut -d. -f2- | rev)"
newname="$prefix-thumb.$suffix"
# Добавить окончание "!", чтобы игнорировать пропорции, если требуется.
if [ -z "$fit" ] ; then
size="$exact!"
echo "Creating ${rwidth}x${rheight} (exact size) thumb for file $image"
else
size="$fit"
echo "Creating ${rwidth}x${rheight} (max size) thumb for file $image"
fi
convert "$image" $strip $convargs "$size" "$newname"
fi
count=$(( $count + 1 ))
done
if [ $count -eq 0 ] ; then
echo "Warning: no images found to process."
fi
exit 0
Пакет ImageMagick настолько сложен, что практически вынуждает писать подобные сценарии, чтобы упростить решение типичных задач. В этом сценарии мы использовали пару дополнительных возможностей, включая параметр -strip , чтобы удалить EXIF-информацию (eXchangeable Image File Format — формат файлов для обмена изображениями), наличие которой оправданно в фотоархивах, но бессмысленно в изображениях, публикуемых в Сети (например, модель фотокамеры, выдержка, диафрагма, географические координаты и так далее).
Другой новый флаг — фильтр -unsharp , гарантирующий, что изображение на миниатюре не получится размазанным. Чтобы понять все возможные значения этого параметра и то, как они влияют на результат, требуются недюжинные познания, так что мы не будем усложнять и просто используем параметр 0x.5 без всяких пояснений. Хотите узнать больше? В Интернете вы быстро найдете подробную информацию.
Взгляните на рис. 14.3, чтобы лучше уловить разницу между теми миниатюрами, для которых были заданы точные размеры, и теми, которые требовалось уместить в определенные рамки с соблюдением пропорций.
Разница между созданием миниатюр точного размера и миниатюр с сохранением пропорций заключается в единственном восклицательном знаке. Она определяется в блоке .
Все остальное, что есть в этом сценарии, от пересборки имен файлов до использования флага -format, чтобы получить высоту и ширину текущего изображения, вы уже видели выше.
Исходное изображение, 1024 × 657
Миниатюра «с сохранением пропорций»
Миниатюра «с точно заданными
размерами»
Рис. 14.3. Разница между миниатюрой с точно заданными размерами (аргумент -e) и миниатюрой, полученной уменьшением до определенных размеров с сохранением пропорций (аргумент -f)
В листинге 14.8 демонстрируется попытка создать с помощью сценария миниатюры разных размеров для фотографии, сделанной на Гавайях.
Листинг 14.8. Запуск сценария thumbnails
$ thumbnails
Usage: thumbnails (-e|-f) thumbnail-size image [image] [image]
-e resize to exact dimensions, ignoring original proportions
-f fit image into specified dimensions, retaining proportion
-s strip EXIF information (make ready for web use)
please use WIDTHxHEIGHT for requested size (e.g., 100x100)
$ thumbnails -s -e 300x300 hawaii.png
Creating 300x300 (exact size) thumb for file hawaii.png
$ thumbnails -f 300x300 hawaii.png
Creating 300x300 (max size) thumb for file hawaii.png
$
Отличным дополнением для этого сценария стала бы возможность создавать наборы миниатюр указанных размеров, например 100 × 100, 500 × 500 и 1024 × 768 (типичный размер обоев для рабочего стола), одним вызовом сценария. С другой стороны, эту задачу, пожалуй, лучше реализовать в другом сценарии.
Большинство фотографий в наши дни делается с помощью сотовых телефонов или других цифровых устройств, способных определять широту и долготу своего местонахождения. Конечно, это создает некоторые проблемы с сохранением тайны частной жизни, но возможность узнать, где была сделана фотография, представляет определенный интерес. К сожалению, даже при том, что утилита identify из пакета ImageMagick позволяет извлекать информацию GPS, формат, в каком она представляет данные, очень сложно читать:
exif:GPSLatitude: 40/1, 4/1, 1983/100
exif:GPSLatitudeRef: N
exif:GPSLongitude: 105/1, 12/1, 342/100
exif:GPSLongitudeRef: W
Координаты выводятся в градусах, минутах и секундах — что естественно, — но сам формат представления не понятен на первый взгляд, как, например, формат, принимаемый сайтами Google Maps или Bing Maps:
40 4' 19.83" N, 105 12’ 3.42" W
Сценарий преобразует информацию EXIF в этот формат, благодаря чему вы сможете скопировать данные и вставить их непосредственно в программу отображения карт. В ходе преобразования сценарий решает несколько элементарных уравнений (обратите внимание, что значение секунд широты, в действительности равное 19,83, инструментом identify возвращается в виде 1983/100).
Понятие широты и долготы появилось намного раньше, чем вы могли бы подумать. В действительности впервые линии, обозначающие широту, появились еще в 1504 году на картах португальского картографа Педру Рейнел (Pedro Reinel). В вычислениях используются также некоторые математические формулы. К счастью, нам не придется обрабатывать их. Нам достаточно знать, как преобразовать широту и долготу из значений в формате EXIF в традиционные, понятные современным программам отображения карт, как можно увидеть в листинге 14.9. Этот сценарий также использует сценарий № 8, echon, из главы 1.
Листинг 14.9. Сценарий geoloc
#!/bin/bash
# geoloc -- для изображений, включающих информацию GPS, преобразует эти
# данные в строку, которую можно ввести в Google Maps или Bing Maps.
tempfile="/tmp/geoloc.$$"
trap "$(which rm) -f $tempfile" 0 1 15
if [ $# -eq 0 ] ; then
echo "Usage: $(basename $0) image" >&2
exit 1
fi
for filename
do
identify -format "%[EXIF:*]" "$filename" | grep GPSL > $tempfile
latdeg=$(head -1 $tempfile | cut -d, -f1 | cut -d= -f2)
latdeg=$(scriptbc -p 0 $latdeg)
latmin=$(head -1 $tempfile | cut -d, -f2)
latmin=$(scriptbc -p 0 $latmin)
latsec=$(head -1 $tempfile | cut -d, -f3)
latsec=$(scriptbc $latsec)
latorientation=$(sed -n '2p' $tempfile | cut -d= -f2)
longdeg=$(sed -n '3p' $tempfile | cut -d, -f1 | cut -d= -f2)
longdeg=$(scriptbc -p 0 $longdeg)
longmin=$(sed -n '3p' $tempfile | cut -d, -f2)
longmin=$(scriptbc -p 0 $longmin)
longsec=$(sed -n '3p' $tempfile | cut -d, -f3)
longsec=$(scriptbc $longsec)
longorientation=$(sed -n '4p' $tempfile | cut -d= -f2)
echon "Coords: $latdeg ${latmin}' ${latsec}\" $latorientation, "
echo "$longdeg ${longmin}' ${longsec}\" $longorientation"
done
exit 0
Каждый раз, исследуя приемы использования пакета ImageMagick, мы находим другие параметры и другие способы применения его возможностей. В данном случае аргумент -format извлекает из EXIF изображения только один определенный параметр.
Обратите внимание, что здесь роль шаблона в команде grep играет строка GPSL, а не GPS. Благодаря этому отфильтровывается вся дополнительная информация, связанная с GPS, которая нам не нужна. Попробуйте убрать символ L, и вы увидите, как много других сведений из блока с EXIF-данными будет выведено на экран!
Затем остается только извлечь конкретные поля и решить несколько уравнений с помощью scriptbc, чтобы преобразовать данные в более понятный формат, как можно видеть в строках latdeg .
Суть использования конвейера с несколькими командами cut должна быть вам уже знакома. Это чрезвычайно удобный для сценариев инструмент!
После извлечения всех данных и решения всех уравнений необходимо вновь собрать информацию в виде, совместимом со стандартной формой записи широты и долготы . Вот и все!
Передайте сценарию файл изображения, и, если он включает информацию о широте и долготе, сценарий преобразует ее в формат, понятный Google Maps, Bing Maps и другим программам для отображения карт, как показано в листинге 14.10.
Листинг 14.10. Запуск сценария geoloc
$ geoloc parking-lot-with-geotags.jpg
Coords: 40 3' 19.73" N, 103 12' 3.72" W
$
Что получится, если передать сценарию фотографию, в которой отсутствует информация EXIF? Сценарий должен обрабатывать эту ситуацию, а не просто выводить уродливое сообщение об ошибке, полученное от программы bc, потерпевшей неудачу, или пустые координаты. Вы согласны? Дополнительные проверки информации GPS с координатами, извлекаемой с помощью ImageMagick, были бы полезным дополнением.
В первом случае определяются параметры бордюра, как пиксели×пиксели или проценты×проценты, за которыми следует желаемый цвет бордюра (в формате RGB или в виде названия цвета).
Во втором случае определяются размеры рамки и ее фасок, за которым следует цвет рамки.