65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.90/5 (93投票s)

2009年5月11日

CPOL

5分钟阅读

viewsIcon

1422518

downloadIcon

21304

读取 JPEG Exif 数据,无需实例化重量级且不必要的 GDI+ 对象。

Exif Lib - test application

引言

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 值的支持,这要归功于 schurigBrandonOrding 的评论
  • 未定义的 Exif 字段现在返回为 byte[] 而不是 uint[]
  • 修复了缩略图提取器中的一个错误,该错误导致无法识别带有 0xFF 填充的缩略图,这要归功于 _d-fens_ 的评论。
  • 添加了将 TIFF 有理数作为 int[] {分子, 分母} 数组(而不是 double)提取的选项,这要归功于 Member 10226163 的评论。
  • 更改了缩略图填充检测代码,以接受 0x000xFF 作为填充字节,这要归功于 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 编码字符串的支持,这要归功于 lightfinderForcasual things 的评论。

NuGet 发布

ExifLib 现在 可在 nuget 上找到!只需在 Visual Studio 的包管理器控制台中输入 *Install-Package ExifLib* 即可安装。

© . All rights reserved.