Skip to content

Instantly share code, notes, and snippets.

@nmfzone
Forked from 5342/Program.cs
Created October 18, 2015 14:57
Show Gist options
  • Save nmfzone/d9fd06ba32b6a51fa356 to your computer and use it in GitHub Desktop.
Save nmfzone/d9fd06ba32b6a51fa356 to your computer and use it in GitHub Desktop.
Quick hack to find and extract GPS exif data from all jpg files in a given path
using System;
using System.IO;
using System.Drawing;
using System.Diagnostics;
using System.Collections.Generic;
namespace LocationExtractor
{
/// <summary>
/// Version 0.0 Initial version, This was hacked together over a few beers, and is no way complete or correct, it just accomplished the task required at the time.
/// version 0.1 Used Image.FromStream as aposed to Image.FromFile it caused some strange errors opening some files
/// Added some extra error checking on opening images and for zero denominator
/// </summary>
class Program
{
static void Main(string[] args)
{
if(args.Length != 1 || !Directory.Exists(args[0]))
{
Console.WriteLine("Usage\r\nLocationExtractor path");
return;
}
ExtractData(args[0]);
Console.ReadLine();
}
private static void ExtractData(string folder)
{
try
{
foreach (var file in Directory.GetFiles(folder))
{
if (file.ToLower().EndsWith(".jpg") || file.ToLower().EndsWith(".jpeg"))
{
ExtractLocation(file);
}
}
foreach (var directory in Directory.GetDirectories(folder))
{
ExtractData(directory);
}
}
catch (UnauthorizedAccessException) { /*Ignore*/} // Stuff we do not have access to
catch (DirectoryNotFoundException) { /*Ignore*/} // Symbolic links that are invalid
}
private static void ExtractLocation(string file)
{
if (file.ToLower().EndsWith("jpg") || file.ToLower().EndsWith("jpeg"))
{
Image image = null;
try
{
Console.Title = file;
try
{
FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read);
image = Image.FromStream(fs);
}
catch (Exception ex)
{
Console.WriteLine("Error opening {0} image may be corupted, {1}", file, ex.Message);
return;
}
// GPS Tag Names
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/GPS.html
// Check to see if we have gps data
if (Array.IndexOf<int>(image.PropertyIdList, 1) != -1 &&
Array.IndexOf<int>(image.PropertyIdList, 2) != -1 &&
Array.IndexOf<int>(image.PropertyIdList, 3) != -1 &&
Array.IndexOf<int>(image.PropertyIdList, 4) != -1)
{
string gpsLatitudeRef = BitConverter.ToChar(image.GetPropertyItem(1).Value, 0).ToString();
string latitude = DecodeRational64u(image.GetPropertyItem(2));
string gpsLongitudeRef = BitConverter.ToChar(image.GetPropertyItem(3).Value, 0).ToString();
string longitude = DecodeRational64u(image.GetPropertyItem(4));
Console.WriteLine("{0}\t{1} {2}, {3} {4}", file, gpsLatitudeRef, latitude, gpsLongitudeRef, longitude);
}
}
catch (Exception ex) { Console.WriteLine("Error processign {0} {1}", file, ex.Message); }
finally
{
if(image != null) image.Dispose();
}
}
}
private static string DecodeRational64u(System.Drawing.Imaging.PropertyItem propertyItem)
{
uint dN = BitConverter.ToUInt32(propertyItem.Value, 0);
uint dD = BitConverter.ToUInt32(propertyItem.Value, 4);
uint mN = BitConverter.ToUInt32(propertyItem.Value, 8);
uint mD = BitConverter.ToUInt32(propertyItem.Value, 12);
uint sN = BitConverter.ToUInt32(propertyItem.Value, 16);
uint sD = BitConverter.ToUInt32(propertyItem.Value, 20);
decimal deg;
decimal min;
decimal sec;
// Found some examples where you could get a zero denominator and no one likes to devide by zero
if (dD > 0) { deg = (decimal)dN / dD; } else { deg = dN; }
if (mD > 0) { min = (decimal)mN / mD; } else { min = mN; }
if (sD > 0) { sec = (decimal)sN / sD; } else { sec = sN; }
if (sec == 0) return string.Format("{0}° {1:0.###}'", deg, min);
else return string.Format("{0}° {1:0}' {2:0.#}\"", deg, min, sec);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment