ExifLib - .NET 2.0+ 快速 Exif 数据提取器






4.90/5 (93投票s)
读取 JPEG Exif 数据,无需实例化重量级且不必要的 GDI+ 对象。
引言
ExifLib
仅从 JPEG 文件中读取 Exif 标签(例如相机型号、GPS 数据、拍摄日期、快门速度等),而无需使用 `System.Drawing.Imaging` 中的 GDI+ 类引入的开销,并且开发人员的代码行数更少。
背景
我一直在使用一个简单的命令行应用程序,根据照片的创建日期将它们移动到子目录中。与我见过的所有其他 .NET Exif 实现一样,我使用的是 `System.Drawing.Imaging` 中的 `PropertyItem` 类。虽然它能完成工作,但我经常一次处理成千上万张图片,而 .NET 类对于这项工作来说太慢了。ExifLib
回归到 JPEG/TIFF 标准本身,只读取必需的部分,几乎只使用 `System.IO` 中的文件输入类。
Using the Code
ExifLib
非常简单,命名空间中只有一个类和一个 `enum`。只需添加对 *ExifLib.dll* 的引用,即可开始使用!示例如下:
using ExifLib;
...
...
...
// Instantiate the reader
using (ExifReader reader = new ExifReader(@"C:\temp\testImage.jpg"))
{
// Extract the tag data using the ExifTags enumeration
DateTime datePictureTaken;
if (reader.GetTagValue<DateTime>(ExifTags.DateTimeDigitized,
out datePictureTaken))
{
// Do whatever is required with the extracted information
MessageBox.Show(this, string.Format("The picture was taken on {0}",
datePictureTaken), "Image information", MessageBoxButtons.OK);
}
}
请注意,ExifReader
类会保持图像文件打开状态,因此在完成阅读器使用后,请务必调用其 Dispose
方法,无论是显式调用,还是通过 `using` 语句(如上例所示)隐式调用。
工作原理
Exif 数据存储在 JPEG 文件的头部,位于 APP1 块中。该块包含多个 IFD(图像文件目录)。其中包括 EXIF IFD 和 GPS IFD,它们包含此库可用于检索的标签。
IFD 以 EXIF 标签目录和每个标签数据存储位置的流偏移量开始。实例化时,库会创建一个这些标签偏移量的 `Dictionary`,在检索特定标签的值时会访问这些偏移量。正是这种惰性检索赋予了库速度,因为大多数 Exif 用例只涉及检索少量标签值,因此在需要之前检索标签值没什么用处。
关注点
编写此库时,我学到的一件奇怪的事情是,虽然 JPEG 规定使用“大端”(Big Endian)编码(即数字从左到右读取),但 TIFF 标准允许使用大端或小端(Little Endian)编码。由于 Exif 标签使用 TIFF 编码,因此 JPEG 通常会使用“大端”编码读取,直到到达 TIFF 部分,此时编码会反转,文档的其余部分将使用“小端”编码读取。
编码过程中,我从 CodeProject 文章 ExifWorks 的一个评论中了解到,通过将构造函数的 `validateImageData` 参数设置为 false
,可以提高使用 `System.Drawing.Image` 时的性能。然而,即使使用此增强功能,ExifLib
的性能仍然快 50%,这可能是因为它直到请求时才读取标签值。我还注意到,ExifLib
在处理小型(<1MP)图像时性能相似,但在加载大型图像时扩展性更好。此页面顶部的截图是使用 12MP 图像生成的。
历史
版本 1.1
- 增加了数组提取功能,这要归功于 Justin Carasick 的评论。这在各种字段中使用,包括 GPS 坐标和 Exif 版本。旧版本的
ExifLib
只会返回数组的第一个元素。
版本 1.2
- 修复了检索小于 4 字节字段数据时的错误,这要归功于 bartsy 的评论。旧版本的
ExifLib
在处理大端编码文件时会丢失这些字段中的重要数据。 - 项目已更新至 Visual Studio 2010,并重构了部分代码。项目仍支持 .NET 2.0+。
版本 1.3
- 添加了从图像中提取 JPEG 编码缩略图的功能,这要归功于 StyrianOak 的评论。请注意,不支持未压缩(即 TIFF)编码的缩略图,但由于任何支持 DCF 标准的相机都会生成 JPEG 缩略图,因此这是一个小限制。
版本 1.4
- 添加了一个构造函数重载,允许从任何可查找流读取 JPEG 数据
- 修改了代码以允许编译 Windows Phone 和 Silverlight。NuGet 包现在包含 Windows Phone 和 Silverlight 的 DLL。
- 改进了对 null
DateTime
值的支持,这要归功于 schurig 和 BrandonOrding 的评论 - 未定义的 Exif 字段现在返回为
byte[]
而不是uint[]
- 修复了缩略图提取器中的一个错误,该错误导致无法识别带有
0xFF
填充的缩略图,这要归功于 _d-fens_ 的评论。 - 添加了将 TIFF 有理数作为
int[] {分子, 分母}
数组(而不是double
)提取的选项,这要归功于 Member 10226163 的评论。 - 更改了缩略图填充检测代码,以接受
0x00
和0xFF
作为填充字节,这要归功于 Cruiser77 的评论 - 添加了用于 Windows Store 应用兼容性的条件编译选项,这要归功于 _dieQueeQ. 的评论。
版本 1.5
- 修复了读取包含无数据类型标签的图像时发生的异常
- 重构代码,为每个 IFD 存储单独的标签数据字典
- 添加了从不包含 EXIF 子 IFD 的图像中提取元数据的能力,这要归功于 Charlie Hess 在工作区中提出的一个问题
1.6 版
- 为 framework 4.5+ 添加了一个新的构造函数参数,允许用户指示在处置阅读器时应将提供的流保持打开状态
- 感谢 disore 的评论,修复了在实例化过程中到达流末尾时抛出的
ArgumentExceptions
;将一些实例化异常包装在ExifLibExceptions
中。
1.7 版
- 标签支持已更新至 EXIF 2.3
- 更新了 IFD 选择以处理乱序的标签设计(以支持非标准的 Microsoft XP 标签)
- 添加了对 Unicode 编码字符串的支持,这要归功于 lightfinder 和 Forcasual things 的评论。
NuGet 发布
ExifLib 现在 可在 nuget 上找到!只需在 Visual Studio 的包管理器控制台中输入 *Install-Package ExifLib* 即可安装。