图像元数据

本文介绍如何读写图像元数据属性以及如何使用 GeotagHelper 实用程序类标注文件。

映像属性

StorageFile.Properties 属性返回对关于文件的相关内容信息提供访问的 StorageItemContentProperties 对象。 通过调用 GetImagePropertiesAsync 获取特定于图像的属性。 返回的 ImageProperties 对象公开包含基本图像元数据字段(如图像的标题和捕获日期)的成员。

private async void GetImageProperties(StorageFile imageFile)
{
    ImageProperties props = await imageFile.Properties.GetImagePropertiesAsync();

    string title = props.Title;
    if (title == null)
    {
        // Format does not support, or image does not contain Title property
    }

    DateTimeOffset date = props.DateTaken;
    if (date == null)
    {
        // Format does not support, or image does not contain DateTaken property
    }
}

若要访问较大的文件元数据集,请使用 Windows 属性系统,一组可以使用唯一的字符串标识符进行检索的文件元数据。 创建字符串列表,并为想要检索的每个属性添加标识符。 ImageProperties.RetrievePropertiesAsync 方法采用此字符串列表,并返回键/值对的字典,其中键是属性标识符,值是属性值。

ImageProperties props = await imageFile.Properties.GetImagePropertiesAsync();

var requests = new System.Collections.Generic.List<string>();
requests.Add("System.Photo.Orientation");
requests.Add("System.Photo.Aperture");

IDictionary<string, object> retrievedProps = await props.RetrievePropertiesAsync(requests);

ushort orientation;
if (retrievedProps.ContainsKey("System.Photo.Orientation"))
{
    orientation = (ushort)retrievedProps["System.Photo.Orientation"];
}

double aperture;
if (retrievedProps.ContainsKey("System.Photo.Aperture"))
{
    aperture = (double)retrievedProps["System.Photo.Aperture"];
}
  • 有关 Windows 属性的完整列表(包括标识符和每个属性的类型),请参阅 Windows 属性

  • 某些属性仅适用于某些文件容器和图像编解码器。 有关每种图像类型支持的图像元数据的列表,请参阅照片元数据策略

  • 由于不受支持的属性在检索时可能会返回 Null 值,因此在使用返回的元数据值之前,始终检查 Null。

地理标签帮助程序

GeotagHelper 是一个实用工具类,可以方便地直接使用 Windows.Devices.Geolocation API 标记带有地理数据的图像,而不必手动分析或构建元数据格式。

如果你已拥有表示要在图像(来自先前使用的地理位置 API 或某些其他源)中标记的位置的 Geopoint 对象,你可以通过调用 GeotagHelper.SetGeotagAsync 并传入 StorageFileGeopoint 来设置地理标签数据。

var point = new Geopoint(
new BasicGeoposition
{
    Latitude = 48.8567,
    Longitude = 2.3508,
});

await GeotagHelper.SetGeotagAsync(imageFile, point);

若要使用设备的当前位置设置地理标签数据,则创建一个新的 Geolocator 对象,并调用传入 Geolocator 和要标记文件的 GeotagHelper.SetGeotagFromGeolocatorAsync

var locator = new Geolocator();

// Shows the user consent UI if needed
var accessStatus = await Geolocator.RequestAccessAsync();
if (accessStatus == GeolocationAccessStatus.Allowed)
{
    await GeotagHelper.SetGeotagFromGeolocatorAsync(imageFile, locator);
}

若要获取表示图像文件的已加注地理标签位置的 GeoPoint,请调用 GetGeotagAsync

Geopoint geoPoint = await GeotagHelper.GetGeotagAsync(imageFile);

解码和编码图像元数据

使用图像数据的最先进方式是使用 BitmapDecoderBitmapEncoder 在流级别上读写属性。 对于这些操作,你可以使用 Windows 属性来指定正在读写的数据,但你也可以使用由 Windows 图像处理组件 (WIC) 提供的元数据查询语言为请求的属性指定路径。

使用此技术读取图像元数据要求你拥有使用源图像文件流创建的 BitmapDecoder。 有关如何执行此操作的详细信息,请参阅图像处理

安装解码器后,创建一个字符串列表,并为要使用 Windows 属性标识符字符串或 WIC 元数据查询进行检索的每个元数据属性添加一个新项。 调用解码器的 BitmapProperties 成员上的 BitmapPropertiesView.GetPropertiesAsync 方法以请求指定的属性。 在包含属性名称或路径和属性值的键/值对的字典中将返回属性。

private async void ReadImageMetadata(BitmapDecoder bitmapDecoder)
{

    var requests = new System.Collections.Generic.List<string>();
    requests.Add("System.Photo.Orientation"); // Windows property key for EXIF orientation
    requests.Add("/xmp/dc:creator"); // WIC metadata query for Dublin Core creator

    try
    {
        var retrievedProps = await bitmapDecoder.BitmapProperties.GetPropertiesAsync(requests);

        ushort orientation;
        if (retrievedProps.ContainsKey("System.Photo.Orientation"))
        {
            orientation = (ushort)retrievedProps["System.Photo.Orientation"].Value;
        }

        string creator;
        if (retrievedProps.ContainsKey("/xmp/dc:creator"))
        {
            creator = (string)retrievedProps["/xmp/dc:creator"].Value;
        }
    }
    catch (Exception err)
    {
        switch (err.HResult)
        {
            case unchecked((int)0x88982F41): // WINCODEC_ERR_PROPERTYNOTSUPPORTED
                                             // The file format does not support the requested metadata.
                break;
            case unchecked((int)0x88982F81): // WINCODEC_ERR_UNSUPPORTEDOPERATION
                                             // The file format does not support any metadata.
            default:
                throw err;
        }
    }
}
  • 有关 WIC 元数据查询语言和支持的属性的信息,请参阅 WIC 图像格式本机元数据查询

  • 许多元数据属性仅受图形类型的一个子集支持。 如果请求的属性中的某一个属性不受与解码器关联的图像支持,GetPropertiesAsync 将失败,错误代码为 0x88982F41;如果图像完全不支持元数据,错误代码为 0x88982F81。 与这些错误代码相关联的常量是 WINCODEC_ERR_PROPERTYNOTSUPPORTED 和 WINCODEC_ERR_UNSUPPORTEDOPERATION,它们在 winerror.h 标头文件中定义。

  • 由于不确定图像是否包含特定属性的值,在尝试访问它之前,请使用 IDictionary.ContainsKey 来验证属性是否出现在结果中。

将图像元数据写入流需要与图像输出文件关联的 BitmapEncoder

创建 BitmapPropertySet 对象以包含要设置的属性值。 创建 BitmapTypedValue 对象以表示属性值。 此对象将 object 用作值和定义值类型的 PropertyType 枚举的成员。 将 BitmapTypedValue 添加到 BitmapPropertySet,然后调用 BitmapProperties.SetPropertiesAsync 会导致编码器将属性写入流中。

private async void WriteImageMetadata(BitmapEncoder bitmapEncoder)
{
    var propertySet = new Windows.Graphics.Imaging.BitmapPropertySet();
    var orientationValue = new Windows.Graphics.Imaging.BitmapTypedValue(
        1, // Defined as EXIF orientation = "normal"
        Windows.Foundation.PropertyType.UInt16
        );

    propertySet.Add("System.Photo.Orientation", orientationValue);

    try
    {
        await bitmapEncoder.BitmapProperties.SetPropertiesAsync(propertySet);
    }
    catch (Exception err)
    {
        switch (err.HResult)
        {
            case unchecked((int)0x88982F41): // WINCODEC_ERR_PROPERTYNOTSUPPORTED
                                             // The file format does not support this property.
                break;
            default:
                throw err;
        }
    }
}