Channels ▼


Building Google Map Mashups in .NET

System Overview and Design

This application is made up of six main classes:

  • GeoMapperForm
  • ExifForm
  • ImageDialog
  • ImageViewer
  • ThumbnailController
  • ThumbnailFlowLayoutPanel

The Helper Classes include:

  • Configurator
  • CountryInfo
  • LatLongConversion

Figure 1 depicts these classes and their relationships.

[Click image to view at full size]
Figure 1: GeoMapper Classes and their relationships.

GeoMapperForm is the main point of entry into the application. The Window Form components that make up the main window are Figure 2.

[Click image to view at full size]
Figure 2: Window Form Components in the GeoMapper Window.

Configuration information is read on GeoMapperForm() object instantiation. I utilize the ConfigurationManager in the helper class, Configurator, to read custom information from an application configuration file. The format of this configuration file is:

<?xml version="1.0" encoding="utf-8" ?>
    <add key="GoogleMapKey" value="Your Google Maps API Key here" />
    <add key="WorldCountriesKey" value="c:\country.txt" />
    <add key="AppKey" value="C:\exiv2\exiv2.exe"/>

The configuration file name conforms to the following naming convention:


The value associated with a particular key is retrieved by calling:


where the key is the argument passed to the Get() method. The values associated with the definition of the keys in the configuration file has the following denotations:

  • GoogleMapKey, your unique google map key when you sign up for the Google Maps API
  • WorldCountriesKey, the location and name of a "country" file containing a list of countries and their three letter codes
  • AppKey, the name and location of the exiv2 executable

The thumbnail view of all the images from the image folder appears in the ThumbnailFlowLayoutPanel. The user-selected image is shown in the PictureBox component. The TextBox area will display the extracted metadata of the selected image. If the selected image contains GPS location data, a street map view of the selected image will be displayed in the embedded browser (WebBrowser) window. The embedded browser will be empty if the selected image does not contain GPS information. GPS information can be added to images via the drop down menus; likewise image directory location selection is done via the drop-down menu.

EXIF metadata extraction is achieved using the ExifLibrary for .NET. An ExifFile object is first created via the static method call:

ExifFile file = ExifFile.Read(filename);

where filename is the selected thumbnail image. The various captured camera properties are retrieved via an indexed property. To retrieve the image exposure time, I index into the ExifFile object created earlier as follows:


Retrieving GPS location data follows the same rule. However, since not all cameras are equipped with GPS receivers, the GPS location data may not embedded within the EXIF metadata. In this case, I will have to check if the ExifFile object contains the GPS-related keys:

if (file.Properties.ContainsKey(ExifTag.GPSLatitude) &&

Only if this statement evaluates to True do I retrieve the latitude and longitude values and display the street map. Latitude and longitude are recovered as follows:

GPSLatitudeLongitude latitiude = file.Properties[ExifTag.GPSLatitude] as GPSLatitudeLongitude;

EXIF GPS data are stored in Sexagesimal format (i.e. base 60, degrees, minutes and seconds). This has to be converted to decimal format. This is where the helper class, LatLongConversion, comes in. Once the GPS data has been converted to decimal format, a webservice request is made to Google Maps using the helper method:

doDisplayGoogleMap(latitude, longitude)

If the Web Service request is successful, the street map will be displayed in the embedded web browser component. To display the street map in the embedded browser, I navigate to this URL address<latitude>,<longitude>&key=<GoogleMapAPIKey>&output=embed via the Navigate() method of the WebBrowser component. The Google Map API key is required. It lets you embed Google Maps in your web pages. The key can be obtained from the Google Map API Key. The output=embed (key,value) pair causes the side panel to be removed.

For images that do not contain embedded GPS location information, this application lets users retrieve GPS location data via Google Maps Web Services by passing the URL<completeAddress>&output=csv&key=<GoogleMapAPIKey> to the WebClient DownloadString() method. The complete address would consists of the concatenation of address, postal code, and country name.

The country names and three-letter country codes are read from a file and stored in the helper class, CountryInfo. Adding in the postal code would give an increased level of accuracy to the GPS location returned. For more information on the (key, value) parameters for this URL, refer to Google Maps API Service. The output of this URL service is csv (comma separated value, which is the default) and the returned value has the syntax:status,accuracy,latitude,longitude. If this geocoding request is successful, the latitude, longitude results are then converted to sexagesimal format for display purposes.

Obtaining altitude information via a WebService call to<elevation_model>?lat={0}&lng={1} is based on the same principle. Here the supplied elevation model can be either Global Topographic Data (GTOPO30) or Shuttle Radar Topography Mission (SRTM3) depending on the user selection. The resulting altitude value is returned as a string whose unit is in meters.

The latitude, longitude data returned from the Google Maps WebService request can then be embedded into the selected image. I use the command-line utility Exiv2 for this. This call is encapsulated within the method:

runExiv2Cmd(string appName, string appArgs)

A new Process() object (ProcessObj) is first instantiated. The application to be invoked (in this case, exiv2.exe) and its arguments are then associated with the Process object. To ensure that no DOS command window appear, I have to set the two attributes of the Process object (UseShellExecute and CreateNoWindow):

ProcessObj.StartInfo.UseShellExecute = false;
ProcessObj.StartInfo.CreateNoWindow = true;

The process is then started by calling the Start() method. After the process has started, I have to call the method, WaitForExit(), to wait for the process to exit. Finally the output (if any) is read from the DOS application by making a call to ReadToEnd().

Related Reading

More Insights

Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.