画像メタデータの読み取りと書き込みの概要

このトピックでは、Windows Imaging Component (WIC) API を使用して、イメージ ファイルに埋め込まれたメタデータの読み取りと書き込みを行う方法の概要について説明します。

このトピックは、次のセクションで構成されています。

前提条件

このトピックを理解するには、「 WIC メタデータの概要」で説明されているように、WIC メタデータ システムについて理解している必要があります。 また、「メタデータ クエリ言語の概要」で説明されているように、メタデータの読み取りと書き込みに使用される クエリ言語についても理解しておく必要があります。

はじめに

WIC は、アプリケーション開発者にコンポーネント オブジェクト モデル (COM) コンポーネントを提供し、イメージ ファイルに埋め込まれたメタデータの読み取りと書き込みを行います。 メタデータの読み取りと書き込みには、次の 2 つの方法があります。

  • クエリ リーダー/ライターとクエリ式を使用して、入れ子になったブロックまたはブロック内の特定のメタデータのメタデータ ブロックに対してクエリを実行します。
  • メタデータ ハンドラー (メタデータ リーダーまたはメタデータ ライター) を使用して、入れ子になったメタデータ ブロックまたはメタデータ ブロック内の特定のメタデータにアクセスします。

最も簡単なのは、クエリ リーダー/ライターとクエリ式を使用してメタデータにアクセスすることです。 クエリ リーダー (IWICMetadataQueryReader) を使用してメタデータを読み取り、クエリ ライター (IWICMetadataQueryWriter) を使用してメタデータを書き込みます。 どちらもクエリ式を使用して、目的のメタデータの読み取りまたは書き込みを行います。 バックグラウンドでは、クエリ リーダー (およびライター) はメタデータ ハンドラーを使用して、クエリ式によって記述されたメタデータにアクセスします。

より高度なメソッドは、メタデータ ハンドラーに直接アクセスすることです。 メタデータ ハンドラーは、ブロック リーダー (IWICMetadataBlockReader) またはブロック ライター (IWICMetadataBlockWriter) を使用して、個々フレームから取得されます。 使用できるメタデータ ハンドラーの 2 種類は、メタデータ リーダー (IWICMetadataReader) とメタデータ ライター (IWICMetadataWriter) です。

このトピックの例では、JPEG イメージ ファイルの内容を次の図に示します。 この図で表される画像は、Microsoft ペイントを使用して作成されました。評価メタデータは、Windows Vista のフォト ギャラリー機能を使用して追加されました。

評価メタデータを含む jpeg 画像の図

クエリ リーダーを使用したメタダデータの読み取り

メタデータを読み取る最も簡単な方法は、クエリ リーダー インターフェイス IWICMetadataQueryReader を使用することです。 クエリ リーダーを使用すると、クエリ式を使用してメタデータ ブロックとメタデータ ブロック内の項目を読み取ることができます。

クエリ リーダーを取得するには、ビットマップ デコーダー (IWICBitmapDecoder)、個々のフレーム (IWICBitmapFrameDecode)、またはクエリ ライター (IWICMetadataQueryWriter) の 3 つの方法があります。

クエリ リーダーの取得

次のコード例は、イメージング ファクトリからビットマップ デコーダーを取得し、個々のビットマップ フレームを取得する方法を示しています。 このコードでは、デコードされたフレームからクエリ リーダーを取得するために必要なセットアップ作業も実行します。

IWICImagingFactory *pFactory = NULL;
IWICBitmapDecoder *pDecoder = NULL;
IWICBitmapFrameDecode *pFrameDecode = NULL;
IWICMetadataQueryReader *pQueryReader = NULL;
IWICMetadataQueryReader *pEmbedReader = NULL;
PROPVARIANT value;

// Initialize COM
CoInitialize(NULL);

// Initialize PROPVARIANT
PropVariantInit(&value);

//Create the COM imaging factory
HRESULT hr = CoCreateInstance(
    CLSID_WICImagingFactory,
    NULL,
    CLSCTX_INPROC_SERVER,
    IID_IWICImagingFactory,
    (LPVOID*)&pFactory);

// Create the decoder
if (SUCCEEDED(hr))
{
    hr = pFactory->CreateDecoderFromFilename(
        L"test.jpg",
        NULL,
        GENERIC_READ,
        WICDecodeMetadataCacheOnDemand,
        &pDecoder);
}

// Get a single frame from the image
if (SUCCEEDED(hr))
{
    hr = pDecoder->GetFrame(
         0,  //JPEG has only one frame.
         &pFrameDecode); 
}

test.jpg ファイルのビットマップ デコーダーは、イメージング ファクトリの CreateDecoderFromFilename メソッドを使用して取得されます。 このメソッドでは、4 番目のパラメーターは WICDecodeOptions 列挙の値 WICDecodeMetadataCacheOnDemand に設定されます。 これにより、メタデータが必要になったときにメタデータをキャッシュするようにデコーダーに指示されます。クエリ リーダーまたは基になるメタデータ リーダーを取得します。 このオプションを使用すると、高速メタデータ エンコードに必要なメタデータへのストリームを保持でき、JPEG イメージのロスレス デコードが可能になります。 または、他の WICDecodeOptions 値 WICDecodeMetadataCacheOnLoad を使用して、イメージが読み込まれるとすぐに埋め込みイメージ メタデータをキャッシュすることもできます。

フレームのクエリ リーダーを取得するには、フレームの GetMetadataQueryReader メソッドを簡単に呼び出します。 次のコードは、この呼び出しを示しています。

// Get the query reader
if (SUCCEEDED(hr))
{
    hr = pFrameDecode->GetMetadataQueryReader(&pQueryReader);
}

同様に、クエリ リーダーもデコーダー レベルで取得できます。 デコーダーの GetMetadataQueryReader メソッドを簡単に呼び出すと、デコーダーのクエリ リーダーが取得されます。 デコーダーのクエリ リーダーは、フレームのクエリ リーダーとは異なり、個々のフレームの外部にあるイメージのメタデータを読み取ります。 ただし、このシナリオは一般的ではなく、ネイティブ イメージ形式ではこの機能はサポートされていません。 WIC によって提供されるネイティブ イメージ コーデックは、JPEG などの単一フレーム形式の場合でも、フレーム レベルでメタデータを読み取りおよび書き込みます。

メタデータの読み取り

実際にメタデータを読み取る前に、埋め込みメタデータ ブロックと取得する実際のデータを含む JPEG ファイルの次の図を参照してください。 この図では、画像内の特定のメタデータ ブロックとアイテムへの吹き出しを提供し、メタデータ クエリ式を各ブロックまたは項目に提供します。

メタデータ吹き出しを含む jpeg 画像の図

埋め込まれたメタデータ ブロックまたは特定のアイテムを名前で照会するには、 GetMetadataByName メソッドを呼び出します。 このメソッドは、クエリ式と、メタデータ項目が返される PROPVARIANT を受け取ります。 次のコードは、入れ子になったメタデータ ブロックを照会し、PROPVARIANT 値によって提供される IUnknown コンポーネントが見つかった場合にクエリ リーダーに変換します。

if (SUCCEEDED(hr))
{
    // Get the nested IFD reader
    hr = pQueryReader->GetMetadataByName(L"/app1/ifd", &value);
    if (value.vt == VT_UNKNOWN)
    {
        hr = value.punkVal->QueryInterface(IID_IWICMetadataQueryReader, (void **)&pEmbedReader);
    }
    PropVariantClear(&value); // Clear value for new query
}

クエリ式 "/app1/ifd" は、App1 ブロックに入れ子になった IFD ブロックに対してクエリを実行しています。 JPEG イメージ ファイルには IFD 入れ子になったメタデータ ブロックが含まれているため、PROPVARIANT は の変数型 (vt) と IUnknown インターフェイス (punkVal) VT_UNKNOWN へのポインターを使用して返されます。 次に、クエリ リーダーの IUnknown インターフェイスに対してクエリを実行します。

次のコードは、入れ子になった IFD ブロックに対する新しいクエリ リーダーに基づく新しいクエリを示しています。

if (SUCCEEDED(hr))
{
    hr = pEmbedReader->GetMetadataByName(L"/{ushort=18249}", &value);
    PropVariantClear(&value); // Clear value for new query
}

クエリ式 "/{ushort=18249}" は、タグ 18249 に埋め込まれた MicrosoftPhoto 評価の IFD ブロックに対してクエリを実行します。 PROPVARIANT 値には、 の値型VT_UI2と 50 のデータ値が含まれるようになりました。

ただし、特定のデータ値に対してクエリを実行する前に、入れ子になったブロックを取得する必要はありません。 たとえば、入れ子になった IFD に対してクエリを実行してから MicrosoftPhoto 評価を照会する代わりに、ルート メタデータ ブロックと次のコードに示すクエリを使用して、同じ情報を取得できます。

if (SUCCEEDED(hr))
{
    hr = pQueryReader->GetMetadataByName(L"/app1/ifd/{ushort=18249}", &value);
    PropVariantClear(&value);
}

メタデータ ブロック内の特定のメタデータ 項目に対するクエリに加えて、メタデータ ブロック内のすべてのメタデータ 項目を列挙することもできます (入れ子になったメタデータ ブロック内のメタデータ項目は含まれません)。 現在のブロック内のメタデータ項目を列挙するために、クエリ リーダーの GetEnumeration メソッドが使用されます。 このメソッドは、現在のブロック内のメタデータ項目が設定された IEnumString インターフェイスを取得します。 たとえば、次のコードは、前に取得した入れ子になった IFD ブロックの XMP 評価と MicrosoftPhoto 評価を列挙します。

IEnumString *metadataItems = NULL;

if (SUCCEEDED(hr))
{
    hr = pEmbedReader->GetEnumerator(&metadataItems);
}

さまざまなイメージ形式とメタデータ形式に適したタグを識別する方法の詳細については、「 ネイティブ イメージ形式メタデータ クエリ」を参照してください。

その他のクエリ リーダー メソッド

メタデータの読み取りに加えて、クエリ リーダーに関する追加情報を取得し、他の方法でメタデータを取得することもできます。 クエリ リーダーには、クエリ リーダー GetContainerFormat と GetLocation に関する情報を提供する 2 つのメソッド が用意されています

埋め込みクエリ リーダーを使用すると、 GetContainerFormat を 使用してメタデータ ブロックの種類を決定できます。 また、GetLocation を呼び出して、ルート メタデータ ブロックに対する相対パスを取得できます。 次のコードは、埋め込みクエリ リーダーにその場所を照会します。

// Determine the metadata block format

if (SUCCEEDED(hr))
{
    hr = pEmbedReader->GetContainerFormat(&containerGUID);
}

// Determine the query reader's location
if (SUCCEEDED(hr))
{
    UINT length;
    WCHAR readerNamespace[100];
    hr = pEmbedReader->GetLocation(100, readerNamespace, &length);
}

埋め込みクエリ リーダーの GetContainerFormat を呼び出すと、IFD メタデータ形式 GUID が返されます。 GetLocation の呼び出しは、"/app1/ifd" の名前空間を返します。新しいクエリ リーダーへの後続のクエリの実行元となる相対パスを指定します。 もちろん、上記のコードはあまり役に立ちませんが、入れ子になったメタデータ ブロックを検索するために GetLocation メソッドを使用する方法を示しています。

クエリ ライターを使用したメタデータの書き込み

注意

このセクションで提供されるコード例の一部は、メタデータの書き込みに必要な実際の手順のコンテキストでは示されていません。 作業サンプルのコンテキストでコード例を表示するには、「方法: メタデータを使用してイメージを再エンコードする」チュートリアルを参照してください。

 

メタデータを書き込むメイン コンポーネントは、クエリ ライター (IWICMetadataQueryWriter) です。 クエリ ライターを使用すると、メタデータ ブロック内のメタデータ ブロックと項目を設定および削除できます。

クエリ リーダーと同様に、クエリ ライターを取得するには、ビットマップ エンコーダー (IWICBitmapEncoder)、個々のフレーム (IWICBitmapFrameEncode)、高速メタデータ エンコーダー (IWICFastMetadataEncoder) の 3 つの方法があります。

クエリ ライターの取得

最も一般的なクエリ ライターは、ビットマップの個々のフレームです。 このクエリ ライターは、イメージ フレームのメタデータ ブロックと項目を設定および削除します。 イメージ フレームのクエリ ライターを取得するには、フレームの GetMetadataQueryWriter メソッドを呼び出します。 次のコードは、フレームのクエリ ライターを取得するための単純なメソッド呼び出しを示しています。

IWICMetadataQueryWriter &pFrameQWriter = NULL;

//Obtain a query writer from the frame.
hr = pFrameEncode->GetMetadataQueryWriter(&pFrameQWriter);

同様に、エンコーダー レベルに対してクエリ ライターを取得することもできます。 エンコーダーの GetMetadataQueryWriter メソッドを簡単に呼び出すと、エンコーダーのクエリ ライターが取得されます。 エンコーダーのクエリ ライターは、フレームのクエリ ライターとは異なり、個々のフレームの外部にあるイメージのメタデータを書き込みます。 ただし、このシナリオは一般的ではなく、ネイティブ イメージ形式ではこの機能はサポートされていません。 WIC によって提供されるネイティブ イメージ コーデックは、JPEG などの単一フレーム形式の場合でも、フレーム レベルでメタデータを読み取りおよび書き込みます。

また、イメージング ファクトリ (IWICImagingFactory) から直接クエリ ライターを取得することもできます。 クエリ ライターを返すイメージング ファクトリ メソッドには、CreateQueryWriter と CreateQueryWriterFromReader の 2 つがあります。

CreateQueryWriter は 、指定されたメタデータ形式とベンダーのクエリ ライターを作成します。 このクエリ ライターを使用すると、特定のメタデータ形式のメタデータを書き込み、それをイメージに追加できます。 次のコードは、XMP クエリ ライターを作成するための CreateQueryWriter 呼び出しを示しています。

IWICMetadataQueryWriter *pXMPWriter = NULL;

// Create XMP block
GUID vendor = GUID_VendorMicrosoft;
hr = pFactory->CreateQueryWriter(
        GUID_MetadataFormatXMP,
        &vendor,
        &pXMPWriter);

この例では、フレンドリ名 GUID_MetadataFormatXMPguidMetadataFormat パラメーターとして使用されます。 これは XMP メタデータ形式 GUID を表し、ベンダーは Microsoft によって作成されたハンドラーを表します。 または、他の XMP ハンドラーが存在しない場合は、同じ結果を持つ pguidVendor パラメーターとして NULL を渡すことができます。 ネイティブ XMP ハンドラーと共にカスタム XMP ハンドラーがインストールされている場合、ベンダーに NULL を 渡すと、返される GUID が最も低いクエリ ライターになります。

CreateQueryWriterFromReaderCreateQueryWriter メソッドに似ていますが、新しいクエリ ライターにクエリ リーダーによって提供されるデータが事前に設定される点が除きます。 これは、既存のメタデータを維持しながらイメージを再エンコードする場合や、不要なメタデータを削除する場合に便利です。 次のコードは、 CreateQueryWriterFromReader 呼び出しを示しています。

hr = pFrameDecode->GetMetadataQueryReader(&pFrameQReader);

// Copy metadata using query readers
if(SUCCEEDED(hr) && pFrameQReader)
{
    IWICMetadataQueryWriter *pNewWriter = NULL;

    GUID vendor = GUID_VendorMicrosoft;
    hr = pFactory->CreateQueryWriterFromReader(
        pFrameQReader,
        &vendor,
        &pNewWriter);

メタデータの追加

クエリ ライターを取得したら、それを使用してメタデータ ブロックと項目を追加できます。 メタデータを書き込むには、クエリ ライターの SetMetadataByName メソッドを 使用します。 SetMetadataByName は、クエリ式 (wzName) と PROPVARIANT (pvarValue) へのポインターという 2 つのパラメーターを受け取ります。 クエリ式は設定するブロックまたは項目を定義しますが、PROPVARIANT は設定する実際のデータ値を提供します。

次の例では、 CreateQueryWriter メソッドを使用して以前に取得した XMP クエリ ライターを使用してタイトルを追加する方法を示します。

// Write metadata to the XMP writer
if (SUCCEEDED(hr))
{
    PROPVARIANT value;
    PropVariantInit(&value);

    value.vt = VT_LPWSTR;
    value.pwszVal = L"Metadata Test Image.";
   
    hr = pXMPWriter->SetMetadataByName(L"/dc:title", &value);

    PropVariantClear(&value);
}

この例では、値の型 (vt) が に VT_LPWSTR設定され、文字列がデータ値として使用されることを示します。 の型は文字列であるため、pwszVal を使用して、使用するタイトルを設定します。 SetMetadataByName は、クエリ式 "/dc:title" と新しく設定された PROPVARIANT を使用して呼び出されます。 使用されるクエリ式は、デジタル カメラ (dc) スキーマの title プロパティを設定する必要があることを示します。 式が "/xmp/dc:title" ではないことに注意してください。これは、クエリ ライターが XMP に既に固有であり、埋め込み XMP ブロックが含まれていないためです。これは、"/xmp/dc:title" が推奨します。

ここまでは、実際に画像フレームにメタデータを追加していません。 クエリ ライターにデータを設定するだけです。 クエリ ライターによって表されるメタデータ ブロックをフレームに追加するには、再び PROPVARIANT の値としてクエリ ライターを使用して SetMetadataByName を呼び出します。 これにより、クエリ ライター内のメタデータがイメージ フレームに効果的にコピーされます。 次のコードは、以前に取得した XMP クエリ ライターのメタデータをフレームのルート メタデータ ブロックに追加する方法を示しています。

// Get the frame's query writer and write the XMP query writer to it
if (SUCCEEDED(hr))
{
    hr = pFrameEncode->GetMetadataQueryWriter(&pFrameQWriter);

    // Copy the metadata in the XMP query writer to the frame
    if (SUCCEEDED(hr))
    {
        PROPVARIANT value;

        PropVariantInit(&value);
        value.vt = VT_UNKNOWN;
        value.punkVal = pXMPWriter;
        value.punkVal->AddRef();

        hr = pFrameQWriter->SetMetadataByName(L"/", &value);

        PropVariantClear(&value);
    }
}

この例では、 の値型 (vt) VT_UNKOWN が使用されます。COM インターフェイスの値の型を示します。 その後、XMP クエリ ライター (piXMPWriter) が PROPVARIANT の値として使用され、AddRef メソッドを使用して参照が追加されます。 最後に、XMP クエリ ライターを設定するには、フレームの SetMetadataByName メソッドを呼び出し、ルート ブロックと新しく設定された PROPVARIANT を示すクエリ式 "/" を渡します。

注意

追加しようとしているメタデータ ブロックがフレームに既に含まれている場合は、追加するメタデータが追加され、既存のメタデータが上書きされます。

 

メタデータの削除

クエリ ライターを使用すると、 RemoveMetadataByName メソッドを呼び出してメタデータを削除することもできます。 RemoveMetadataByName はクエリ式を受け取り、メタデータ ブロックまたはアイテムが存在する場合は削除します。 次のコードは、以前に追加されたタイトルを削除する方法を示しています。

if (SUCCEEDED(hr))
{
    hr = pFrameQWriter->RemoveMetadataByName(L"/xmp/dc:title");
}

次のコードは、XMP メタデータ ブロック全体を削除する方法を示しています。

if (SUCCEEDED(hr))
{
    hr = pFrameQWriter->RemoveMetadataByName(L"/xmp");
}

再エンコード用のメタデータのコピー

注意

このセクションのコードは、ソースとコピー先のイメージの形式が同じ場合にのみ有効です。 別のイメージ形式にエンコードする場合、1 回の操作ですべてのイメージのメタデータをコピーすることはできません。

 

イメージを同じイメージ形式に再エンコードするときにメタデータを保持するために、すべてのメタデータを 1 回の操作でコピーできるメソッドがあります。 これらの各操作は、同様のパターンに従います。では、デコードされたフレームのメタデータがエンコードされる新しいフレームに直接設定されます。

メタデータをコピーする方法として推奨される方法は、デコードされたフレームのブロック リーダーを使用して、新しいフレームのブロック ライターを初期化することです。 次のコードは、このメソッドを示しています。

if (SUCCEEDED(hr) && formatsEqual)
{
    // Copy metadata using metadata block reader/writer
    if (SUCCEEDED(hr))
    {
        pFrameDecode->QueryInterface(
            IID_IWICMetadataBlockReader,
            (void**)&pBlockReader);
    }
    if (SUCCEEDED(hr))
    {
        pFrameEncode->QueryInterface(
            IID_IWICMetadataBlockWriter,
            (void**)&pBlockWriter);
    }
    if (SUCCEEDED(hr))
    {
        pBlockWriter->InitializeFromBlockReader(pBlockReader);
    }
}

この例では、ブロック リーダーとブロック ライターは、それぞれソース フレームとターゲット フレームから取得されます。 その後、ブロック ライターはブロック リーダーから初期化されます。 これにより、ブロック リーダーの事前設定されたメタデータを使用してブロック リーダーが初期化されます。

メタデータをコピーするもう 1 つの方法は、エンコーダーのクエリ ライターを使用してクエリ リーダーによって参照されるメタデータ ブロックを書き込む方法です。 次のコードは、このメソッドを示しています。

if (SUCCEEDED(hr) && formatsEqual)
{
    hr = pFrameDecode->GetMetadataQueryReader(&pFrameQReader);

    // Copy metadata using query readers
    if(SUCCEEDED(hr))
    {
        hr = pFrameEncode->GetMetadataQueryWriter(&pFrameQWriter);
        if (SUCCEEDED(hr))
        {
            PropVariantClear(&value);
            value.vt=VT_UNKNOWN;
            value.punkVal=pFrameQReader;
            value.punkVal->AddRef();
            hr = pFrameQWriter->SetMetadataByName(L"/", &value);
            PropVariantClear(&value);
        }
    }
}

ここで、クエリ リーダーはデコードされたフレームから取得され、値型が VT_UNKNOWN に設定された PROPVARIANT のプロパティ値として使用されます。 エンコーダーのクエリ ライターが取得され、クエリ式 "/" を使用して、ルート ナビゲーション パスにメタデータが設定されます。 クエリ式を目的の場所に調整することで、入れ子になったメタデータ ブロックを設定するときにも、このメソッドを使用できます。

同様に、イメージング ファクトリの CreateQueryWriterFromReader メソッドを使用して、デコードされたフレームのクエリ リーダーに基づいてクエリ ライターを作成できます。 この操作で作成されたクエリ ライターには、クエリ リーダーからのメタデータが事前設定され、フレームで設定できます。 次のコードは、 CreateQueryWriterFromReader コピー操作を示しています。

IWICMetadataQueryWriter *pNewWriter = NULL;

GUID vendor = GUID_VendorMicrosoft;
hr = pFactory->CreateQueryWriterFromReader(
    pFrameQReader,
    &vendor,
    &pNewWriter);

if (SUCCEEDED(hr))
{
    // Get the frame's query writer
    hr = pFrameEncode->GetMetadataQueryWriter(&pFrameQWriter);
}

// Set the query writer to the frame.
if (SUCCEEDED(hr))
{
    PROPVARIANT value;

    PropVariantInit(&value);
    value.vt = VT_UNKNOWN;
    value.punkVal = pNewWriter;
    value.punkVal->AddRef();
    hr = pFrameQWriter->SetMetadataByName(L"/",&value);
}

このメソッドは、クエリ リーダーのデータに基づいて作成される個別のクエリ ライターを使用します。 この新しいクエリ ライターは、フレームに設定されます。

ここでも、メタデータをコピーするこれらの操作は、ソース イメージとコピー先イメージの形式が同じ場合にのみ機能します。 これは、異なるイメージ形式でメタデータ ブロックが異なる場所に格納されるためです。 たとえば、JPEG と TIFF の両方で XMP メタデータ ブロックがサポートされます。 JPEG 画像では、「 WIC メタデータの概要」に示すように、XMP ブロックはルート メタデータ ブロックにあります。 ただし、TIFF イメージでは、XMP ブロックはルート IFD ブロックに入れ子になっています。 次の図は、JPEG 画像と同じ評価メタデータを持つ TIFF イメージの違いを示しています。

jpeg と tiff の比較。

高速メタデータ エンコード

新しいメタデータを書き込むには、必ずしもイメージを再エンコードする必要はありません。 メタデータは、高速メタデータ エンコーダーを使用して書き込むこともできます。 高速メタデータ エンコーダーでは、イメージを再エンコードすることなく、限られた量のメタデータをイメージに書き込むことができます。 これは、一部のメタデータ形式によって提供される空のパディング内に新しいメタデータを書き込むことで実現されます。 メタデータの埋め込みをサポートするネイティブ メタデータ形式は、Exif、IFD、GPS、XMP です。

メタデータ ブロックへのパディングの追加

高速メタデータ エンコードを実行するには、メタデータ ブロック内に、より多くのメタデータを書き込むスペースが必要です。 既存のパディング内に新しいメタデータを書き込むのに十分なスペースがない場合、高速メタデータ エンコードは失敗します。 画像にメタデータ パディングを追加するには、イメージを再エンコードする必要があります。 埋め込み中のメタデータ ブロックでサポートされている場合は、クエリ式を使用して、他のメタデータ項目を追加するのと同じ方法でパディングを追加できます。 次の例では、App1 ブロックに埋め込まれた IFD ブロックにパディングを追加する方法を示します。

if (SUCCEEDED(hr))
{
    // Add metadata padding
    PROPVARIANT padding;

    PropVariantInit(&padding);
    padding.vt = VT_UI4;
    padding.uiVal = 4096; // 4KB

    hr = pFrameQWriter->SetMetadataByName(L"/app1/ifd/PaddingSchema:padding", &padding);

    PropVariantClear(&padding);
}

パディングを追加するには、VT_UI4型の PROPVARIANT と、追加するパディングのバイト数に対応する値を作成します。 一般的な値は 4096 バイトです。 JPEG、TIFF、JPEG-XR のメタデータ クエリを次の表に示します。

メタデータ形式 JPEG メタデータ クエリ TIFF、JPEG-XR メタデータ クエリ
IFD /app1/ifd/PaddingSchema:Padding /ifd/PaddingSchema:Padding
Exif /app1/ifd/exif/PaddingSchema:Padding /ifd/exif/PaddingSchema:Padding
Xmp /xmp/PaddingSchema:Padding /ifd/xmp/PaddingSchema:Padding
GPS /app1/ifd/gps/PaddingSchema:Padding /ifd/gps/PaddingSchema:Padding

 

高速メタデータ エンコーダーの取得

メタデータ パディングを含むイメージがある場合は、イメージング ファクトリ メソッド CreateFastMetadataEncoderFromDecoderCreateFastMetadataEncoderFromFrameDecode を使用して高速メタデータ エンコーダーを取得できます。

名前が示すように、 CreateFastMetadataEncoderFromDecoder はデコーダー レベルのメタデータ用の高速メタデータ エンコーダーを作成します。 WIC によって提供されるネイティブ イメージ形式はデコーダー レベルのメタデータをサポートしていませんが、このようなイメージ形式が将来開発される場合に備えて、このメソッドが提供されます。

より一般的なシナリオは、 CreateFastMetadataEncoderFromFrameDecode を使用して、イメージ フレームから高速メタデータ エンコーダーを取得することです。 次のコードは、デコードされたフレームの高速メタデータ エンコーダーを取得し、App1 ブロックの評価値を変更します。

if (SUCCEEDED(hr))
{
    IWICFastMetadataEncoder *pFME = NULL;
    IWICMetadataQueryWriter *pFMEQW = NULL;

    hr = pFactory->CreateFastMetadataEncoderFromFrameDecode(
        pFrameDecode, 
        &pFME);
}

高速メタデータ エンコーダーの使用

高速メタデータ エンコーダーから、クエリ ライターを取得できます。 これにより、前に示したようにクエリ式を使用してメタデータを記述できます。 クエリ ライターでメタデータが設定されたら、高速メタデータ エンコーダーをコミットしてメタデータの更新を完了します。 次のコードは、メタデータの変更の設定とコミットを示しています

    if (SUCCEEDED(hr))
    {
        hr = pFME->GetMetadataQueryWriter(&pFMEQW);
    }

    if (SUCCEEDED(hr))
    {
        // Add additional metadata
        PROPVARIANT value;

        PropVariantInit(&value);

        value.vt = VT_UI4;
        value.uiVal = 99;
        hr = pFMEQW->SetMetadataByName(L"/app1/ifd/{ushort=18249}", &value);

        PropVariantClear(&value);
    }

    if (SUCCEEDED(hr))
    {
        hr = pFME->Commit();
    }
}

何らかの理由 でコミット が失敗した場合は、イメージを再エンコードして、新しいメタデータがイメージに追加されるようにする必要があります。

概念

Windows イメージング コンポーネントの概要

WIC メタデータの概要

メタデータ クエリ言語の概要

メタデータ機能拡張の概要

方法: メタデータを使用して JPEG イメージを再エンコードする