Metadados de imagem

Este artigo mostra como ler e gravar propriedades de metadados de imagem e como geografar arquivos usando a classe de utilitário GeotagHelper.

Propriedades da imagem

A propriedade StorageFile.Properties retorna um objeto StorageItemContentProperties que fornece acesso a informações relacionadas ao conteúdo sobre o arquivo. Obtenha as propriedades específicas da imagem chamando GetImagePropertiesAsync. O objeto ImageProperties expõe membros que contêm campos de metadados de imagem básicos, como o título da imagem e a data da captura.

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 dateTaken = props.DateTaken;
}

Para acessar um conjunto maior de metadados de arquivo, use o Windows Property System, um conjunto de propriedades de metadados de arquivo que podem ser recuperadas com um identificador de cadeia de caracteres exclusivo. Crie uma lista de cadeias de caracteres e adicione o identificador para cada propriedade que você deseja recuperar. O método ImageProperties.RetrievePropertiesAsync usa essa lista de cadeias de caracteres e retorna um dicionário de pares chave/valor em que a chave é o identificador de propriedade e o valor é o valor da propriedade.

private async void GetWindowsProperties(StorageFile imageFile)
{
    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"];
    }
}
  • Para obter uma lista completa de propriedades de Windows, incluindo os identificadores e o tipo de cada propriedade, consulte Windows Properties.

  • Algumas propriedades têm suporte apenas para determinados contêineres de arquivo e codecs de imagem. Para obter uma listagem dos metadados de imagem com suporte para cada tipo de imagem, consulte Políticas de Metadados de Foto.

  • Como as propriedades sem suporte podem retornar um valor nulo quando recuperadas, sempre verifique se há nulo antes de usar um valor de metadados retornado.

Assistente de georreferenciamento

GeotagHelper é uma classe de utilitário que facilita a marcação de imagens com dados geográficos usando o Windows. Devices.Geolocation APIs diretamente, sem precisar analisar ou construir manualmente o formato de metadados.

Se você já tiver um objeto Geopoint que represente o local que deseja associar à imagem, seja de um uso anterior das APIs de geolocalização ou de alguma outra fonte, você poderá definir os dados de geotag chamando GeotagHelper.SetGeotagAsync e passando um StorageFile e o Geopoint.

private async void SetGeoDataFromPoint(StorageFile imageFile)
{
    var point = new Geopoint(
        new BasicGeoposition
        {
            Latitude = 48.8567,
            Longitude = 2.3508,
        });

    await GeotagHelper.SetGeotagAsync(imageFile, point);
}

Para definir os dados de geotag usando a localização atual do dispositivo, crie um novo objeto Geolocator e chame GeotagHelper.SetGeotagFromGeolocatorAsync passando o Geolocator e o arquivo a ser marcado.

private async void SetGeoDataFromGeolocator(StorageFile imageFile)
{
    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);
    }
}

Para obter um GeoPoint que representa o local geografático de um arquivo de imagem, chame GetGeotagAsync.

private async void GetGeoData(StorageFile imageFile)
{
    Geopoint geoPoint = await GeotagHelper.GetGeotagAsync(imageFile);
}

Decodificar e codificar metadados de imagem

A maneira mais avançada de trabalhar com dados de imagem é ler e gravar as propriedades no nível do fluxo usando um BitmapDecoder ou um BitmapEncoder. Para essas operações, você pode usar Windows Propriedades para especificar os dados que está lendo ou gravando, mas também pode usar a linguagem de consulta de metadados fornecida pelo WIC (Componente de Imagem Windows) para especificar o caminho para uma propriedade solicitada.

Ler metadados de imagem usando essa técnica exige que você tenha um BitmapDecoder que foi criado com o fluxo de arquivos de imagem de origem. Para obter informações sobre como fazer isso, consulte Criar, editar e salvar imagens de bitmap.

Depois de obter o decodificador, crie uma lista de cadeias de caracteres e adicione uma nova entrada para cada propriedade de metadados que você deseja recuperar, usando a cadeia de caracteres identificadora de propriedade do Windows ou uma consulta de metadados do WIC. Chame o método BitmapPropertiesView.GetPropertiesAsync no membro BitmapProperties do decodificador para solicitar as propriedades especificadas. As propriedades são retornadas em um dicionário de pares chave/valor que contém o nome ou o caminho da propriedade e o valor da propriedade.

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;
        }
    }
}
  • Para obter informações sobre a linguagem de consulta de metadados WIC e as propriedades compatíveis, consulte consultas nativas de metadados do formato de imagem WIC.

  • Muitas propriedades de metadados só têm suporte por um subconjunto de tipos de imagem. GetPropertiesAsync falhará com o código de erro 0x88982F41 se uma das propriedades solicitadas não tiver suporte pela imagem associada ao decodificador e 0x88982F81 se a imagem não oferecer suporte a metadados. As constantes associadas a esses códigos de erro são WINCODEC_ERR_PROPERTYNOTSUPPORTED e WINCODEC_ERR_UNSUPPORTEDOPERATION e são definidas no arquivo de cabeçalho winerror.h.

  • Como uma imagem pode ou não conter um valor para uma propriedade específica, use IDictionary.ContainsKey para verificar se uma propriedade está presente nos resultados antes de tentar acessá-la.

Gravar metadados de imagem no fluxo requer um BitmapEncoder associado ao arquivo de saída da imagem.

Crie um objeto BitmapPropertySet para conter os valores de propriedade que você deseja definir. Crie um objeto BitmapTypedValue para representar o valor da propriedade. Esse objeto usa um object como o valor e o membro da enumeração PropertyType que define o tipo do valor. Adicione o BitmapTypedValue ao BitmapPropertySet e, em seguida, chame BitmapProperties.SetPropertiesAsync para fazer com que o codificador escreva as propriedades no fluxo.

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;
        }
    }
}