使用 Visual Studio 的新对象数据绑定功能访问图像元数据






4.85/5 (13投票s)
2007 年 2 月 1 日
12分钟阅读

85101

990
使用一个新的类库,只需几行代码即可绑定到照片元数据。
引言
元数据是关于嵌入在文件中的图像(或其他媒体类型)的信息。有几种类型的元数据。最常用的是 EXIF(可交换图像文件格式)。数码相机将拍摄数据保存在 EXIF 段中。浏览器和图像管理应用程序(如 Photoshop Elements Organizer 或(我最喜欢的)Photo Mechanic)保存用户输入的信息,如图像标题;它们还可以编辑拍摄数据,如创建时间。它们会更新原始 EXIF 段,但也可以将数据保存在 XMP(可扩展元数据平台)段中。本文主要关注 XMP 元数据的访问。
Visual Studio 2005 和 .NET 2.0 最强大的功能之一是能够直接将数据绑定到对象的属性。我将介绍一个用于创建可绑定 XMP 数据对象的类库。Adobe XMP 规范中的 XMP 数据模型包含一组 XMP Schema 定义。每个 Schema 列出了一组相关的属性。库中的类映射到 XMP 数据模型中的 Schema。为了提高可用性,该库还包含一个绑定到 EXIF 元数据的类。
在本文中,我将首先介绍一个说明类库用法的示例应用程序。请参阅 Rockford Lhotka 的文章,其中对使用的对象数据绑定技术进行了深入描述。接下来,我将简要讨论类库的一些细节。有关创建可绑定类的更多信息,请参阅Code Project 文章以及描述 INotifyPropertyChanged
接口的其他文章。最后,我将介绍如何根据 XMP 规范中的信息生成该库。特别是,我将揭示用于从 PDF 格式规范文件中提取可用源数据的技巧。
使用代码
屏幕截图显示了示例应用程序的一些功能。加载数据按钮从图像文件中加载元数据。写入数据按钮将 XMP 元数据写入 XML 文件。选项卡控件在单独的选项卡页面中显示多个照片元数据对象的属性。
选项卡控件包含五个页面,其中包含我们要显示的 照片元数据。
Visual Studio 2005 的强大功能之一是能够通过将对象数据源从“数据源”窗口拖到窗体上,仅凭此即可创建属性显示和编辑字段。Visual Studio 还创建了大部分所需的数据绑定源代码。在此所示的点,正在创建一个用于显示 PDF 元数据属性的选项卡页面。
第一步是创建一个绑定到 PdfMetadata 对象的“数据源”。屏幕截图显示了“数据源配置向导”中的“对象选择”页面。通过单击“数据源”窗口中的“添加新数据源”按钮并选择“对象数据源类型”来显示它。选择 PdfMetadata 对象并单击“完成”按钮会将 PdfMetadata 添加到“数据源”列表中。
下一个屏幕截图显示了如何配置“数据源”窗口中的属性字段。在左侧的视图中,我选择了“详细”布局,该布局会在单独的字段中显示属性。右侧的视图显示了如何配置每个属性使用的控件类型。在此情况下,我选择不显示 PDFVersion 属性。
配置数据源后,我只需将 PdfMetadata 项从“数据源”窗口拖到“PDF 元数据”选项卡即可。Visual Studio 2005 负责布局并创建了大部分数据绑定代码。
为了完成此过程,我添加了以下代码
private void LoadData(string imageFile)
{
xmpData = XmpMetadata.CreateNewXmpData(imageFile);
this.photoshopMetadataBindingSource.DataSource = xmpData
.XmpPhotoshopMetadata;
this.dcMetadataBindingSource.DataSource = xmpData
.XmpDcMetadata;
this.exifMetaDataBindingSource.DataSource = xmpData
.ImageExifMetadata;
this.tiffMetadataBindingSource.DataSource = xmpData
.XmpTiffMetadata;
this.pdfMetadataBindingSource.DataSource = xmpData
.XmpPdfMetadata;
}
LoadData
在加载数据按钮事件处理过程中调用,它接收选定的图像文件。第一行创建 xmpData 对象,它是 元数据对象的容器。其余行将照片元数据对象链接到自动生成的
BindingSource 对象。
写入数据按钮将 XMP 属性写入 XML 文件。在 XMP 规范允许的情况下(请参阅下面的讨论),对显示的属性字段的编辑更改会写入输出文件。您的应用程序可以使用编辑后的输出来更新源图像文件中的 XMP 段。
以上基本内容已涵盖。我再次建议您参考 Rockford Lhotka 的文章,其中对如何使用对象数据绑定进行了深入讨论。
本文的其余部分是有关该库及其创建过程的背景信息。
XMP 元数据类库概述
XMP 元数据 Schema
这十五个 XMP 元数据类映射到 Adobe XMP 规范中定义的 Schema。通过“EXIF 附加 EXIF 属性的 EXIF Schema”这一较短的 Schema 之一,说明了这种映射。这是从规范文档中截取的 Schema 屏幕截图。
其 Schema 名称为“http://ns.adobe.com/exif/1.0/aux/”。其 Schema 命名空间前缀为 aux。类名以 Schema 命名空间前缀开头。
第一列包含属性名称。第二列显示了规范中定义的属性的值类型。第三列是“类别”,可以是“内部”或“外部”。“外部”属性,例如“标题”,可以由用户更新。“内部”属性,例如相机“序列号”,无法更改。在库中,“内部”属性是只读的。最后一列是属性描述。在库中,属性描述包含在 XML 注释中。
下一个屏幕截图显示了在“对象浏览器”中显示的“照片元数据”类。
“EXIF 附加 EXIF 属性的 EXIF Schema”Schema 被映射到 AuxMetadata
类。类名源自 Schema 命名空间前缀。对象属性名称源自 Schema 属性名称。由于选定的属性 Lens
属于“内部”类别,因此仅存在 get
访问器。“外部”属性同时具有访问器并且可以编辑。由于 Schema 注释用作 AuxMetadata
类代码中的 XML 注释,因此它显示在“对象浏览器”的“摘要”部分。
XmpMetadata 类
XmpMetadata
对象是元数据对象的容器。实例化时,它会从指定文件中提取 XMP 段并将其加载到 XmlDocument
对象中。该文件可以是 Jpeg 或 TIFF 图像文件或 XML 文件。它会解析 XmlDocument
对象以提取单个 Schema 元素,这些元素存储为 XmlNode
对象。公开为属性的元数据对象是从 XmlNode
对象创建的。它们在应用程序中首次引用时实例化。
它在 metadataList Dictionary 对象中维护实例化元数据对象的列表。该列表用于 UpdateXmpSegment
方法,该方法将元数据属性更改应用于原始 XmlDocument
对象。
其 WriteXmpSegment
方法将 XmlDocument
对象写入指定流。indent 参数指定输出是否已格式化。
有一堆相当琐碎的代码用于从 JPEG 和 TIFF 图像文件中提取嵌入的 XMP 段。其中一部分可能具有普遍意义,它会搜索 TIFF 文件以查找指定的 Tag ID,并以 C# 数据结构返回该标签。TIFF 代码支持“大端”和“小端”字节序。我查看过的文件由于可能源自 PC 而倾向于“小端”。源自旧 Mac 的文件可能是“大端”。
照片元数据基类
PhotoMetadata
类是 XMP 元数据类的基类。它实现了必需的 INotifyPropertyChanged
接口。实例化时,它会接收从 XMP 段提取的 XmlNode
对象。该对象包含属于该类 XMP Schema 的属性。它还接收顶层 XmlDocument
对象,并在属性编辑期间使用它。
其 GetInitialValue
方法从 XmlNode
对象中提取指定的属性值,并将其作为字符串返回。GetInitialValue
在初始数据加载过程中被调用。它接收 XMP Schema 定义中定义的属性名称和属性值类型。
当更改元数据属性时,会调用其 UpdateData 方法。它接收新的属性值以及 XMP 属性名称和属性值类型。它会使用更改更新 XmlNode
对象。
其 WriteXML
方法将 XmlNode
对象写入输出流。事实证明,这是一种进化死胡同,在示例应用程序中实际上并未真正使用,但可能对其他应用程序有所帮助。
XMP Schema 元数据类
每个 XMP 元数据类都基于 PhotoMetadata
类,并公开其 XMP Schema 中定义的属性。它们每个都包含一个 LoadInitialData
方法,该方法在基类实例化时被调用。LoadInitialData
从 XmlNode
对象中提取初始属性值。
以下是示例属性代码。
private string m_Contributor = null;
/// <summary>
/// Contributors to the resource (other than the authors).
/// </summary>
public string Contributor
{
get
{
return m_Contributor;
}
set
{
string adjustedValue = AdjustedValue(value);
if (adjustedValue != m_Contributor)
{
m_Contributor = adjustedValue;
ElementUpdated("Contributor", "dc:contributor",
"bag ProperName", adjustedValue);
}
}
}
此代码创建了 Dublin Core (DcMetadata) 类中的第一个属性。XML 文档取自 XMP 规范中属性的描述。m_Contributor 字符串由 LoadInitialData
方法初始化。此处存在“set”访问器是因为 Contributor 属性是只读的。AdjustedValue
方法会清理输入字符串。调用 ElementUpdated
方法来输出所需的通知事件并更新 XmlNode
对象中的属性值。其参数是 .Net 属性名称、XMP Schema 属性名称和属性值类型以及更新后的值。
代码生成器
由于有十五个 XMP Schema 和数百个属性,手动编写 XMP 元数据类代码是不切实际的。因此,我使用了 CodeGenerator 项目中的代码生成器,该项目是代码分发的一部分。代码生成器使用的源数据位于“doc”子目录的 XML 文件中。
我从包含“Adobe XMP Specification”的 PDF 文件中提取了源文件。我的规范文件副本也位于“doc”子目录中。我使用 Adobe Acrobat Professional 提取了数据。我的版本是 6.0.5。我加载了规范文件,然后提取了页面或生成。我使用了“文档/页面/提取”菜单选项并输入了我要提取的页面。在提取的文档中,我选择将文档另存为 XML。然后,我继续手动编辑生成的 XML。我首先删除了不包含在 <table> 标签中的任何行。然后,如有必要,我将多个表合并成一个表。
代码生成器将此过程创建的原始 XML 加载到 XmlDocument
对象中。然后 CleanXmlTable
方法合并连续的行,直到每个 XmlNode
对象只有一个属性。
其余代码很简单。应用程序在 XmlDocument
对象中遍历每个属性节点两次。第一次遍历时,它生成属性代码。第二次遍历时,它生成属性初始化语句。
新增功能
除了前面讨论的类之外,我还将 PhotoMechanicMetadata 类包含在库中。它访问 Photo Mechanic 创建的自定义 XMP Schema 中的数据(请参阅 www.camerabits.com)。Photo Mechanic 将不适合任何其他 Schema 的用户输入的元数据保存在此自定义 Schema 中。我添加它的主要原因是我希望在自己的应用程序中能够访问 Photo Mechanic 提供的颜色编码的照片质量评级信息。我通过逆向工程自定义 Schema 中的数据来创建该类。
正如在引言中所述,该库还包含 ImageExifMetadata
类,该类绑定到 EXIF 元数据。ImageExifMetadata
类使用 Asim Goheer 在 Code Project 文章中描述的 EXIFExtractor
类。ImageExifMetadata
使用 EXIFExtractor
访问图像文件中的 EXIF 属性并将其存储在 Hashtable 中。它包含生成的属性代码,用于创建可绑定、只读的属性。它使用 LoadData
函数从 Hashtable 中的数据初始化属性。
省略
此库省略了许多可能有用但未完全实现的功能。以下是一些示例:
我自己的应用程序不需要完整的编辑功能,因此编辑并未完全实现。特别是,虽然可以添加新属性,但结果可能不完全符合 XMP 规范。必需的“属性值类型”信息在 ElementUpdated
函数调用中提供。这可以(但现在不能)用于控制新插入的属性值的格式。
此库可以访问 TIFF、JPEG 和 XML 文件中的数据。XMP 规范列出了其他几种可以支持嵌入式 XMP 元文件的文件类型。我希望访问的一种常见格式是 Adobe Photoshop (*.psd)。列出的其他类型之一是 PNG,我喜欢它,因为它是一种开放标准,是无损的,具有良好的文件压缩,并且得到了广泛支持。能够访问 PNG 文件中的元数据以及可能列出的其他一些图像文件类型将非常有用。
此列表是未来改进的基础。
最后,由于缺乏测试数据,许多类实际上并未经过测试。由于它们是通过自动化过程创建的,因此这不太可能成为问题,但没有测试,我无法确定。
关注点
元数据在哪里?如果您运行示例应用程序并使用直接从相机拍摄的文件,您将在 EXIF 元数据选项卡上看到数据,但其他选项卡可能会为空。原因是大多数相机都根据旧的(且复杂的)EXIF 标准保存元数据,但不支持基于 XML 的 XMP 标准。您需要使用一个可以配置为将 XMP 段写入图像文件的应用程序来保存文件。
一些应用程序,如 Adobe Photoshop Elements,允许您查看 XMP 段的内容。例如,在 Elements 中,从“文件”菜单中选择“文件信息”。在“文件信息”窗口中,选择“高级”选项卡。这将显示一个树形结构,其中 XMP 属性按 Schema 组织。
历史
本文最初于 2007 年 1 月 24 日提交。