Geotagging — привязка фотографий к карте
Уверен что про geotagging слышало подавляющее большинство хабраюзеров, особенно те кто интересуется фотографией. Для тех же, кто все таки не слышал поясню — в двух словах geotagging есть внедрение Exif тегов содержащих информацию с координатами GPS в фотографии с последующей привязкой фотографий к карте.
Возможность просмотра привязанных к картам фотографий предоставляет большинство современных фото-хостингов — PicasaWeb, Flickr, Яндекс-Фотки и прочие, да и десктопные программы подтягиваются, например Picasa.
Идеальный вариант для геотеггинга это приобретение специальных GPS-логгеров, тем более что цены на них в последнее время постоянно падают. Принцип действия GPS-логгеров прост до безобразия — устройство периодически сбрасывает текущие координаты на карту памяти, параллельно фотографируются фотки (желательно с включенной функцией «шедевр»). После фотосессии на фотки и трек с гео-логгера натравливается спец-софт, прописывающий в фотографии GPS координаты, синхронизируясь по времени.
Можно также использовать для этих целей коммуникатор с GPS — алгоритм аналогичен, хотя и не без минусов. Например, время работы коммуникатора, учитывая то что он не специально заточен под эти цели, оставляет желать лучшего. Но что делать если волшебного девайса нету, а фотки привязать к карте все-таки хочется?
Если все же сильно хочется, то можно залить фотографии на фотохостинг и вручную привязать их к карте, минус данного способа в том что на диске остаются фотографии без координат, да и делать что-то вручную не достойно правоверных айтишников/программистов с обостренной врожденной ленью.
Учитывая все вышенаписанное, было потрачено около часа времени на написание простого кода выдирающего GPS координаты с карты при щелчке мыши и прописывающего их в Exif фотографии.
Итак, задачу можно разделить на два этапа: 1. Вывод карты на экран и определение GPS координат. 2. Добавление тегов с GPS координатами в Exif информацию JPEG файла.
Вывод карты и определение GPS координатРешить данную задачу при помощи Google Maps API гораздо проще чем может показаться на первый взгляд.
Создадим HTML файл с компонентом Google Maps, растянутым на весь экран без марджинов:
- <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" >
- < html xmlns ="http://www.w3.org/1999/xhtml" xmlns:v ="urn:schemas-microsoft-com:vml" >
- < head >
- < meta http-equiv ="content-type" content ="text/html; charset=UTF-8" />
- < title ></ title >
- < style type ="text/css" >
- body, html
- #map_canvas
- </ style >
- < script src
- type ="text/javascript" ></ script >
- <script type= "text/javascript" >
- var map;
- function initialize()
- </ script >
- </ head >
- < body onload ="initialize()" >
- < div id ="map_canvas" >
- </ div >
- </ body >
- </ html >
* Ключ для использования Google Maps API можно получить здесь, в примере используется ключ используемый в примерах в документации Maps API.
Загрузим файл в компонент WebBrowser (для удобства я поместил файл в ресурсы проекта):
- webBrowser.AllowWebBrowserDrop = false ;
- webBrowser.IsWebBrowserContextMenuEnabled = false ;
- webBrowser.WebBrowserShortcutsEnabled = false ;
- webBrowser.ObjectForScripting = this ;
- webBrowser.DocumentText = Resources.google;
Скомпилировав приложение на данном этапе, увидим следующее:
Добавим к компоненту карты возможность поиска, для этого включим GoogleBar, добавив следующий код к функции initialize():
- var mapOptions =
- // Включаем строку поиска
- map.enableGoogleBar();
Теперь добавим обработчик клика мыши на карте, для этого определим следующую функцию:
- // Обработчик клика по карте
- function getLatLng(overlay,latlng)
- >
И соответствюший listener в функцию initialize():
- GEvent.addListener(map, "click" , getLatLng);
Функция getLatLng() довольно проста. Сначала мы вычищаем все оверлеи с карты, создаем новый маркер с координатами места где пользователь кликнул по карте, ну и наконец, из эстетических соображений выводим popup с координатами.
Вот что у нас получилось:
Все выглядит красиво и юзабельно, но как же передать данные с координатами в приложение-хост (WinForms с компонентом WebBrowser)?
Для этого можно воспользоваться свойством WebBrowser.ObjectForScripting. Обьект присвоенный этому свойству доступен скриптам в странице как window.external. Замечу что обьект присваемый свойству ObjectForScripting (в данном случае обьект Form содержащий компонент WebBrowser) должен быть помечен аттрибутом ComVisible и в скриптах будут доступны только public методы и свойства.
Итак, добавим в функцию getLatLng() следуюшую строку:
- // Передача координат в хост-приложение
- window.external.SetValue(latlng.lat() + '|' + latlng.lng());
Как я уже сказал, доступ к обьекту присвоенному ObjectForScripting осуществляется через window.external, следовательно чтобы добавленный код заработал надо добавить в класс формы public метод SetValue(string):
- public void SetValue( string value )
Небольшое отступление, в методе SetValue используется класс GPSCoordinates.
Класс GPSCoordinatesGoogle Maps выдает координаты в десятичной форме, в Exif данные пишутся в виде массива байтов (об этом — ниже). Класс GPSCoordinates переводит десятичные GPS координаты в формат DMS (Degrees, Minutes, Seconds). Метод GetExifBytes() возвращает массив байтов подходящий для записи в Exif, об этом — в следующей части статьи.
- internal class GPSCoordinate