Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting GPS data from an image's EXIF in C#

I am developing a system that allows for an image to be uploaded to a server using ASP.NET C#. I am processing the image and all is working great. I have managed to find a method that reads the Date Created EXIF data and am parsing it as a DateTime. That works great too.

I am now trying to read GPS data from the EXIF. I am wanting to capture the Latitude and Longitude figures.

I am using this list as a reference to the EXIF data (using the numbers for the property items) http://www.exiv2.org/tags.html

Here is the method to capture the date created (which works).

public DateTime GetDateTaken(Image targetImg) {     DateTime dtaken;      try     {         //Property Item 306 corresponds to the Date Taken         PropertyItem propItem = targetImg.GetPropertyItem(0x0132);          //Convert date taken metadata to a DateTime object         string sdate = Encoding.UTF8.GetString(propItem.Value).Trim();         string secondhalf = sdate.Substring(sdate.IndexOf(" "), (sdate.Length - sdate.IndexOf(" ")));         string firsthalf = sdate.Substring(0, 10);         firsthalf = firsthalf.Replace(":", "-");         sdate = firsthalf + secondhalf;         dtaken = DateTime.Parse(sdate);     }     catch     {         dtaken = DateTime.Parse("1956-01-01 00:00:00.000");     }     return dtaken; } 

Below is my attempt at doing the same for GPS..

public float GetLatitude(Image targetImg) {     float dtaken;      try     {         //Property Item 0x0002 corresponds to the Date Taken         PropertyItem propItem = targetImg.GetPropertyItem(2);          //Convert date taken metadata to a DateTime object         string sdate = Encoding.UTF8.GetString(propItem.Value).Trim();         dtaken = float.Parse(sdate);     }     catch     {         dtaken = 0;     }     return dtaken; } 

The value that's coming out and into sdate is "5\0\0\0\0\0\0l\t\0\0d\0\0\0\0\0\0\0\0\0\0"

And that is coming from an image that was taken by an iPhone 4 which does carry the GPS EXIF data.

I know there are classes out there that do this but would prefer to write my own - I am open to suggestions though :-)

Thanks in advance.

like image 592
tmutton Avatar asked Feb 13 '11 11:02

tmutton


People also ask

How do I get coordinates from EXIF data?

In Windows, all you have to do is right-click a picture file, select “Properties,” and then click the “Details” tab in the properties window. Look for the Latitude and Longitude coordinates under GPS.

Does EXIF data include GPS?

Exchangeable Image File Format (EXIF) is a standard that defines specific information related to an image or other media captured by a digital camera. It is capable of storing such important data as camera exposure, date/time the image was captured, and even GPS location.

Does metadata include GPS coordinates?

This information, known as “metadata,” might include items like the GPS coordinates of the photo's location, the date and time it was taken, the camera type and shutter settings, and the software used to edit the photo. Many digital photographers don't realize that their photos might carry this metadata.


1 Answers

According to the link posted above by tomfanning, property item 0x0002 is the latitude expressed as a PropertyTagTypeRational. The rational type is defined as...

Specifies that the value data member is an array of pairs of unsigned long integers. Each pair represents a fraction; the first integer is the numerator and the second integer is the denominator.

You are trying to parse it as a string when it's actually just a series of bytes. According to the above, there should be 3 pairs of 32-bit unsigned integers packed into that byte array, which you can retrieve using the following:

uint degreesNumerator   = BitConverter.ToUInt32(propItem.Value, 0); uint degreesDenominator = BitConverter.ToUInt32(propItem.Value, 4); uint minutesNumerator   = BitConverter.ToUInt32(propItem.Value, 8); uint minutesDenominator = BitConverter.ToUInt32(propItem.Value, 12); uint secondsNumerator   = BitConverter.ToUInt32(propItem.Value, 16); uint secondsDenominator = BitConverter.ToUInt32(propItem.Value, 20); 

What you do with these values after you've got them is for you to work out :) Here's what the docs say:

Latitude is expressed as three rational values giving the degrees, minutes, and seconds respectively. When degrees, minutes, and seconds are expressed, the format is dd/1, mm/1, ss/1. When degrees and minutes are used and, for example, fractions of minutes are given up to two decimal places, the format is dd/1, mmmm/100, 0/1.

like image 175
Jon Grant Avatar answered Sep 17 '22 17:09

Jon Grant