イメージのメタデータ

この記事では、画像のメタデータ プロパティを読み取ったり書き込んだりする方法のほか、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 を直接使って簡単にタグを設定することができます。メタデータの形式を手動で解析したり構築したりする必要はありません。

地理位置情報 API の使用後など、タグの設定対象となる画像の位置情報を表す Geopoint オブジェクトが取得済みで、そのオブジェクトが既に存在する場合は、GeotagHelper.SetGeotagAsyncStorageFileGeopoint を渡して呼び出すことで位置情報タグ データを設定できます。

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

画像メタデータのデコードとエンコード

画像データを操作する最も高度な方法は、BitmapDecoder または BitmapEncoder を使って、プロパティの読み取りと書き込みをストリーム レベルで行うことです。 これらの操作では、読み取りまたは書き込みの対象データを Windows プロパティを使って指定できるほか、要求するプロパティのパスを Windows Imaging Component (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 で失敗します。画像がどのメタデータもサポートしていない場合は、0x88982F81 で失敗します。 これらのエラー コードに関連付けられている定数はそれぞれ WINCODEC_ERR_PROPERTYNOTSUPPORTED と WINCODEC_ERR_UNSUPPORTEDOPERATION であり、winerror.h ヘッダー ファイルに定義されています。

  • 特定のプロパティの値が画像に存在するかどうかはわからないので、IDictionary.ContainsKey を使って、結果にプロパティが存在するかどうかを確かめたうえでアクセスしてください。

画像のメタデータをストリームに書き込むには、画像の出力ファイルに関連付けられている BitmapEncoder が必要です。

設定対象プロパティの値を保持する BitmapPropertySet オブジェクトを作成します。 プロパティの値を表す BitmapTypedValue オブジェクトを作成します。 このオブジェクトでは、値の型を定義する PropertyType 列挙型の値およびメンバーとして object を使います。 BitmapTypedValueBitmapPropertySet に追加したうえで、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;
        }
    }
}