Metadatos de imagen

En este artículo se muestra cómo leer y escribir las propiedades de los metadatos de imágenes y cómo geoetiquetar archivos mediante la clase de utilidad GeotagHelper.

Propiedades de la imagen

La propiedad StorageFile.Properties devuelve un objeto StorageItemContentProperties que proporciona acceso a información relacionada con el contenido sobre el archivo. Obtenga las propiedades específicas de la imagen mediante una llamada a GetImagePropertiesAsync. El objeto devuelto ImageProperties expone miembros que contienen campos de metadatos de imagen básicos, como el título de la imagen y la fecha de 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 obtener acceso a un conjunto mayor de metadatos de archivo, use el sistema de propiedades de Windows, un conjunto de propiedades de metadatos de archivo que se pueden recuperar con un identificador de cadena único. Cree una lista de cadenas y agregue el identificador de cada propiedad que quiera recuperar. El método ImageProperties.RetrievePropertiesAsync toma esta lista de cadenas y devuelve un diccionario de pares clave-valor donde la clave es el identificador de propiedad y el valor es el valor de propiedad.

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 obtener una lista completa de Windows Propiedades, incluidos los identificadores y el tipo de cada propiedad, vea Windows Properties.

  • Algunas propiedades solo se admiten para determinados contenedores de archivos y códecs de imagen. Para obtener una lista de los metadatos de imagen admitidos para cada tipo de imagen, consulte Directivas de metadatos de fotos.

  • Dado que las propiedades que no se admiten pueden devolver un valor NULL cuando se recuperan, compruebe siempre null antes de usar un valor de metadatos devuelto.

Asistente de geoetiquetado

GeotagHelper es una clase de utilidad que facilita la etiqueta de imágenes con datos geográficos mediante el Windows. Devices.Geolocation API directamente, sin tener que analizar ni construir manualmente el formato de metadatos.

Si ya tiene un objeto Geopoint que representa la ubicación que desea etiquetar en la imagen, ya sea de un uso previo de las API de geolocalización o de alguna otra fuente, puede establecer los datos de geoetiquetado llamando a GeotagHelper.SetGeotagAsync y pasándole un StorageFile y el 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 establecer los datos de geotag mediante la ubicación actual del dispositivo, cree un nuevo objeto Geolocator y llame a GeotagHelper.SetGeotagFromGeolocatorAsync pasando el Geolocator y el archivo que se va a etiquetar.

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);
    }
}
  • Debes incluir la funcionalidad del dispositivo de ubicación en el manifiesto de la aplicación para poder usar la API SetGeotagFromGeolocatorAsync .

  • Debes llamar a RequestAccessAsync antes de llamar a SetGeotagFromGeolocatorAsync para asegurarte de que el usuario ha concedido permiso a la aplicación para usar su ubicación.

  • Para obtener más información sobre la geolocalización y las API de mapas, consulte Control de mapa.

Para obtener un GeoPoint que represente la ubicación geográfica de un archivo de imagen, llame a GetGeotagAsync.

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

Descodificar y codificar metadatos de imagen

La forma más avanzada de trabajar con datos de imagen es leer y escribir las propiedades en el nivel de secuencia mediante un BitmapDecoder o un BitmapEncoder. Para estas operaciones, puede usar Windows Propiedades para especificar los datos que está leyendo o escribiendo, pero también puede usar el lenguaje de consulta de metadatos proporcionado por el Windows Componente de creación de imágenes (WIC) para especificar la ruta de acceso a una propiedad solicitada.

La lectura de los metadatos de una imagen mediante esta técnica requiere disponer de un BitmapDecoder creado a partir del flujo del archivo de imagen de origen. Para obtener información sobre cómo hacerlo, vea Crear, editar y guardar imágenes de mapa de bits.

Una vez que tenga el descodificador, cree una lista de cadenas y agregue una nueva entrada para cada propiedad de metadatos que quiera recuperar, mediante la cadena de identificador de propiedad de Windows o una consulta de metadatos wiC. Llame al método BitmapPropertiesView.GetPropertiesAsync en el miembro BitmapProperties del descodificador para solicitar las propiedades especificadas. Las propiedades se devuelven en un diccionario de pares clave/valor que contiene el nombre o la ruta de la propiedad y el valor de la propiedad.

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 obtener información sobre el lenguaje de consulta de metadatos de WIC y las propiedades admitidas, consulte Consultas de metadatos nativos con formato de imagen WIC.

  • Muchas propiedades de metadatos solo son compatibles con un subconjunto de tipos de imagen. GetPropertiesAsync producirá un error con el código de error 0x88982F41 si una de las propiedades solicitadas no es compatible con la imagen asociada al descodificador y 0x88982F81 si la imagen no admite metadatos en absoluto. Las constantes asociadas a estos códigos de error son WINCODEC_ERR_PROPERTYNOTSUPPORTED y WINCODEC_ERR_UNSUPPORTEDOPERATION, y se definen en el archivo de cabecera winerror.h.

  • Dado que una imagen puede contener o no un valor para una propiedad determinada, use IDictionary.ContainsKey para comprobar que una propiedad está presente en los resultados antes de intentar acceder a ella.

La escritura de los metadatos de la imagen en el flujo requiere un BitmapEncoder asociado al archivo de salida de la imagen.

Cree un objeto BitmapPropertySet para contener los valores de propiedad que desee establecer. Cree un objeto BitmapTypedValue para representar el valor de propiedad. Este objeto usa un object como valor y como miembro de la enumeración PropertyType que define el tipo de dicho valor. Agregue BitmapTypedValue a BitmapPropertySet y, a continuación, llame a BitmapProperties.SetPropertiesAsync para que el codificador escriba las propiedades en el flujo.

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