Coding4Fun – фотоснимки рядом с вами

Опубликовано 26 апреля 2010 г. 18:53 | Coding4Fun

Терпеть не можете вручную менять фоновые изображения для рабочего стола? Тогда меняйте их автоматически с помощью Flickr!

Автор: Ариан Т. Кулп (Arian T. Kulp)
Исходный код: загрузить
Сложность: средняя
Необходимое время: 3 часа
Затраты: бесплатно!
ПО: Visual Basic или Visual C# Express (или выше), Windows API Code Pack, Sensors and Location API, MEF Utility Runner, FlickrNet API

Введение

В этой статье я продемонстрирую, как задействовать новый функционал Windows 7 для определения местонахождения, чтобы загружать из Flickr фотографии, сделанные в ваших окрестностях, и обновлять ими фоновую картинку на рабочем столе. Утилита написана как плагин для моего предыдущего проекта Utility Runner (приложения MEF).

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

Этот проект требует наличия Visual C#/Visual Basic Edition 2008 или выше. Он выполняется как плагин Utility Runner, поэтому перед отладкой вы должны установить это приложение.

Взрыв из прошлого

Если вы уже видели Utility Runner на основе MEF, то знаете, что это облегченный контейнер для выполнения системных утилит. Смысл в том, что разгрузить область уведомлений вашего рабочего стола (системный лоток) и сократить издержки установки множества небольших утилит. Как и в случае с гаджетами рабочего стола, вам не придется разделять выполняемые процессы. Но в отличие от гаджетов утилиты зачастую не имеют пользовательского интерфейса. Они могут выводить форму для настройки, а свою основную работу выполняют в фоновом режиме.

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

clip_image002

Так как вы разрабатываете плагин, отладку нужно проводить на хосте. Установив Utility Runner, вы можете задать его исполняемый файл как процесс, подлежащий отладке. При запуске он проверит наличие плагинов в текущем каталоге и запустит ваш код. Это упрощает отладку до такой степени, что достаточно нажать F5. Конечно, создание модульных тестов для проверки своего кода вне хоста тоже было бы отличной идеей.

Что здесь происходит

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

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

Идея смены фоновых картинок рабочего стола крайне проста в реализации. Вам нужно изображение в формате BMP или JPG и параметр масштабирования (растягивание, центрирование, мозаичное размещение, заполнение). Эта информация сохраняется в реестре Windows (HKCU/Control Panel/Desktop), а вызов Win32-функции SystemParametersInfo служит триггером операции смены изображения. Вся логика содержится в файле Wallpaper.vb/cs.

Увы, нет никакого способа инициировать новую функцию слайд-шоу в Windows 7, которая автоматически выполняла бы циклическую смену изображений. Вы могли бы добиться этого созданием файла темы и настройкой его на RSS-канал или папку с изображениями, но это не самое элегантное решение. Пользователям моей программы не понадобится конкретная тема. Однако это возможная точка расширения, если она покажется кому-то неплохой идеей.

Поиск самого себя

В Windows 7 интерфейс Location API является частью Sensors API. Это открывает вам доступ к текущему местонахождению в гражданском формате (адрес, город, штат и т. д.) или в военном – в виде пары «широта – долгота». Провайдер информации о местонахождении, содержащийся в вашей системе, определяет точность этих данных.

clip_image002[4]

В комплект скачивания Sensors and Location API входит пример под названием «Enhanced Default Location Provider», который позволяет указывать свое местонахождение щелчком нужного места на карте. Другой вариант – использовать Geosense for Windows. Это приложение определяет ваше местонахождение через Google Location Services на основе вашего IP-адреса и/или сопоставления с точкой беспроводного доступа. Так как Geosense является бесплатным приложением, настоятельно рекомендую скачать его, но оно не поможет в тестировании, если только вы не намерены много путешествовать!

Код для получения местонахождения очень прост:

Visual C#

 loc = new LatLongLocationProvider(10000);

loc.LocationChanged += new LocationChangedEventHandler(loc_LocationChanged);

lastLocation = (LatLongLocationReport)(loc.GetReport());

Visual Basic

 loc = New LatLongLocationProvider(10000)

AddHandler loc.LocationChanged, New LocationChangedEventHandler(AddressOf loc_LocationChanged)

lastLocation = loc.GetReport()

Четыре миллиарда фотоснимков

Все знают, что Flickr – то место, где можно найти много фотографий. Популярность Facebook (более 15 миллиардов снимков) меняет эту ситуацию, но, если вам нужен поиск фотоснимков местности с минимумом фото отчетов о всяких вечеринках, Flickr все же гораздо лучше. Благодаря Yahoo! имеется полнофункциональный API поиска фотографий, пользователей и групп. Одна из функций поиска принимает пару «широта – долгота» и ищет фотоснимки ближайших окрестностей, помеченные геокодом. Конечно, такая метка имеется не во всех снимках, но во многих есть.

Flickr API легко использовать, и вы можете проделать основную часть работы на основе REST-вызовов. Однако, чтобы еще больше упростить все вещи, я решил задействовать FlickrNet API, размещенный на Codeplex; он обертывает Flickr API в отличный объектно-ориентированный пакет. Из него можно авторизовать пользователя и выполнять операции поиска изображений. Авторизация пользователя необязательна, но позволяет получать любые частные снимки, принадлежащие какому-либо пользователю, и его контактную информацию. Если вы загрузили фотоснимки с геокодом, вам вряд ли понравится, что они не появляются в результатах поиска.

Авторизация пользователя заключается в его автоматической регистрации, и он даже никогда не увидит пароль. Если вы пользовались другими приложениями на основе Flickr, то видели этот механизм в действии: мы запрашиваем аутентификационный ключ от Flickr – frob (нет, я не знаю, откуда взялось такое название), который на данном этапе не значит ровным счетом ничего. Для авторизации пользователя мы должны открыть URL (передав frob как параметр) для аутентификации на Flickr. Пользователь входит, и этот frob теперь сопоставляется с ним. Когда пользователь сообщает нам, что процесс завершен, мы можем запросить от Flickr ключ авторизации. Этот ключ можно сохранить на будущее, чтобы пользователю не пришлось регистрироваться еще раз. Этот ключ также сопоставляется с разрешениями, которые пользователь выдал нашему приложению.

clip_image002[6]

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

clip_image002[8]

После авторизации на право делать вызовы, выполнение самих операций поиска осуществляется весьма прямолинейно (показаны ниже без обработки исключений):

Visual C#

 PhotoSearchOptions searchOptions = new PhotoSearchOptions();

searchOptions.Tags = FlickrTags;

searchOptions.TagMode = TagMode.AnyTag;

searchOptions.Latitude = (float)location.Latitude;

searchOptions.Longitude = (float)location.Longitude;

searchOptions.Extras = PhotoSearchExtras.OwnerName;

photos = F.PhotosSearch(searchOptions).PhotoCollection;

Properties.Settings.Default.FlickrTags = FlickrTags;

Properties.Settings.Default.Save();

photoIdx = rnd.Next(0, photos.Length – 1);

lastLocation = location;

Visual Basic

 Dim searchOptions As New PhotoSearchOptions()

searchOptions.Tags = FlickrTags

searchOptions.TagMode = TagMode.AnyTag

searchOptions.Latitude = location.Latitude

searchOptions.Longitude = location.Longitude

searchOptions.Extras = PhotoSearchExtras.OwnerName

photos = F.PhotosSearch(searchOptions).PhotoCollection

My.Settings.FlickrTags = FlickrTags

My.Settings.Save()

photoIdx = rnd.Next(0, photos.Length – 1)

lastLocation = location

Вы заполняете поисковые теги, указываете широту и долготу, а затем запрашиваете, чтобы с данными возвращалось имя их владельца. В итоге вы получаете набор объектов, представляющих Flickr-объекты. С этого момента вы запрашиваете размеры, доступные для данного снимка, и скачиваете тот, у которого самый большой размер. Приложение сохраняет его в системную папку для временных файлов. Вероятно, лучше создать папку в My Photos, но тогда возникает риск со временем потерять это изображение.

Visual C#

 string fn = Path.Combine(Path.GetTempPath(), photo.PhotoId + "_" + photo.Secret + ".jpg");

// Если снимок уже кеширован, повторное скачивание не выполняется

if (!File.Exists(fn))

{

Sizes s = F.PhotosGetSizes(photo.PhotoId);

// Используйте самое высокое из доступных разрешений

string url = s.SizeCollection[s.SizeCollection.Length – 1].Source;

Stream ds = F.DownloadPicture(url);

Stream fs = new FileStream(fn, FileMode.CreateNew);

ds.CopyTo(fs);

fs.Close();

ds.Close();

}

Status = "Now showing '" + photo.Title + "' by " + photo.OwnerName;

LastPhoto = photo;

Wallpaper.SetWallpaper(fn, WallpaperStyle.Fit);

Visual Basic

 Dim fn As String = Path.Combine(Path.GetTempPath(), photo.PhotoId + "_" + photo.Secret & ".jpg")

' Если снимок уже кеширован, повторное скачивание не выполняется

If Not File.Exists(fn) Then

Dim s As Sizes = F.PhotosGetSizes(photo.PhotoId)

' Используйте самое высокое из доступных разрешений

Dim url As String = s.SizeCollection(s.SizeCollection.Length – 1).Source

Dim ds As Stream = F.DownloadPicture(url)

Dim fs As IO.Stream = New FileStream(fn, FileMode.CreateNew)

ds.CopyTo(fs)

fs.Close()

ds.Close()

End If

Status = ("Now showing '" + photo.Title & "' by ") + photo.OwnerName

LastPhoto = photo

Wallpaper.SetWallpaper(fn, WallpaperStyle.Fit)

CopyTo – это метод расширения в файле StreamExtensions.vb/cs. Он просто копирует информацию из одного потока данных в другой – в нашем случае из потока скачиваемых данных в файловый поток.

Следующие шаги

Авторизация на Flickr через браузер была бы теснее интегрирована, если бы вы встроили элемент управления WebBrowser непосредственно в UI. Тогда вы могли бы показывать страницу авторизации вместе с окном своего приложения и кнопками Complete Authorization и Cancel.

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

Заключение

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

Об авторе

Ариан Кулп (Arian Kulp) – разработчик ПО, живет в Западном Орегоне. Создает примеры, демо-ролики, лабораторные занятия и пишет статьи, выступает на различных мероприятиях, посвященных вопросам программирования, а также с удовольствием проводит свободное время со своей семьей.