Что-то все больше меня уносит в сторону ПО, работающего со всякими online-сервисами. Вон было недавно о Google Translate и Yahoo! Maps, а сегодня буду рассказывать о том как работать с сервисом хостинга фотографий Flickr на .NET Compact Framework.
Итак, предметом нашего внимания сегодня будет библиотека Flickr.NET, которую можно найти на CodePlex. Flickr.NET – это библиотека с открытым исходным кодом, есть версия для .NET Compact Framework. Вот ее мы и будем использовать.
Для начала Создаем новый проект для Smart Device на C#.
Затем распаковываем исходный код Flickr.NET в папку с созданным решением (рядом с папкой, в которой находится исходный код только что созданного проекта).
После этого добавляем проект FlickrNetCF в решение
Добавляем ссылку на проект FlickrNetCF в список зависимостей нашего приложения (с помощью Project -> Add Reference).
Ну вот, теперь можно работать.
Рисуем вот такую форму:

На форме:
- Поле ввода запроса для поиска изображений
- Кнопка поиска
- Список (ListView) для просмотра информации о найденных изображениях
- Кнопка открытия формы для просмотра полноразмерного изображения
Теперь можно заняться, собсьвенно, работой с Flickr. Для работы с сервисом в библиотеке FlickrNetCF есть класс Flickr. Для работы ему необходимы:
- Application Key
- Secret Key
Получить эти два ключа можно вот по этому адресу.
Создаем объект для работы с сервисом
using FlickrNet;
...
Flickr _flickr = new Flickr();
_flickr.ApiKey = "<здесь будет ваш API Key>";
_flickr.ApiSecret = "<здесь будет ваш Secret Key>";
Теперь нам неплохо бы обеспечить поиск изображений и отображение превью, а также информации об изображении. Загрузка превью – процесс длительный, поэтому обрабатывать информацию, полученную от сервиса будем в отдельном потоке:
Thread _downloadThread;
string _searchText = "";
...
private void StartDownloadingPreviws()
{
if (_downloadThread != null)
{
_downloadThread.Abort();
}
photoInfoListView.Items.Clear();
photoThumbnailList.Images.Clear();
_searchText = searchTextBox.Text;
_downloadThread = new Thread(new ThreadStart(DownloadPhotosDelegate));
_downloadThread.Start();
}
Для поиска изображений в классе Flickr предусмотрен метод PhotosSearchText()
, который в качестве параметра принимает строку поискового запроса. Именно этот метод мы и будем использовать для получения информации о найденных фотографиях. Метод PhotosSearchText()
возвращает объект класса Photos
, из которого мы можем получить всю информацию о найденных изображениях (свойство PhotoCollection
класса Photos
возвращает массив объектов Photo
, каждый из которых содержит полную информацию об одном изображении, например, название, ссылку на превью, ссылку на полноразмерное изображение и др.)
void DownloadPhotosDelegate()
{
try
{
Photos _photos = _flickr.PhotosSearchText(_searchText);
foreach (Photo photo in _photos.PhotoCollection)
{
MemoryStream photoStream = new MemoryStream();
WebRequest request = HttpWebRequest.Create(photo.SquareThumbnailUrl);
WebResponse response = request.GetResponse();
MemoryStream stream = new MemoryStream();
Stream responseStream = response.GetResponseStream();
int readCount = 0;
byte[] buffer = new byte[1024];
while ((readCount =
responseStream.Read(buffer, 0, buffer.Length)) > 0)
{
stream.Write(buffer, 0, readCount);
}
response.Close();
Bitmap bmp = new Bitmap(stream);
string originalURL = photo.LargeUrl;
string title = photo.Title;
Invoke(new AddItemDelegate(AddItemToList),
new object[] { bmp, title, originalURL})
}
}
catch (ThreadAbortException)
{
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Т.к. в .NET неглавный поток не может работать с элементами GUI, то добавление превью изображений в список нам необходимо делать в отдельном методе, который будет вызываться посредством Invoke():
Invoke(new AddItemDelegate(AddItemToList), new object[] { bmp, title, originalURL});
...
private delegate void AddItemDelegate(Bitmap bmp, string name, string originalURL);
Bitmap ResizeBitmap(Bitmap b, System.Drawing.Size size)
{
Bitmap result = new Bitmap(size.Width, size.Height);
using (Graphics g = Graphics.FromImage((Image)result))
g.DrawImage(b,
new Rectangle(0, 0, result.Width, result.Height),
new Rectangle(0, 0, b.Width, b.Height),
GraphicsUnit.Pixel);
return result;
}
void AddItemToList(Bitmap bmp, string name, string originalURL)
{
try
{
photoThumbnailList.Images.Add(bmp);
ListViewItem newItem = new ListViewItem(name);
newItem.ImageIndex = photoThumbnailList.Images.Count - 1;
newItem.Tag = originalURL;
photoInfoListView.Items.Add(newItem);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
ОК, с главной формой пока закончили. теперь приступим к созданию формы для просмотра полноразмерного изображения.
Добавляем в проект новую форму. На нее кладем Panel (Dock = Fill, AutoScroll = true), на Panel кладем PictureBox.
Теперь нам нужно обеспечить загрузку изображения в отдельном потоке. Подход приблизительно такой же как и в главной форме:
private Thread _downloader;
private string _imageURL = "";
Bitmap _sourceBitmap;
public string ImageURL
{
get
{
return _imageURL;
}
set
{
_imageURL = value;
}
}
public ImageViewForm()
{
InitializeComponent();
}
void OnImageDownloaded(Bitmap bmp)
{
_sourceBitmap = bmp;
imageBox.Image = bmp;
imageBox.Width = bmp.Width;
imageBox.Height = bmp.Height;
}
private delegate void ImageDownloadedDelegate(Bitmap bmp);
void DownloadImage()
{
try
{
do
{
if (ImageURL == null || ImageURL.Length == 0) break;
WebRequest request = HttpWebRequest.Create(ImageURL);
WebResponse response = request.GetResponse();
Bitmap bmp = new Bitmap(response.GetResponseStream());
response.Close();
Invoke(new ImageDownloadedDelegate(OnImageDownloaded),
new object[] { bmp });
}
while (false);
}
catch (ThreadAbortException)
{
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
public void StartDownloading()
{
_downloader = new Thread(new ThreadStart(DownloadImage));
_downloader.Start();
}
private void ImageViewForm_Closing(object sender, CancelEventArgs e)
{
if (_downloader != null)
{
_downloader.Abort();
}
}
Теперь пишем обработчик нажатия кнопки открытия формы просмотра полноразмерного изображения в главной форме
private void showPictureButton_Click(object sender, EventArgs e)
{
do
{
if (photoInfoListView.SelectedIndices.Count == 0) break;
ListViewItem item = photoInfoListView.Items[photoInfoListView.SelectedIndices[0]];
if (item == null) break;
string url = (item.Tag as string);
if (url == null || url.Length == 0) break;
ImageViewForm dlg = new ImageViewForm();
dlg.ImageURL = url;
dlg.StartDownloading();
dlg.ShowDialog();
}
while (false);
}
Ну вот, собственно и все. В результате мы получим вот такое приложение:


Исходный код тестового приложения, а также исполняемый файл можно скачать здесь.