用C#和。NET框架


介绍

上周末,我决定尝试使用C#和.NET Framework导入图像元数据。除了“普通”文件属性(如修改日期和大小)之外,Windows资源管理器(Shell)还提供了扩展的文件属性信息,这可能非常有价值。

挑战在于如何提取这些信息,因为.NET Framework对这种类型的提取的支持有些有限?请继续阅读以了解如何提取。

扩展文件属性数据

当您在Windows资源管理器中右键单击某个文件并选择“属性”时,您会注意到一个名为“详细信息”的选项卡。

同样,如果您将文件夹视图更改为“Details”视图并右键单击列标题,则可以选择“More…”它允许您包括可供查看的扩展属性列。

请注意,根据文件夹中包含的文件类型,许多属性将不适用。

添加后,Explorer视图将显示每个文件的附加属性数据;这是我们将使用.NET Framework查询的数据类型。

图像数据

在我的特定场景中,我希望访问与照片相关的扩展属性,例如ISO速度、F-Stop、焦距、尺寸等。*每个属性都有一个标识符,可用于检索相关的属性数据。*您可以从.NET中获取一些信息,如下所示:

Image image = new Bitmap(file);




PropertyItem propItem = image.GetPropertyItem(36867);
string dateTaken = r.Replace(Encoding.UTF8.GetString(propItem.Value), "-", 2);
var dateTaken = DateTime.Parse(dateTaken);

所以你通过使用Win32互操作并直接从C#/.NET调用shell调用来获取更多这样的信息,但这可能很耗时,更不用说费力了,因为您必须跟踪要使用的正确Win32API接口和属性项ID。一定有更简单的方法吗?

Windows API代码包简介

谢天谢地,已经有人为我们做了腿上的工作,最终完成了极其有用的Windows API Code Pack,最新版本是available via this link

该包本身包含文档、示例、预编译的二进制文件和二进制文件的源代码。

老实说,我发现文档和示例有点平淡无奇,但核心程序集绝对是黄金级的--一旦您弄清楚如何正确使用它们的话。*以下是作为示例随包一起提供的Explorer浏览器的屏幕截图:


这可能是我多年来见过的最令人不安的事情之一

正在检索扩展属性数据

该包最好的功能之一肯定是有人已经将所有扩展属性值映射到强类型定义,这为我们节省了大量时间和精力。

ShellObject picture = ShellObject.FromParsingName(file);




var camera = picture.Properties.GetProperty(SystemProperties.System.Photo.CameraModel);
newItem.CameraModel = GetValue(camera, String.Empty, String.Empty);




var company = picture.Properties.GetProperty(SystemProperties.System.Photo.CameraManufacturer);
newItem.CameraMaker = GetValue(company, String.Empty, String.Empty);

SystemProperties类定义了一个非常有用的扩展属性标识符层次结构,可以与shell对象结合使用,如上所述。

使用包

基于上述内容,提取扩展照片属性数据轻而易举。我编写了一个小实用程序来演示提取所需数据的直截了当的方式。您需要引用打包的Microsoft.WindowsAPICodePack.dll和Microsoft.WindowsAPICodePack.Shell.dll中的两个程序集。

以下是我使用的代码的完整转储:

using System;
using Microsoft.WindowsAPICodePack.Shell.PropertySystem;
using Microsoft.WindowsAPICodePack.Shell;
using System.Diagnostics;




namespace DataTools.FilePropertyExtract
{




class Program
{
private static string GetValue(IShellProperty value)
{
if (value == null || value.ValueAsObject == null)
{
return String.Empty;
}
return value.ValueAsObject.ToString();
}




static void Main(string[] args)
{
if (args.Length != 1)
return;




string filename = args[0];
if (!System.IO.File.Exists(filename))
return;




ShellObject picture = ShellObject.FromParsingName(filename);




if (picture != null)
{
var camera = GetValue(picture.Properties.
GetProperty(SystemProperties.System.Photo.CameraManufacturer));
var cameraModel = GetValue(picture.Properties.
GetProperty(SystemProperties.System.Photo.CameraModel));
var formattedString = String.Format("File {0} has Manufacturer {1} and Model {2}",
filename, camera, cameraModel);
Trace.WriteLine(formattedString);
}
}
}
}

如果您传递要从中提取数据的照片的完全限定路径和文件名,则会导致以下结果:

请注意,在本例中,文件没有相机制造商,因此该属性为空(但不为空)。

摘要

这个包显然不仅仅是对Windows Shell API的抽象。稍后我可能会做更多的探索,但我觉得对于那些需要更简单的解决方案来提取扩展文件属性数据的人来说,这篇文章可能会很方便。请欣赏。