You will need to assign the proper EXIF tags. I ran into this a while back and found a solution I liked. Here is the code for it:
There is of course libraries too, but this if all you need is geo this is pretty light weight.
using System.Drawing;
using System.Drawing.Imaging;
void Main()
{
//How to use methods below
Geotag(new Bitmap(@"D:\test.jpg"), 88, -169) // image location, latitude, longitude
.Save(@"D:\geotaggedTest.jpg", ImageFormat.Jpeg);
}
// You can define other methods, fields, classes and namespaces here
static Image Geotag(Image original, double lat, double lng)
{
// These constants come from the CIPA DC-008 standard for EXIF 2.3
const short ExifTypeByte = 1;
const short ExifTypeAscii = 2;
const short ExifTypeRational = 5;
const int ExifTagGPSVersionID = 0x0000;
const int ExifTagGPSLatitudeRef = 0x0001;
const int ExifTagGPSLatitude = 0x0002;
const int ExifTagGPSLongitudeRef = 0x0003;
const int ExifTagGPSLongitude = 0x0004;
char latHemisphere = 'N';
if (lat < 0)
{
latHemisphere = 'S';
lat = -lat;
}
char lngHemisphere = 'E';
if (lng < 0)
{
lngHemisphere = 'W';
lng = -lng;
}
MemoryStream ms = new MemoryStream();
original.Save(ms, ImageFormat.Jpeg);
ms.Seek(0, SeekOrigin.Begin);
Image img = Image.FromStream(ms);
AddProperty(img, ExifTagGPSVersionID, ExifTypeByte, new byte[] { 2, 3, 0, 0 });
AddProperty(img, ExifTagGPSLatitudeRef, ExifTypeAscii, new byte[] { (byte)latHemisphere, 0 });
AddProperty(img, ExifTagGPSLatitude, ExifTypeRational, ConvertToRationalTriplet(lat));
AddProperty(img, ExifTagGPSLongitudeRef, ExifTypeAscii, new byte[] { (byte)lngHemisphere, 0 });
AddProperty(img, ExifTagGPSLongitude, ExifTypeRational, ConvertToRationalTriplet(lng));
return img;
}
static byte[] ConvertToRationalTriplet(double value)
{
int degrees = (int)Math.Floor(value);
value = (value - degrees) * 60;
int minutes = (int)Math.Floor(value);
value = (value - minutes) * 60 * 100;
int seconds = (int)Math.Round(value);
byte[] bytes = new byte[3 * 2 * 4]; // Degrees, minutes, and seconds, each with a numerator and a denominator, each composed of 4 bytes
int i = 0;
Array.Copy(BitConverter.GetBytes(degrees), 0, bytes, i, 4); i += 4;
Array.Copy(BitConverter.GetBytes(1), 0, bytes, i, 4); i += 4;
Array.Copy(BitConverter.GetBytes(minutes), 0, bytes, i, 4); i += 4;
Array.Copy(BitConverter.GetBytes(1), 0, bytes, i, 4); i += 4;
Array.Copy(BitConverter.GetBytes(seconds), 0, bytes, i, 4); i += 4;
Array.Copy(BitConverter.GetBytes(100), 0, bytes, i, 4);
return bytes;
}
static void AddProperty(Image img, int id, short type, byte[] value)
{
PropertyItem pi = img.PropertyItems[0];
pi.Id = id;
pi.Type = type;
pi.Len = value.Length;
pi.Value = value;
img.SetPropertyItem(pi);
}
this produces:
