Recommended

Skip Navigation LinksHome / Articles / View Article

Displaying geo-referenced Flickr images in Silverlight 4 using Bing Maps

+ Add to SilverlightShow Favorites
1 comments   /   posted by Marcel du Preez on Jun 25, 2010
(6 votes)
Categories: Tutorials , Samples , QuickStarts

Introduction

This tutorial will guide you through creating your own application to display geo-tagged Flickr images on a Bing Maps backdrop in Silverlight 4.

The components

Flickr Web Services

Flickr exposes a variety of services to access their database of public images, in REST (see this article), SOAP (read here) and RPC (here) formats. For more details, go to their API documentation. A detailed explanation of accessing RESTful services is outside the scope of this article, but, in essence is involves generating a url, downloading the result as a string (the Flickr REST service returns an XML file), and then parsing it to get the info we want.

Bing Maps

Bing released their Silverlight control SDK in November. We’ll be using version 1.0.1, which can be downloaded here. Download and install it.

Preparing

Both Flickr’s web services and Bing Maps web services (which the Bing Maps Control accesses for maps) require you to register an API key to identify who is accessing their services.

To apply for a Flickr API key, go here. For Bing Maps, go here.

Starting out

To start out, we’ll first setup a Silverlight page to display a map.

Create a new project in Blend4/VS2010. I’ll call mine BingFlickrSample. In the Silverlight project, add a reference to the Bing Maps DLL’s, located where you installed the Bing Maps SDK (default location is \Program Files\Bing Maps Silverlight Control).

To add a map to your page, add a namespace in your XAML file :

 1: xmlns:map="clr-namespace:Microsoft.Maps.MapControl;assembly=Microsoft.Maps.MapControl"

Add a map to your page, and set the API key using the CredentialsProvider property :

 1: <maps:Map CredentialsProvider="your key here" />

This should display a map of the world on your page :

The Bing Maps control provides a lot of functionality out of the box. You can zoom in/out using the left hand slider, pan using the top left pan controller, and switch between Road and Aerial views. To collapse the controls, click the << button.

 

Accessing the Flickr web services

We’ll be using two of the Flickr API’s methods :

  • photos.search (searches through the database with the arguments we specify), and
  • photos.geo.getlocation (gets the location of the specified photo)

Our application will allow the user to search for photos with a search string, and only return the results in the current map view. The current map views extents are exposed via the map’s BoundingRectangle property. This is what our url looks like :

 1: http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=YourAPIKeyHere&text=SearchStringHere&
 2:    bbox=MinLatitude,MinLongitude,MaxLatitude,MaxLongitude&per_page=10
 
An example of the returned XML can be found here.

In the url I’ve also included a per_page property, to limit the amount of results returned (10). In the sample application, the arguments are filled using the string.Format method. The MinLatitude, MinLongitude, MaxLatitude and MaxLongitude values are set to the map’s BoundingRectangle.West, BoundingRectangle.South, BoundingRectangle.East and BoundingRectangle.North properties respectively (refer to Wikipedia for a refresher on Latitudes and Longitudes).

To call the web service, we pass the url to a WebClient, set a handler for its DownloadStringCompleted event and call DownloadStringAsync :

 1: WebClient flickRService = new WebClient();
 2: flickRService.DownloadStringCompleted += 
 3:      new DownloadStringCompletedEventHandler(flickRService_DownloadStringCompleted);
 4: flickRService.DownloadStringAsync(new Uri(url));
 
In the DownloadStringCompleted, we need to parse the returned XML. By using the System.Xml.LINQ namespace, we can use LINQ to parse it into a packaged object, which I’ll call FlickrPhoto (originally from Brad Abrams) :
 1: public class FlickRPhoto
 2:     {
 3:         public string Id { get; set; }
 4:         public string Owner { get; set; }
 5:         public string Secret { get; set; }
 6:         public string Server { get; set; }
 7:         public string Farm { get; set; }
 8:         public string Title { get; set; }
 9:         public string ImageUrl
 10:         {
 11:             get
 12:             {
 13:                 return string.Format("http://farm{0}.static.flickr.com/{1}/{2}_{3}.jpg",
 14:                     Farm, Server, Id, Secret);
 15:             }
 16:         }
 17:  
 18:         public GeoLocation Location { get; set; }
 19:     }

 

The GeoLocation property is a simple container for two double properties :

 1: public class GeoLocation
 2:     {
 3:         public double Latitude { get; set; }
 4:         public double Longitude { get; set; }
 5:  
 6:         /// <summary>
 7:         /// Initializes a new instance of the GeoLocation class.
 8:         /// </summary>
 9:         public GeoLocation(double latitude, double longitude)
 10:         {
 11:             Latitude = latitude;
 12:             Longitude = longitude;
 13:         }
 14:  
 15:         public GeoLocation()
 16:         {
 17:  
 18:         }
 19:     }

The XML parsing is done with this code :

 1: IEnumerable<FlickRPhoto> Photos;
 2:  
 3: Photos = from photo in xmlPhotos.Element("rsp").Element("photos").Descendants().ToList()
 4:                      select new FlickRPhoto
 5:                      {
 6:                          Id = (string)photo.Attribute("id"),
 7:                          Owner = (string)photo.Attribute("owner"),
 8:                          Secret = (string)photo.Attribute("secret"),
 9:                          Server = (string)photo.Attribute("server"),
 10:                          Farm = (string)photo.Attribute("farm"),
 11:                          Title = (string)photo.Attribute("title"),
 12:                      };

 

Photos from Flickr are not returned with their geo-location by default, therefore we have to enumerate over all the returned photos, and request the location by calling photos.geo.getLocation on the web service :

 1: http://api.flickr.com/services/rest/?method=flickr.photos.geo.getLocation&api_key=YourAPIKeyHere&
 2:    photo_id=PhotoIDHere
 
An example of the returned XML can be found here.

 

Handling the parsing of the returned XML  is a bit different than the previous example. This call only returns one photo (if it is found), with its Location information. To parse it, we use :

 1: string photoID = (string)(from x in xmlGeoLoc.Element("rsp").Descendants().ToList() select x).
 2:    First().Attribute("id");
 
to get the Photo ID (the photo’s identifier on Flickr), and
 
 1: double Lat = Convert.ToDouble(xmlGeoLoc.Element("rsp").Descendants().
 2:    FirstOrDefault().Descendants().FirstOrDefault().Attribute("latitude").Value);
 3: double Lon = Convert.ToDouble(xmlGeoLoc.Element("rsp").Descendants().
 4:    FirstOrDefault().Descendants().FirstOrDefault().Attribute("longitude").Value);
 
to get the Latitude and Longitude values, and then add them as GeoLocation properties to the specific photo.

 

Showing it on the map

Now we have a list of photos, with their locations, and we can display them on the map. Add a Pushpin (a native class included in Microsoft.Maps.MapControl) to the map to visually indicate where the photo was taken :

 1: Pushpin pin = new Pushpin();
 2: pin.Tag = currentPhoto.Id;
 3: pin.Location = new Location(currentPhoto.Location.Latitude, currentPhoto.Location.Longitude);
 4: pin.MouseLeftButtonDown += new MouseButtonEventHandler(pin_MouseLeftButtonDown);
 5: mapMain.Children.Add(pin);

 

I add the photo’s ID as a Tag to the Pushpin, to have quick access to it in the Pushpin’s MouseLeftButtonDown event.

When over South Africa, and searching for the term “Fifa”, this is the result :

(Remember, only 10 results are being returned. Also, the zoom level may cause some Pushpins that are close to each other, look like only one)

I’ve added the MouseLeftButtonDown event handler on the Pushpin, to be able to view the actual photo at that location. In the event handler, I just get the photo’s ID from the Pushpin’s Taq property, pass the FlickrPhoto to a Silverlight Child Window (source code is attached), that displays the photo with an Image control :

 1: <Image x:Name="imgPhoto" />

 

This sets the Image control’s Source :

 1: imgPhoto.Source = new BitmapImage(new Uri(photo.ImageUrl));

 

The ImageUrl property is a calculated property on the FlickrPhoto class that combines arguments (farm, server, ID and secret) and builds a url to the photo.

And this, the result when click on one of the Pushpins :

SS3

Conclusion

This application demonstrates how to display geo-coded images on a map. In the next article, I will modify the interface to also allow you to upload photos to Flickr, and geo-tag them.

Ciao!
Marcel du Preez
marcel@inivit.com

Share


Comments

Comments RSS RSS
  • RE: Displaying geo-referenced Flickr images in Silverlight 4 using Bing Maps  

    posted by youth on Jun 26, 2010 17:12
    i love this tutorial. Very clear!!

Add Comment

 
 

   
  
  
   
Please add 2 and 6 and type the answer here:

Help us make SilverlightShow even better. Whether you'd like to suggest a change in the structure, content organization, section layout or any other aspect of SilverlightShow appearance - we'd love to hear from you! Need material (article, tutorial, or other) on a specific topic? Let us know and SilverlightShow content authors will work to have that prepared for you. (hide this)