WIC/WPF: System.GPS.Longitude和System.GPS.Latitude始终通过BitmapMetadata返回NULL。

3
有人成功地使用WPF类BitmapMetadata读取GPS数据吗?这个类内部使用WIC(Windows Imaging Component)。我有一张图片,Windows(8.1)资源管理器和外部工具如XnView都显示了GPS坐标。我尝试使用类BitmapFrame的属性Metadata提取这些数据:
var md = (BitmapMetdata)extractedFrame.Metadata;
var altitude = md.GetQuery("System.GPS.Altitude");
var altitudeProxy = md.GetQuery("System.GPS.Altitude.Proxy");
var altitudeRef = md.GetQuery("System.GPS.AltitudeRef");
var longitude = md.GetQuery("System.GPS.Longitude");
var longitudeProxy = md.GetQuery("System.GPS.Longitude.Proxy");
var longitudeRef = md.GetQuery("System.GPS.LongitudeRef");
var latitude = md.GetQuery("System.GPS.Latitude");
var latitudeProxy = md.GetQuery("System.GPS.Latitude.Proxy");
var latitudeRef = md.GetQuery("System.GPS.LatitudeRef");

altitude (System.Double)、altitudeRef (System.Byte)、longitudeRef (System.String) 和 latitudeRef (System.String) 的结果都正常,并且检索到了合理的数据("510.70", "0", "N", "E")。

longitudelatitude 应该是 System.Double 数组类型,但它们始终为 NULL。

使用 ".Proxy" 后缀返回的结果是奇怪的字符串数据,我不确定如何解析它们,也不确定它们是否与区域设置无关:MSDN 文档中没有提到字符串;但至少在那里可以获取到 Longitude 和 Latitude 的“有效”数据。

这是一个 bug 还是我错过了什么?

2个回答

7
我使用这里的代码来获取纬度和经度:http://khason.net/blog/how-to-read-gps-metadata-from-image/。但它没有处理N、S、E、W的正负部分,因此你需要使用上方的LongitudeRef和LatitudeRef来确定是否改变坐标的符号。简而言之:
JpegBitmapDecoder decoder = new JpegBitmapDecoder(stream, BitmapCreateOptions.None, BitmapCacheOption.None);
BitmapMetadata meta = (BitmapMetadata)decoder.Frames[0].Metadata;
ulong[] latitude    = meta.GetQuery("/app1/ifd/gps/subifd:{ulong=2}") as ulong[];
ulong[] longitude   = meta.GetQuery("/app1/ifd/gps/subifd:{ulong=4}") as ulong[];
double lat          = ConvertCoordinate(latitude);
double longit       = ConvertCoordinate(longitude);

static double ConvertCoordinate(ulong[] coordinates)
{
    int lDash   = (int)(coordinates[0] - ((ulong)0x100000000));
    int lF      = (int)(coordinates[1] - ((ulong)0x100000000));
    double lR   = ((double)(coordinates[2] - ((ulong)0x6400000000))) / 100;
    double tRes = (lDash + (((double)lF) / 60)) + (lR / 3600);
    return (Math.Floor((double)(tRes * 1000000)) / 1000000);
}

修改:以上方法仅适用于旧版EXIF格式。新版格式的坐标位数更多,因此转换错误。我不得不更新“转换坐标”如下:

static double ConvertCoordinate(ulong[] coordinates)
{
    if (coordinates == null)
        return 0;

    double degrees = ConvertToUnsignedRational( coordinates[ 0 ] ); 
    double minutes = ConvertToUnsignedRational( coordinates[ 1 ] ); 
    double seconds = ConvertToUnsignedRational( coordinates[ 2 ] ); 
    return degrees + (minutes / 60.0) + (seconds / 3600); 

}
static double ConvertToUnsignedRational( ulong value ) 
{ 
    return (value & 0xFFFFFFFFL) / (double) ((value & 0xFFFFFFFF00000000L) >> 32); 
} 

@StefanFalk 这是一个回答,不是一个问题。如果您是投票者,我建议您撤销投票,因为该答案确实返回了合理的值。 - springy76
@springy76 对不起!我在审核时犯了错误,认为这是一个真正的问题!我会撤销我的负评,但我必须等到她接受我的编辑,因为SO锁定了我的投票决定。 - Stefan Falk
顺便提一下:meta.GetQuery() 还有两个额外的键,也可以返回 ulong[]:"/xmp/exif:GPSLatitude" 和 "/xmp/exif:GPSLongitude"。 - springy76

1

可能已经太晚来回答了,但是.Proxy值具有以下格式:

MetaDataValue   "16,0.4965000000000145E"    object {string}

意思是16度,0.49分。因此,您只需要将其转换为分钟和秒。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接