共用方式為


影像中繼資料

本文介紹如何讀取和寫入影像中繼資料屬性,以及如何使用 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 輕鬆地使用地理資料標記影像,而無需手動解析或建立中繼資料格式。

如果您已經有一個 Geopoint 物件來表示要標記在影像中的位置 (無論是來自先前使用的地理定位 API 還是其他來源),您可以透過呼叫 GeotagHelper.SetGeotagAsync 並傳入 StorageFileGeopoint

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

await GeotagHelper.SetGeotagAsync(imageFile, point);

若要使用裝置的目前位置設定地理標記資料,請建立一個新的 Geolocator 物件並呼叫 GeotagHelper.SetGeotagFromGeolocatorAsync 傳入 Geolocator 和要標記的檔案。

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;如果影像根本不支援中繼資料,則 GetPropertiesAsync 將失敗並顯示錯誤代碼 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;
        }
    }
}