TASSOGRAPHY

Photography and More
by Ben Vincent
TransparentPadder

Share On FacebookShare On Facebook
 
Ben's Blog (71)Ben's Blog (71)
Development (16)Development (16)
Lisa's Blog (6)Lisa's Blog (6)
 
Show All (94)Show All (94)
 
Jun 2010 (4)Jun 2010 (4)
May 2010 (2)May 2010 (2)
Apr 2010 (7)Apr 2010 (7)
Mar 2010 (5)Mar 2010 (5)
Feb 2010 (1)Feb 2010 (1)
Jan 2010 (3)Jan 2010 (3)
Nov 2009 (8)Nov 2009 (8)
Oct 2009 (4)Oct 2009 (4)
Sep 2009 (4)Sep 2009 (4)
Jul 2009 (6)Jul 2009 (6)
Jun 2009 (5)Jun 2009 (5)
May 2009 (7)May 2009 (7)
Mar 2009 (1)Mar 2009 (1)
Feb 2009 (5)Feb 2009 (5)
Jan 2009 (7)Jan 2009 (7)
Dec 2008 (6)Dec 2008 (6)
Oct 2008 (3)Oct 2008 (3)
Sep 2008 (3)Sep 2008 (3)
Aug 2008 (9)Aug 2008 (9)
Jul 2008 (3)Jul 2008 (3)
Jun 2008 (1)Jun 2008 (1)
 
Show All (94)Show All (94)
 
RSS & Atom FeedsRSS & Atom Feeds




TransparentPadder
Home Job Runner Image Usage Tracker Image Blog   |   Highlights   |   Photography   |   Contact   |   About    Atom & RSS Feeds  

Reading Geotagging in Photos Using Windows Imaging Component by Ben Vincent

In this blog I’m going to explain how Geotagging metadata can be read and written using Windows Imaging Component.

First lets look at all the queries. These are the common ones, there are plenty more but I have not found any immediate need to use them.

// GPS Altitude
public static readonly string GpsAltitude = "/app1/ifd/Gps/subifd:{uint=6}";

// 0 = Above sea level, 1 = Below sea level
public static readonly string GpsAltitudeRef = "/app1/ifd/Gps/subifd:{uint=5}";

// ASCII count 'N' indicates north latitude, and 'S' is south latitude
public static readonly string GpsLatitudeRef = "/app1/ifd/Gps/subifd:{uint=1}";
public static readonly string GpsLatitude = "/app1/ifd/Gps/subifd:{uint=2}";

// ASCII 'E' indicates east longitude, and 'W' is west longitude
public static readonly string GpsLongitudeRef = "/app1/ifd/Gps/subifd:{uint=3}";
public static readonly string GpsLongitude = "/app1/ifd/Gps/subifd:{uint=4}";

// Indicates the Gps measurement mode. '2' means two-dimensional measurement and '3' means three-dimensional
public static readonly string GpsMeasureMode = "/app1/ifd/Gps/subifd:{uint=10}";

// A character string recording the name of the method used for place finding.
public static readonly string GpsProcessingMethod = "/app1/ifd/Gps/subifd:{uint=27}";

// Byte sequence 2, 2, 0, 0 to indicate version 2.2
public static readonly string GpsVersionID = "/app1/ifd/Gps/subifd:{uint=0}";

// GPSTimeStamp rational64u[3]
public static readonly string GpsTimeStamp = "/app1/ifd/Gps/subifd:{uint=7}";
public static readonly string GpsDateStamp = "/app1/ifd/Gps/subifd:{uint=29}";

First lets cover the basics of retrieving the GPS data using my ReadMetadata method.

// Grab copy of BitmapMetadata
BitmapMetadata bitmapMetadata = this.ReadMetadata(inputFile);

// Grab the GpsTimeStamp
string gpsTimeStamp = bitmapMetadata.GetQuery("/app1/ifd/Gps/subifd:{uint=7}").ToString();

Simple as that, but if you run this code you’ll see the value make no sense at all. So we’ll go through each of property in turn, starting with the easy ones.

GpsMeasureMode

This value has two possible values the number 2 or 3. They represents the number of dimensions for the GPS coordinates. I use 3 when I get the Geotagging data from a GPS because it includes the Altitude. And 2 when I’m manually adding the data and I don’t have an altitude.

GpsProcessingMethod

This is a string value and there appears to be no standard for possible values. I use it to store the source, which is the make & model of the GPS tracker or Bing Maps APIs.

GpsVersionID

This is a string and is always set to 2200, meaning version 2.2.

GpsAltitude and GpsAltitudeRef

Now it starts to get complicated. The GpsAltitudeRef is either 0 for above sea level or 1 for below. The GpsAltitude is a rational representing the altitude which is positive or negative based on the GpsAltitudeRef.

Here’s how you go about reading the Altitude and converting it into a double. For more details on reading and writing Rationals check out this blog.

// Grab copy of BitmapMetadata
BitmapMetadata bitmapMetadata = this.ReadMetadata(inputFile);

// Grab the GpsAltitudeRef
string altitudeRef = bitmapMetadata.GetQuery("/app1/ifd/Gps/subifd:{uint=5}").ToString();

// Grab GpsAltitude as a ulong
ulong rational = (ulong)bitmapMetadata.GetQuery("/app1/ifd/Gps/subifd:{uint=6}");

// Now shift & mask out the upper and lower parts to get the numerator and the denominator
uint numerator = (uint)(rational & 0xFFFFFFFFL);
uint denominator = (uint)((rational & 0xFFFFFFFF00000000L) >> 32);

// And finally turn it into a double
double altitude = Math.Round(Convert.ToDouble(numerator) / Convert.ToDouble(denominator), 3);

When debugging this you should some something like this.

 image

Clearly 4294967313464 makes no sense but once you rip out the numerator and denominator you get 17464/1000 which is 17.464 meters. With an altitudeRef of 1 it really means -17.464 meters.

GpsLatitudeRef, GpsLatitude, GpsLongitudeRef and GpsLongitude

Now on to the meat of the data, and also the hardest to work with. The Latitude and Longitude are stored as three rationals representing the hours, minutes and seconds. Each also has a Ref field that represents North\South or East\West for their corresponding fields.

// Grab copy of BitmapMetadata
BitmapMetadata bitmapMetadata = this.ReadMetadata(inputFile);

// Grab the GpsLatitudeRef
// 'N' indicates north latitude, and 'S' is south latitude
string latitudeRef = bitmapMetadata.GetQuery("/app1/ifd/Gps/subifd:{uint=1}").ToString();

// Grab GpsLatitude as a ulong array
ulong[] rational = (ulong[])bitmapMetadata.GetQuery("/app1/ifd/Gps/subifd:{uint=2}");
double[] latitude = new double[3];

// Read and convert each of the rationals into a double
for (int i = 0; i < 3; i++)
{
    // Now shift & mask out the upper and lower parts to get the numerator and the denominator
    uint numerator = (uint)(rational[i] & 0xFFFFFFFFL);
    uint denominator = (uint)((rational[i] & 0xFFFFFFFF00000000L) >> 32);

    latitude[i] = Math.Round(Convert.ToDouble(numerator) / Convert.ToDouble(denominator), 3);
}

The output from this should look something like this:

image

This represents the Latitude 37° 48.417′ N. Longitude will look much the same but with E or W for the Ref field.

GpsDateStamp and GpsTimeStamp

These two values store when the GPS coordinate was captured. The GPSDateStamp is a simple string with a semi-colon as a delimiter. Just like Latitude, GPSTimeStamp is stored as three rationals, representing hours, minutes & seconds. Here’s the debug output for 10th Sept 2009 at 9:46pm.

 image

Well that covers reading GPS data. You can find my entire library for reading & writing metadata, Fotofly, on Codeplex.


Posted: Sat, 7 Nov 2009, 01:32:35 GMT Updated: Sat, 7 Nov 2009, 01:36:44 GMT by Ben Vincent
Category: Development
Tags: Windows Imaging Component, XMP, Exif, Geotagging, Fotofly


Fotofly v0.1 available for Download on Codeplex by Ben Vincent
After several years of evolving my photo metadata code I’m finally ready to put it online. Being the nice corporate citizen that I am, I’m using CodePlex and you can find Fotofly here for download. My somewhat lofty description of the project is: “A comprehensive C# library for reading, manipulating and writing metadata stored in jpg photos using WPF and the Windows Imaging Component. Includes support for Windows Live Photo Gallery People Tags, GPS Coordinates and most EXIF, XMP & IPTC properties.” Hopefully I’ll get lots of downloads and feedback to help improve it further.     [Read More]

Posted: Fri, 6 Nov 2009, 09:04:11 GMT Updated: Fri, 6 Nov 2009, 09:07:15 GMT by Ben Vincent


Reading and Creating Exif Rationals by Ben Vincent
Quite why Jeida who created Exif decided to use Rationals is beyond me but they did so you have to work with them if you’re playing with jpg metadata. In this blog post I’ll share my Rational class so you don’t have to go through all the pain I went through in creating it. It’s amusingly short now I look at it here but it took way too long to work it out. The class has two constructors, one for the value you’ve retrieved from BitmapMetadata, the second when you’re creating your own rationals.   [Read More]

Posted: Fri, 6 Nov 2009, 05:51:43 GMT Updated: Fri, 6 Nov 2009, 09:05:23 GMT by Ben Vincent


Basic Editing of Photo Metadata Using Windows Imaging Component by Ben Vincent
In my previous posts I’ve provided examples on using Windows Imaging Component to Read & Write jpg metadata. In this post I’ll explain how to use ContainsQuery, GetQuery, SetQuery and RemoveQuery. As an added bonus I’m going to use the IPTC address fields as my example. Whilst BitmapMetadata does provide some standard properties like Subject and Title, it is far from comprehensive.   [Read More]

Posted: Thu, 5 Nov 2009, 05:09:10 GMT Updated: Thu, 5 Nov 2009, 05:25:28 GMT by Ben Vincent


Writing Photo Metadata Using Windows Imaging Component by Ben Vincent
In this blog I’m going to build on my previous posting on Reading Metadata and explain how to write metadata stored in a jpg file using Windows Imaging Component. You can find all my blogs on Windows Imaging Component here. If you want to change any of the metadata, the first thing you have to do is make sure there’s room for your changes. This is done by adding padding to the metadata.   [Read More]

Posted: Wed, 4 Nov 2009, 05:06:53 GMT Updated: Wed, 4 Nov 2009, 05:42:37 GMT by Ben Vincent


Reading Photo Metadata Using Windows Imaging Component by Ben Vincent
I still see a lot of questions on the Internet and at work on how to read (& write) metadata in Photos. There are plenty of examples out there but they all appear to have some pitfalls. To be quite honest, the code I’ve been using for a number of years now is mature enough that it solves almost all the problems I’ve seen. This blog is the first in a series that document how to read (this blog), write and manipulate photo metadata.   [Read More]

Posted: Tue, 3 Nov 2009, 07:37:33 GMT Updated: Wed, 4 Nov 2009, 05:42:15 GMT by Ben Vincent


Using WIC & C# to read Windows Live Photo Gallery’s People Tags by Ben Vincent
In my last posting I talked about how Windows Live Photo Gallery (WLPG) stores People tags in XMP. In this post I’m going to extend the Windows Imaging Component code from Robert Wlodarczyk’s Blog to read the data. The code is pretty simple to use, just make sure you have PresentationCore registered in your project and the System.Windows.Media.Imaging namespace.     [Read More]

Posted: Fri, 16 Jan 2009, 20:08:45 GMT by Ben Vincent


Understanding how Windows Live Photo Gallery’s People Tags are Stored by Ben Vincent
Since writing Tassography.com tags have been an important part of my workflow. For as long as I can remember I have been using Microsoft’s Digital Image Pro 2006. With the release of the new version of Windows Live Photo Gallery (WLPG), I took this Christmas the time to switch over and take advantage of some of the cool new features. The most compelling new feature for me is the new people tagging capabilities.   [Read More]

Posted: Thu, 15 Jan 2009, 22:17:48 GMT by Ben Vincent


Copying Jpeg Metadata using C# and Windows Imaging Component by Ben Vincent
It’s a scenario I keep finding myself in, I have two copies of the same photo but I want all metadata changes from one file in the other. For example, I want update my backup with changes I’ve made to metadata but don’t want to touch the source image, or I have the original and a small version of the same file. I haven’t found any reliable way to do this, so I finally sat down and wrote my own using plenty of excellent data on Robert Wlodarczyk’s Blog and the Windows Imaging Component. First, let’s look at the metadata stored in my two files using WICExplorer:     [Read More]

Posted: Sun, 11 Jan 2009, 03:20:23 GMT Updated: Sun, 11 Jan 2009, 08:12:46 GMT by Ben Vincent


TransparentPadder TransparentPadder TransparentPadder

Tweet  Ben - Cool! A nice end to the week, my mum was waiting for me in St Louis, she kept it a secret!

(Updated: Fri, 30 Jul 2010, 23:10:30)

Alcatraz . American Express . Amusing Photos . ASP.Net MVC . Australia . Bing . Blue Angels . BMi . Breathe Magazine . British Food . British Virgin Islands . California Highway Patrol . Camping . Canada . Christmas . Christmas Tree . Cleaner Shrimp . codeplex . Cooking . Coral Sea . Diving . Dragonlance . Engagement . Exif . Expedia . Facebook . Fish Tank . Flying . Food . Fotofly . Geotagging . Golden Gate National Recreation Area . Google . Gordon Ramsay . Hotmail . IPTC . Michelin Star . Microsoft . Microsoft Giving Campaign . Monterey Bay Aquarium . Mountain Biking . Nudibranch . San Francisco . Search Engine Optimzation (SEO) . Ship Wrecks . Silverlight . Starbucks . Tassography . The Sea Nettle Jelly . TransRockies . TV Commercial . United Airlines . Usage . Windows 7 . Windows Imaging Component . Windows Live . Windows Live Calendar . Windows Live Photo Gallery . Wineries . XMP


This website, all photography & other content is Copyright © Ben Vincent. Unauthorised use of images is strictly prohibited.
Catalog Last Updated: Mon, 19 Jul 2010, 22:48:43    |   Version v4.0.3861.38195
Powered by
Fotofly Logo