【问题标题】:How can I add EXIF information to geotag an Image in .NET?如何在 .NET 中添加 EXIF 信息以对图像进行地理标记?
【发布时间】:2016-03-22 05:23:53
【问题描述】:

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

【问题讨论】:

    标签: .net image exif geotagging


    【解决方案1】:

    可以使用 PropertyItems 将 EXIF 信息附加到 .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 的公共构造函数,所以这种 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);
    }
    

    【讨论】:

      猜你喜欢
      • 2018-06-27
      • 2012-06-16
      • 2021-01-12
      • 1970-01-01
      • 1970-01-01
      • 2017-07-31
      • 2012-08-04
      • 2012-05-04
      • 1970-01-01
      相关资源
      最近更新 更多