本文說明如何閱讀與撰寫影像元資料屬性,以及如何使用 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 dateTaken = props.DateTaken;
}
若要存取更多檔案元資料,請使用 Windows 屬性系統,這是一組可用唯一字串識別碼檢索的檔案元資料屬性。 建立一個字串清單,並為每個你想取得的屬性加上識別碼。 ImageProperties.RetrievePropertiesAsync 方法會將這串字串列列返回一個鍵/值對字典,其中鍵為屬性識別碼,值為屬性值。
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"];
}
}
欲了解完整的Windows屬性清單,包括每個屬性的識別碼與類型,請參見 Windows 屬性。
部分屬性僅支援特定的檔案容器和影像編碼器。 關於每種影像類型支援的影像元資料清單,請參見 照片元資料政策。
由於不支援的屬性在檢索時可能會回傳 null 值,因此在使用回傳的元資料值前,務必先檢查是否為 null。
地理標籤輔助工具
GeotagHelper 是一個公用程式類別,可讓您直接使用 Windows.Devices.Geolocation API,輕鬆為影像加上地理資料標記,而無需手動解析或建立中繼資料格式。
如果您已經有一個 Geopoint 物件,表示您想在影像中加上標記的位置,無論是先前使用地理位置 API 所取得,還是來自其他來源,您都可以呼叫 GeotagHelper.SetGeotagAsync,並傳入 StorageFile 和 Geopoint,以設定地理標記資料。
private async void SetGeoDataFromPoint(StorageFile imageFile)
{
var point = new Geopoint(
new BasicGeoposition
{
Latitude = 48.8567,
Longitude = 2.3508,
});
await GeotagHelper.SetGeotagAsync(imageFile, point);
}
若要使用裝置目前位置設定地理標籤資料,請建立一個新的 Geolocator 物件,並呼叫 GeotagHelper.SetGeotagFromGeolocatorAsync,並輸入 Geolocator 及待標記的檔案。
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);
}
}
您必須在您的應用程式清單中包含 定位 裝置功能,才能使用 SetGeotagFromGeolocatorAsync API。
你必須先打給 RequestAccessAsync ,再呼叫 SetGeotagFromGeolocatorAsync ,確認使用者已授權你的應用程式使用他們的位置。
欲了解更多地理定位與地圖 API 資訊,請參見 地圖控制。
要取得代表圖片檔案地理標籤位置的 GeoPoint,請呼叫 GetGeotagAsync。
private async void GetGeoData(StorageFile imageFile)
{
Geopoint geoPoint = await GeotagHelper.GetGeotagAsync(imageFile);
}
解碼與編碼影像元資料
處理影像資料最先進的方式,是使用 BitmapDecoder 或 BitmapEncoder 在資料流層級讀取及寫入屬性。 在這些操作中,您可以使用 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;
}
}
}
關於 WIC 元資料查詢語言及其所支援屬性的資訊,請參見 WIC 影像格式的原生元資料查詢。
許多元資料屬性僅由部分影像類型支援。 GetPropertiesAsync 會因錯誤代碼而失敗0x88982F41若解碼器所關聯的圖片不支援其中一個請求屬性,0x88982F81若圖片完全不支援元資料。 與這些錯誤碼相關的常數是WINCODEC_ERR_PROPERTYNOTSUPPORTED和WINCODEC_ERR_UNSUPPORTEDOPERATION,並定義在 winerror.h 標頭檔案中。
由於圖片可能包含或不包含特定屬性的值,請在嘗試存取前使用 IDictionary.ContainsKey 驗證該屬性是否存在於結果中。
若要將影像中繼資料寫入串流,需要使用與影像輸出檔案相關聯的 BitmapEncoder。
建立一個 BitmapPropertySet 物件來包含你想要設定的屬性值。 建立一個 BitmapTypedValue 物件來表示屬性值。 此物件使用 object 作為值,並使用 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;
}
}
}
關於支援哪些屬性及哪些影像檔案類型,請參閱 Windows 屬性、照片元資料政策,以及 WIC 影像格式原生元資料查詢。
SetPropertiesAsync 如果要求的屬性之一不受與編碼器相關聯的映像支援,將會失敗,並顯示錯誤碼 0x88982F41。