直接读取图片EXIF信息在C#中可行,但System.Drawing.Common对GPS和部分时间字段支持不完整,需手动解析PropertyItem字节数组;GPS数据为有理数二进制结构,DateTime字段含末尾空字节,跨平台存在兼容性问题,推荐使用MetadataExtractor库。

直接读取图片 EXIF 信息在 C# 中可行,但 System.Drawing.Common(尤其是 .NET 6+)对 GPS 和部分时间字段支持不完整,容易返回 null 或解析错误——必须手动解析 PropertyItem 字节数组。
为什么 Image.GetPropertyItem 返回的 GPS 数据是乱码或 null
EXIF 的 GPS 信息(如 PropertyTagGpsLatitude)不是字符串,而是由有符号/无符号整数、有理数(Rational)组成的二进制结构。.NET 的 GetPropertyItem 只原样返回 Value 字节数组,不做解码;直接转 Encoding.UTF8.GetString 必然失败。
-
PropertyTagDateTime和PropertyTagDateTimeDigitized同样是 ASCII 字符串,但带末尾空字节,需截断处理 - GPS 纬度/经度字段(
PropertyTagGpsLatitude/PropertyTagGpsLongitude)是PROPERTY_TAG_TYPE_RATIONAL类型,含 3 个UInt32对(分子、分母),共 24 字节 - GPS 北/东标识(
PropertyTagGpsLatitudeRef/PropertyTagGpsLongitudeRef)才是单字节 ASCII 字符('N'/'S'/'E'/'W')
如何正确解析 PropertyTagDateTime 拍摄时间
该字段值是 ASCII 格式字符串(如 "2023:05:12 14:36:22<p>该字段值是 ASCII 格式字符串(如 <code>"2023:05:12 14:36:22\0"),但 .NET 不自动去除末尾空字节,也不校验格式合法性。
- 用
GetPropertyItem(36867)获取PropertyItem,检查Len> 0 且Type == 2(ASCII string) - 用
Encoding.ASCII.GetString(item.Value, 0, item.Len - 1)去掉末尾 \0 - 再用
DateTime.TryParseExact(..., "yyyy:MM:dd HH:mm:ss", ...)解析,注意时分秒可能缺位(如 "2023:05:12 14:36:") - 若失败,可 fallback 到
PropertyTagDateTimeDigitized(36868)或PropertyTagDateTimeOriginal(36866)
怎么从 PropertyItem.Value 提取 GPS 经纬度数值
GPS 坐标以“度分秒”有理数形式存储,需手动拆解字节数组。例如 PropertyTagGpsLatitude(1)对应纬度三元组:度、分、秒。
private static double ParseGpsRational(byte[] value)
{
if (value.Length != 24) return 0;
uint num = BitConverter.ToUInt32(value, 0); // 分子
uint den = BitConverter.ToUInt32(value, 4); // 分母
return den != 0 ? (double)num / den : 0;
}
<p>// 示例:读取纬度(3 个 Rational → 度、分、秒)
var latItem = img.GetPropertyItem(2); // PropertyTagGpsLatitude
double deg = ParseGpsRational(latItem.Value.Skip(0).Take(8).ToArray());
double min = ParseGpsRational(latItem.Value.Skip(8).Take(8).ToArray());
double sec = ParseGpsRational(latItem.Value.Skip(16).Take(8).ToArray());
double latitude = deg + min / 60 + sec / 3600;
// 再读取 ref item 获取 'N' or 'S'
var refItem = img.GetPropertyItem(1); // PropertyTagGpsLatitudeRef
char dir = (char)refItem.Value[0];
if (dir == 'S') latitude = -latitude;.NET 6+ 使用 System.Drawing.Common 的兼容性陷阱
Linux/macOS 下默认禁用 System.Drawing.Common(依赖 GDI+),且部分 EXIF 属性在跨平台时根本无法读取(如 GPS 标签返回空数组)。
- Windows 上需确保安装
libgdiplus(Linux)或启用DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false - 更稳妥方案是改用
MetadataExtractorNuGet 包(纯托管,支持全平台、完整 EXIF/GPS 解析) - 若坚持用原生 API,务必对每个
GetPropertyItem调用加 try/catch,并检查item.Id是否真实存在(不同相机厂商写入的 tag ID 可能略有差异)
真正麻烦的从来不是“能不能读”,而是“读出来的是不是对的”——GPS 值少一位小数、时间差 8 小时、坐标符号反了,这些都得靠字节级验证和多设备实测来兜底。


















