Windows Phone 7 – Browsing your Photos via Bing Maps
2012-06-22 08:56
393 查看
A Technical Blog article. View original blog here.[^]
The Windows Phone 7 camera gives you the option to record the location where a picture was taken (under Settings => applications => pictures+camera). With this feature turned on, each application has their latitude, longitude and altitude
stored as part of the standard EXIF data. I thought it would be fun to combine the previous blog post I wrote on pushpin
clustering with the photos on my camera, to allow me to explore them via a Bing Maps control. With not much more than 100 lines of code I came up with an application which I think is a lot of fun to use.
that this class provides gives you access to Picture instances which have properties that allow you to access the width
/ height and a few other basic attributes. They also have methods that return streams which can be used to read the thumbnail and image data, however, they do not expose the picture location. This is ‘hidden’ within the EXIF data.
Fortunately there is a C# implementation of an EXIF decoder available on codeproject, which, with
a few tweaks by Tim Heuer works just fine within Silverlight for Windows Phone 7.
With this library, accessing the EXIF data is a one-liner:
Collapse | Copy
Code
The JpegInfo class exposes the raw EXIF geolocation data, which is detailed in the EXIF specification as being expressed as separate components
of degrees, minutes and seconds together with a reference direction (North / South, East / West). We can convert from the sexagesimal numeric system used in EXIF,
to the decimal system as follows:
Collapse | Copy
Code
with those that have geolocation data available being stored in a separate list:
Collapse | Copy
Code
When the pictures have all been analysed, a pushpin is created for each image which is then added to the clusterer
described in my previous blog post.
Collapse | Copy
Code
The template used for the pushpins simply renders the image thumbnail:
Collapse | Copy
Code
This makes use of a simple value converter which takes a
is used as the
Collapse | Copy
Code
The puhspin clusterer allows you to specify a separate template for clustered pushpins. The
a list of the
of images. The number of pictures in the cluster is rendered as a
Collapse | Copy
Code
The code that renders the last image is a bit cunning, it uses a value converter that performs a Linq style ‘last’ operations, extracting the last items from a collection of objects:
Collapse | Copy
Code
This feels quite neat to me
The clustered pins look like the following, which is a cluster of 5 images around Paris, with the stunning La Grande Arche de la Défense as
the image at the top of the cluster:
Despite its simplicity, I have had a lot of fun playing with this application. It has certainly encouraged me to take as many photos as possible whenever I go travelling.
You can download the full sourcecode here: PhotoBrowser.zip
Regards, Colin E.
This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)
The Windows Phone 7 camera gives you the option to record the location where a picture was taken (under Settings => applications => pictures+camera). With this feature turned on, each application has their latitude, longitude and altitude
stored as part of the standard EXIF data. I thought it would be fun to combine the previous blog post I wrote on pushpin
clustering with the photos on my camera, to allow me to explore them via a Bing Maps control. With not much more than 100 lines of code I came up with an application which I think is a lot of fun to use.
Here are all the photos on my phone, note the way the pushpins are clustered. | Here are a few pictures I took in New York, of the One World Trade Centre and the Stock Exchange. |
Here are some pictures around Europe, including one ofGergely Orosz waiting for his turn in the Edinburgh Marathon Relay. | And finally, some pictures I took whilst running aroundKielder Water during Kielder marathon. |
Accessing the EXIF data
You can access the photos on a WP7 device via the XNA MediaLibrary class. The interfacethat this class provides gives you access to Picture instances which have properties that allow you to access the width
/ height and a few other basic attributes. They also have methods that return streams which can be used to read the thumbnail and image data, however, they do not expose the picture location. This is ‘hidden’ within the EXIF data.
Fortunately there is a C# implementation of an EXIF decoder available on codeproject, which, with
a few tweaks by Tim Heuer works just fine within Silverlight for Windows Phone 7.
With this library, accessing the EXIF data is a one-liner:
Collapse | Copy
Code
JpegInfo info = ExifReader.ReadJpeg(picture.GetImage(), picture.Name);
The JpegInfo class exposes the raw EXIF geolocation data, which is detailed in the EXIF specification as being expressed as separate components
of degrees, minutes and seconds together with a reference direction (North / South, East / West). We can convert from the sexagesimal numeric system used in EXIF,
to the decimal system as follows:
Collapse | Copy
Code
private static double DecodeLatitude(JpegInfo info) { double degrees = ToDegrees(info.GpsLatitude); return info.GpsLatitudeRef == ExifGpsLatitudeRef.North ? degrees : -degrees; } private static double DecodeLongitude(JpegInfo info) { double degrees = ToDegrees(info.GpsLongitude); return info.GpsLongitudeRef == ExifGpsLongitudeRef.East ? degrees : -degrees; } public static double ToDegrees(double[] data) { return data[0] + data[1] / 60.0 + data[2] / (60.0 * 60.0); }
Analysing the images
When the application starts aBackgroundWorkeris used to read the EXIF data for all of the pictures in the phone’s media library,
with those that have geolocation data available being stored in a separate list:
Collapse | Copy
Code
BackgroundWorker bw = new BackgroundWorker(); bw.WorkerReportsProgress = true; // analyse the pictures that reside in the Media Library in a background thread bw.DoWork += (s, e) => { var ml = new MediaLibrary(); using (var pics = ml.Pictures) { int total = pics.Count; int index = 0; foreach (Picture picture in pics) { // read the EXIF data for this image JpegInfo info = ExifReader.ReadJpeg(picture.GetImage(), picture.Name); // check if we have co-ordinates if (info.GpsLatitude.First() != 0.0) { _images.Add(new LocatedImage() { Picture = picture, Lat = DecodeLatitude(info), Long = DecodeLongitude(info) }); } // report progress back to the UI thread string progress = string.Format("{0} / {1}", index, total); bw.ReportProgress((index * 100 / total), progress); index++; } } }; // update progress on the UI thread bw.ProgressChanged += (s, e) => { string title = (string)e.UserState; ApplicationTitle.Text = title; }; bw.RunWorkerAsync(); // when analysis is complete, add the pushpins bw.RunWorkerCompleted += (s, e) => { ApplicationTitle.Text = ""; AddPushpins(); };
When the pictures have all been analysed, a pushpin is created for each image which is then added to the clusterer
described in my previous blog post.
Collapse | Copy
Code
private void AddPushpins() { List<Pushpin> pushPins = new List<Pushpin>(); // create a pushpin for each picture foreach (var image in _images) { Location location = new Location() { Latitude = image.Lat, Longitude = image.Long }; Pushpin myPushpin = new Pushpin() { Location = location, DataContext = image, Content = image, ContentTemplate = this.Resources["MarkerTemplate"] as DataTemplate }; pushPins.Add(myPushpin); } // add them to the map via a clusterer var clusterer = new PushpinClusterer(map, pushPins, this.Resources["ClusterTemplate"] as DataTemplate); }
The template used for the pushpins simply renders the image thumbnail:
Collapse | Copy
Code
<DataTemplate x:Key="MarkerTemplate"> <Border BorderBrush="White" BorderThickness="1"> <Image Source="{Binding Picture, Converter={StaticResource PictureThumbnailConverter}}" Width="80" Height="80"/> </Border> </DataTemplate>
This makes use of a simple value converter which takes a
Pictureinstance and converts it into a
BitmapImagewhich
is used as the
Sourcefor the image:
Collapse | Copy
Code
public class PictureThumbnailConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { Picture picture = value as Picture; BitmapImage src = new BitmapImage(); src.SetSource(picture.GetThumbnail()); return src; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return null; } }
The puhspin clusterer allows you to specify a separate template for clustered pushpins. The
DataContextfor this template is
a list of the
DataContextsof the clustered pins that it represents. For this application I created a template which renders what looks like a ‘stack’
of images. The number of pictures in the cluster is rendered as a
TextBlockand the last image in the cluster rendered.
Collapse | Copy
Code
<DataTemplate x:Key="ClusterTemplate"> <Grid Width="75" Height="75"> <Canvas> <Border Style="{StaticResource FakePhoto}" Canvas.Left="0" Canvas.Top="0"/> <Border Style="{StaticResource FakePhoto}" Canvas.Left="5" Canvas.Top="5"/> <Border BorderBrush="White" BorderThickness="1" Canvas.Left="10" Canvas.Top="10" DataContext="{Binding Path=., Converter={StaticResource LastConverter}}"> <Image Source="{Binding Picture, Converter={StaticResource PictureThumbnailConverter}}" Width="60" Height="60"/> </Border> <TextBlock Text="{Binding Count}" Opacity="0.5" Canvas.Left="25" Canvas.Top="15" FontSize="35"/> </Canvas> </Grid> </DataTemplate> <Style TargetType="Border" x:Key="FakePhoto"> <Setter Property="Width" Value="60"/> <Setter Property="Height" Value="60"/> <Setter Property="BorderBrush" Value="White"/> <Setter Property="Background" Value="Black"/> <Setter Property="BorderThickness" Value="1"/> </Style>
The code that renders the last image is a bit cunning, it uses a value converter that performs a Linq style ‘last’ operations, extracting the last items from a collection of objects:
Collapse | Copy
Code
public class LastConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { IList enumerable = value as IList; return enumerable.Cast<object>().Last(); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return null; } }
This feels quite neat to me
The clustered pins look like the following, which is a cluster of 5 images around Paris, with the stunning La Grande Arche de la Défense as
the image at the top of the cluster:
Despite its simplicity, I have had a lot of fun playing with this application. It has certainly encouraged me to take as many photos as possible whenever I go travelling.
You can download the full sourcecode here: PhotoBrowser.zip
Regards, Colin E.
License
This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)
相关文章推荐
- Windows Phone开发(22):启动器与选择器之BingMapsDirectionsTask 转:http://blog.csdn.net/tcjiaan/article/details/7393099
- How to download Bing maps to your hard disk
- Windows Phone 7 Quick Tip: How to use Bing Maps in XNA games
- Windows Phone开发(22):启动器与选择器之BingMapsDirectionsTask .
- Windows Phone开发(22):启动器与选择器之BingMapsDirectionsTask
- Windows Phone开发(22):启动器与选择器之BingMapsDirectionsTask
- Windows Phone开发(22):启动器与选择器之BingMapsDirectionsTask
- Windows Phone开发(22):启动器与选择器之BingMapsDirectionsTask
- App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app’s Info.plist file
- SSH: Secure Browsing Via SOCKS Proxy April 10, 2009
- How to make your own maps/tiles
- Speed up your Internet browsing on Linux with a DNS Cache server
- GIS理论(墨卡托投影、地理坐标系、地面分辨率、地图比例尺、Bing Maps Tile System)
- Launching Your Own Application via a Custom URL Scheme
- 微软发布为Windows 8 Metro程序使用Bing Maps SDK
- GIS理论(墨卡托投影、地理坐标系、地面分辨率、地图比例尺、Bing Maps Tile System)
- Add sharing to your app via UIActivityViewController
- 太牛了!街景转换广泛使用 3D 来自于微软 Bing! Maps
- Draggable Pushpins using Bing Maps Silverlight Control
- GIS理论(墨卡托投影、地理坐标系、地面分辨率、地图比例尺、Bing Maps Tile System)