.net - 如何在 .NET 中添加 EXIF 信息以对图像进行地理标记?

标签 .net image exif geotagging

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

最佳答案

EXIF 信息可以使用 PropertyItems 附加到 .NET 2.0 和更高版本中的图像,它转换为单个 EXIF 字段。这些字段的详细信息可以在 the EXIF 2.3 standard 中找到。 ,但我们只需要其中五个来对图像进行地理标记。下面的示例 C# 代码需要引用 System.Drawing、System.Drawing.Imaging 和 System.IO。要测试它,只需使用下面的行。您可以通过使用 this tool 检查图像来验证图像是否已正确标记。 (或许多其他之一)。

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

下面的代码可能看起来很奇怪的一件事是,一个 PropertyItem 被重用于创建一个新的 PropertyItem。这并不明显,因为改变现有的 PropertyItem(它是一个类而不是结构)似乎会影响现有的属性。然而,事实证明并非如此,因为没有用于 PropertyItem 的公共(public)构造函数,所以这种 hack 是必要的。
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);
}

关于.net - 如何在 .NET 中添加 EXIF 信息以对图像进行地理标记?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34305848/

相关文章:

jpeg - 将大量自定义数据添加到 jpg 图像文件中

android - 可以将自定义元数据添加到 Android 中的图像中吗?

c# - 我正在寻找 .NET 的实际功能 Web 浏览器控件,也许是 C++ 库

c# - 使用 Moq 和 MSTest 测试异常的正确方法

Android - 在 Canvas 上淡出位图图像

javascript - 获取 Base64 编码图像并使用 ExpressJS 将其作为图像发送

c# - 使用 ASP.NET MVC4 检索在数据库中存储为字节数组的图像的好方法?

.net - 代码契约怎么了?

image - 当图像通常是最大的 HTTP 请求时,为什么还要担心缩小 JS 和 CSS?

c++ - Exiv2 - 一些图像标签不写,但有些写