如何添加EXIF信息以在.NET中对图像进行地理标记? [英] How can I add EXIF information to geotag an Image in .NET?

查看:79
本文介绍了如何添加EXIF信息以在.NET中对图像进行地理标记?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

.NET中有一个映像.如何通过使用EXIF数据编码产生图像的纬度和经度,而无需使用外部库,来对图像进行地理标记?

I have an Image in .NET. How can I geotag the image by encoding the latitude and longitude at which it was produced using EXIF data, but without needing to use an external library?

推荐答案

EXIF信息可以使用PropertyItems附加到.NET 2.0及更高版本中的Image,这些信息可以转换为单独的EXIF字段.有关这些字段的详细信息,请参见 EXIF 2.3标准,但是我们只需要五个就可以对图像进行地理标记.下面的示例C#代码需要引用System.Drawing,System.Drawing.Imaging和System.IO.要对其进行测试,只需使用下面的行.您可以使用此工具(或许多其他工具之一)进行检查,以验证图像是否已正确地理标记.

EXIF information can be attached to Images in .NET 2.0 and higher using PropertyItems, which translate to individual EXIF fields. The details of these fields may be found in the EXIF 2.3 standard, but we only need five of them to geotag an image. The sample C# code below requires references to System.Drawing, System.Drawing.Imaging, and System.IO. To test it, simply use the line below. You can verify that the image has been correctly geotagged by examining it with this tool (or one of many others).

Geotag(new Bitmap(@"C:\path\to\image.jpg"), 34, -118)
    .Save(@"C:\path\to\geotagged.jpg", ImageFormat.Jpeg);

关于下面的代码,可能看起来很奇怪的一件事是,重复使用了PropertyItem来创建新的PropertyItem.由于改变现有的PropertyItem(它是一个类而不是一个结构)似乎会影响现有的属性,因此这并不可行.但是,事实并非如此,因为没有PropertyItem的公共构造函数,所以需要进行此破解.

One thing that may look odd about the code below is that a PropertyItem is reused to create a new PropertyItem. It is not obvious that this will work since mutating the existing PropertyItem (which is a class rather than a struct) seems like it would affect the existing property. However, this turns out not to be the case and this hack is necessary because there is no public constructor for PropertyItem.

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);
}

这篇关于如何添加EXIF信息以在.NET中对图像进行地理标记?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆