Метаданные изображений

В этой статье показано, как считывать и записывать свойства метаданных изображения и как выполнять геотег-файлы с помощью класса служебной программы 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 принимает этот список строк и возвращает словарь пар key/value, где ключ является идентификатором свойства, и значением является значение свойства.

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 — это служебный класс, который позволяет легко помечать изображения с географическими данными с помощью API Windows.Devices.Geolocation напрямую, не анализируя или создавая формат метаданных вручную.

Если у вас уже есть объект Geopoint, представляющий расположение, которое вы хотите пометить на изображении, либо из предыдущего использования API геолокации или другого источника, можно задать данные геотега, вызвав GeotagHelper.SetGeotagAsync и передав в StorageFile и Geopoint.

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

await GeotagHelper.SetGeotagAsync(imageFile, point);

Чтобы задать данные геотега с помощью текущего расположения устройства, создайте новый объект Геолокатора и вызовите объект 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);
}
  • Чтобы использовать API SetGeotagFromGeolocatorAsync, необходимо включить функцию устройства расположения в манифест приложения.

  • Перед вызовом SetGeotagFromGeolocatorAsync необходимо вызвать RequestAccessAsync, чтобы убедиться, что пользователь предоставил приложению разрешение на использование своего расположения.

  • Дополнительные сведения об API географического расположения см. в разделе "Карты" и "Расположение".

Чтобы получить GeoPoint, представляющую географическое расположение файла изображения, вызовите GetGeotagAsync.

Geopoint geoPoint = await GeotagHelper.GetGeotagAsync(imageFile);

Декодирование и кодирование метаданных изображения

Самый сложный способ работы с данными изображения — чтение и запись свойств на уровне потока с помощью BitmapDecoder или BitmapEncoder. Для этих операций можно использовать свойства Windows для указания данных, которые вы читаете или записываете, но также можно использовать язык запросов метаданных, предоставляемый компонентом образов Windows (WIC), чтобы указать путь к запрошенным свойствам.

Чтение метаданных изображения с помощью этого метода требует наличия bitmapDecoder , созданного с помощью потока файлов исходного образа. Сведения о том, как это сделать, см. в разделе "Образы".

После создания декодировщика создайте список строк и добавьте новую запись для каждого свойства метаданных, которое вы хотите получить, используя строку идентификатора свойства Windows или запрос метаданных WIC. Вызовите метод BitmapPropertiesView.GetPropertiesAsync для элемента BitmapProperties декодера, чтобы запросить указанные свойства. Свойства возвращаются в словаре пар "ключ-значение", содержащих имя свойства или путь и значение свойства.

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 для представления значения свойства. Этот объект использует объект в качестве значения и члена перечисления 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;
        }
    }
}
  • Дополнительные сведения о том, какие свойства поддерживаются для типов файлов изображений, см. в разделе "Свойства Windows", "Политики метаданных фотографий" и запросы собственных метаданных формата WIC.

  • SetPropertiesAsync завершится ошибкой с кодом ошибки 0x88982F41 если одно из запрошенных свойств не поддерживается изображением, связанным с кодировщиком.