Metadatos de imagen

En este artículo se muestra cómo leer y escribir propiedades de metadatos de imagen 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 del archivo. Obtén las propiedades específicas de la imagen mediante una llamada a GetImagePropertiesAsync. El objeto ImageProperties devuelto expone los miembros que contienen los campos básicos de metadatos de la imagen, 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 date = props.DateTaken;
    if (date == null)
    {
        // Format does not support, or image does not contain DateTaken property
    }
}

Para acceder a un conjunto de metadatos de archivo más grande, usa el Sistema de propiedades de Windows, un conjunto de propiedades de metadatos de archivo que se pueden recuperar con un identificador de cadena único. Crea una lista de cadenas y agrega el identificador a cada propiedad que quieras recuperar. El método ImageProperties.RetrievePropertiesAsync toma esta lista de cadenas y devuelve un diccionario de pares de clave y valor, donde la clave es el identificador de propiedad y el valor es el valor de propiedad.

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 las propiedades de Windows, incluidos los identificadores y el tipo de cada propiedad, vea Propiedades de Windows.

  • Algunas propiedades solo son compatibles con ciertos códecs de imagen y contenedores de archivos. 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 son compatibles pueden devolver un valor nulo cuando se recuperan, siempre debes comprobar los valores nulos antes de usar un valor de metadatos devueltos.

Geolocalizar auxiliares

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

Si ya tienes un objeto Geopoint que represente la ubicación que quieres etiquetar en la imagen, ya sea desde un uso anterior de la API de ubicación geográfica o desde otro origen, puedes establecer los datos de geoetiqueta con una llamada a GeotagHelper.SetGeotagAsync y pasando un elemento StorageFile y el elemento Geopoint.

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

await GeotagHelper.SetGeotagAsync(imageFile, point);

Para establecer los datos de geoetiqueta mediante el uso de la ubicación actual del dispositivo, crea un objeto Geolocator nuevo y llama a la API GeotagHelper.SetGeotagFromGeolocatorAsync pasando un elemento Geolocator y el archivo que se va a etiquetar.

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 obtener un elemento GeoPoint que represente la ubicación geoetiquetada de un archivo de imagen, llama a GetGeotagAsync.

Geopoint geoPoint = await GeotagHelper.GetGeotagAsync(imageFile);

Descodificar y codificar los 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 elemento BitmapDecoder o BitmapEncoder. Para estas operaciones puedes usar las propiedades de Windows para especificar los datos de lectura o escritura, pero también puedes usar el lenguaje de consulta de metadatos proporcionado por Windows Imaging Component (WIC) para especificar la ruta de acceso a una propiedad solicitada.

La lectura de metadatos de imagen con esta técnica requiere que dispongas de un elemento BitmapDecoder que se creó con la secuencia de archivos de imagen de origen. Para obtener información sobre cómo hacerlo, consulta Creación de imágenes.

Cuando tengas el descodificador, crea una lista de cadenas y agrega una entrada nueva para cada propiedad de metadatos que quieras recuperar, usando la cadena de identificador de propiedad de Windows o una consulta de metadatos WIC. Llama al método BitmapPropertiesView.GetPropertiesAsync en el miembro BitmapProperties del decodificador para solicitar las propiedades especificadas. Las propiedades se devuelven en un diccionario de pares clave y valor que contiene el nombre de la propiedad o la ruta de acceso 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 err;
        }
    }
}
  • 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 no se realizará correctamente con el código de error 0x88982F41 si una de las propiedades solicitadas no es compatible con la imagen asociada con el descodificador y con el código 0x88982F81 si la imagen no admite metadatos. Las constantes asociadas a estos códigos de error se WINCODEC_ERR_PROPERTYNOTSUPPORTED y WINCODEC_ERR_UNSUPPORTEDOPERATION y se definen en el archivo de encabezado winerror.h.

  • Como una imagen puede contener o no un valor para una propiedad concreta, usa el elemento IDictionary.ContainsKey para comprobar que una propiedad está presente en los resultados antes de intentar acceder a ella.

La escritura de metadatos de imagen en la secuencia requiere un elemento BitmapEncoder asociado al archivo de resultado de la imagen.

Crea un objeto BitmapPropertySet que contenga los valores de propiedad que quieras establecer. Crea un objeto BitmapTypedValue para representar el valor de propiedad. Este objeto se usa un elemento object como el valor y miembro de la enumeración de PropertyType que define el tipo de valor. Agrega el elemento BitmapTypedValue a BitmapPropertySet y luego llama a BitmapProperties.SetPropertiesAsync para que el codificador escriba las propiedades en la secuencia.

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