Книга: Сценарии командной оболочки. Linux, OS X и Unix. 2-е издание
Назад: Глава 13. Работа в облаке
Дальше: Глава 15. Дни и даты

Глава 14. ImageMagick и обработка графических файлов

Командная строка в Linux обладает необычайно широким диапазоном возможностей, но так как она имеет текстовый интерфейс, то не позволяет выполнять сколько-нибудь сложную обработку графики. Или это не так?

Оказывается, практически в любом окружении командной строки, от OSX до Linux и многих других систем, доступен необычайно мощный пакет утилит командной строки, ImageMagick. Чтобы опробовать сценарии в этой главе, вам придется загрузить и установить пакет с сайта http://www.imagemagick.org/ или воспользоваться системным диспетчером пакетов, таким как apt, yum или brew, если вы этого не сделали, когда знакомились со сценарием № 91 из главы 13.

Так как утилиты предназначены для работы в командной строке, они занимают очень мало дискового пространства, что-то около 19 Мбайт (для Windows-версии). Вы можете также получить исходный код пакета, если хотите посмотреть, как выглядит внутри такое мощное и гибкое программное обеспечение. И снова открытое ПО побеждает.

№ 94. Интеллектуальный анализатор размеров изображений

Команда 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.

$

Усовершенствование сценария

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

№ 95. Добавление водяных знаков в изображения

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

Но не все потеряно. У вас есть два способа защитить свои изображения в сети. Первый — публиковать только изображения маленьких размеров. Загляните на сайты профессиональных фотографов и вы увидите, что мы имеем в виду. Обычно на них публикуются только миниатюры, потому что фотографы хотят зарабатывать на больших изображениях.

Второй способ — использование водяных знаков, хотя некоторые художники и отказываются добавлять любую идентификационную информацию непосредственно на фотографии. Тем не менее с помощью 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-01.tif

Рис. 14.1. Изображение с нанесенными водяными знаками

Если вы столкнетесь с ошибкой unable to read font (невозможно прочитать шрифт), скорее всего, в вашей системе отсутствует пакет Ghostscript (в OS X он устанавливается по умолчанию). Чтобы устранить проблему, установите Ghostscript с помощью своего диспетчера пакетов. Например, в OS X это можно сделать следующей командой:

$ brew install ghostscript

Усовершенствование сценария

Размер шрифта, используемого для нанесения водяных знаков, должен быть функцией от размеров изображения. Если изображение имеет ширину 280 пикселей, шрифт размером в 44 пункта окажется слишком большим, но, если изображение имеет ширину 3800 пикселей, тот же шрифт окажется слишком мелким. Можно также позволить пользователю самому выбирать подходящий размер шрифта или местоположение текста, добавив в сценарий поддержку соответствующих параметров.

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

№ 96. Добавление рамок вокруг изображений

Часто бывает желательно добавить вокруг изображения бордюр или причудливую рамку. Пакет 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-02.tif

Рис. 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.

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

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

№ 97. Создание миниатюр изображений

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

Сценарий, продемонстрированный ниже, создает миниатюры из любых изображений, позволяя указать точную высоту и ширину или просто задать размеры, в которые должно уложиться уменьшенное изображение с сохранением пропорций. Именно для создания миниатюр официально предназначается замечательная утилита 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, чтобы получить высоту и ширину текущего изображения, вы уже видели выше.

14-03.tif

Исходное изображение, 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 (типичный размер обоев для рабочего стола), одним вызовом сценария. С другой стороны, эту задачу, пожалуй, лучше реализовать в другом сценарии.

№ 98. Интерпретация информации геопозиционирования GPS

Большинство фотографий в наши дни делается с помощью сотовых телефонов или других цифровых устройств, способных определять широту и долготу своего местонахождения. Конечно, это создает некоторые проблемы с сохранением тайны частной жизни, но возможность узнать, где была сделана фотография, представляет определенный интерес. К сожалению, даже при том, что утилита 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 или в виде названия цвета).

Во втором случае определяются размеры рамки и ее фасок, за которым следует цвет рамки.

Назад: Глава 13. Работа в облаке
Дальше: Глава 15. Дни и даты