共用方式為


讀取和寫入影像元數據的概觀

本主題提供如何使用 Windows 映射元件 (WIC) API 來讀取和寫入內嵌在圖像檔案中的元數據的概觀。

本主題包含下列各節。

先決條件

若要瞭解本主題,您應該熟悉 WIC 元數據系統,如 WIC 元數據概觀中所述。 您也應該熟悉用來讀取和寫入元數據的查詢語言,如 元數據查詢語言概觀中所述。

介紹

WIC 為應用程式開發人員提供元件物件模型 (COM) 元件,以讀取和寫入內嵌在影像檔中的元數據。 有兩種方式可以讀取和寫入元數據:

  • 使用查詢讀取器/寫入器和查詢表達式來查詢元數據區塊,以獲得巢狀區塊或區塊內特定元數據。
  • 使用元數據處理程式(元數據讀取器或元數據寫入器)來存取巢狀元數據區塊或元數據區塊內的特定元數據。

其中最簡單的方式是使用查詢讀取器/寫入器和查詢表達式來存取元數據。 查詢讀取器(IWICMetadataQueryReader)用來讀取元數據,而查詢寫入器(IWICMetadataQueryWriter) 則用來寫入元數據。 這兩者都使用查詢表達式來讀取或寫入所需的元數據。 在幕後,查詢讀取器(和寫入器)會使用元數據處理程式來存取查詢表達式所描述的元數據。

更進階的方法是直接存取元數據處理程式。 元數據處理程式是使用區塊讀取器(IWICMetadataBlockReader)或區塊寫入器從個別框架取得(IWICMetadataBlockWriter)。 可用的元數據處理程式有兩種類型的元數據讀取器(IWICMetadataReader)和元數據寫入器(IWICMetadataWriter)。

在本主題的範例中,將反覆使用顯示 JPEG 影像檔內容的下圖。 此圖表所代表的影像是使用 Microsoft Paint 建立的;評等元數據是使用 Windows Vista 的相片庫功能新增的。

jpeg 影像的圖例,具有評等元數據

使用查詢讀取器讀取 Metadadata

讀取元資料最簡單的方式是使用查詢讀取器介面,IWICMetadataQueryReader。 查詢讀取器可讓您使用查詢表達式讀取元數據區塊和元數據區塊內的專案。

有三種方式可以取得查詢讀取器:透過位圖譯碼器(IWICBitmapDecoder)、透過其個別框架(IWICBitmapFrameDecode),或透過查詢寫入器 (IWICMetadataQueryWriter)。

獲取查詢閱讀器

下列範例程式代碼示範如何從映像處理站取得位圖譯碼器,並擷取個別點圖框架。 此程式代碼也會執行從譯碼框架取得查詢讀取器所需的設定工作。

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

使用映像處理站的 CreateDecoderFromFilename 方法來取得 test.jpg 檔案的點圖譯碼器。 在此方法中,第四個參數會設定為來自 WICDecodeOptions 列舉的值 WICDecodeMetadataCacheOnDemand。 這會告訴譯碼器在需要元數據時,將其快取起來,可以透過獲取查詢讀取器或使用基礎元數據讀取器來實現。 使用此選項可以讓您保留數據流到元數據,這是快速元數據編碼所需,同時實現 JPEG 圖像的無失真解碼。 或者,您可以使用另一個WICDecodeOptions 值 WICDecodeMetadataCacheOnLoad,這會在映像載入後立即快取內嵌中繼資料。

若要取得框架的查詢讀取器,請簡單呼叫框架的 GetMetadataQueryReader 方法。 下列程式代碼示範此呼叫。

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

同樣地,您也可以在譯碼器層級取得查詢讀取器。 簡單呼叫解碼器的 GetMetadataQueryReader 方法即可取得查詢讀取器。 解碼器的查詢讀取器與框的查詢讀取器不同,會讀取個別框架之外影像的元數據。 不過,此案例並不常見,原生映像格式不支援此功能。 WIC 所提供的原生影像 CODECS,即使在 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) 傳回 VT_UNKNOWN,以及 IUnknown 介面 (punkVal) 的指標。 接著,您可以查詢查詢讀取器的 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);
}

如需識別各種影像格式和元數據格式適當標記的詳細資訊,請參閱 原生影像格式元數據查詢

其他查詢讀取器方法

除了讀取元數據之外,您也可以取得查詢讀取器的其他資訊,並透過其他方式取得元數據。 查詢讀取器提供兩種方法,提供查詢讀取器的相關信息,GetContainerFormatGetLocation

使用內嵌查詢讀取器,您可以使用 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)。

取得查詢撰寫器

最常見的查詢生成器是針對位圖的個別影格。 此查詢工具會設定並移除影像框架的元數據區塊和項目。 若要取得影像框架的查詢寫入器,請呼叫框架的 GetMetadataQueryWriter 方法。 下列程式碼示範了取得框架的查詢編寫器的簡單方法呼叫。

IWICMetadataQueryWriter &pFrameQWriter = NULL;

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

同樣地,我們也可以為編碼器層級獲取一個查詢器。 簡單呼叫編碼器的 GetMetadataQueryWriter 方法會取得編碼器的查詢編輯器。 編碼器的查詢寫入器,不同於框架的查詢寫入器,會為個別畫面外部的影像寫入元數據。 不過,此案例並不常見,原生映像格式不支援此功能。 WIC 所提供的原生影像編解碼器,即使在 JPEG 等單一框架格式的情況下,也會在畫面層級讀取和寫入元數據。

您也可以直接從影像工廠取得查詢生成器(IWICImagingFactory)。 傳回查詢寫入器的映像處理站方法有兩種:CreateQueryWriterCreateQueryWriterFromReader

CreateQueryWriter 為指定的元數據格式和供應商建立查詢寫入器。 此查詢寫入器可讓您撰寫特定元數據格式的元數據,並將其新增至影像。 下列程式代碼示範建立 XMP 查詢寫入器的 CreateQueryWriter 呼叫。

IWICMetadataQueryWriter *pXMPWriter = NULL;

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

在此範例中,易記名稱 GUID_MetadataFormatXMP 會作為 guidMetadataFormat 參數。 它代表 XMP 元數據格式 GUID,而廠商則代表Microsoft建立的處理程式。 或者,如果沒有任何其他 XMP 處理程式存在,NULL 可以傳遞為具有相同結果的 pguidVendor 參數。 如果自定義 XMP 處理程式與原生 XMP 處理程式一起安裝,則為廠商傳遞 NULL 會導致傳回最低 GUID 的查詢寫入器。

CreateQueryWriterFromReader 類似於 CreateQueryWriter 方法,不同之處在於它會使用查詢讀取器所提供的數據,預先填入新的查詢寫入器。 這適用於在維護現有元數據時重新編碼影像,或移除不需要的元數據。 下列程式代碼示範 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)。 查詢表達式會定義要設定的區塊或專案,而 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 用來設定要使用的標題。 接著會使用查詢表達式 「/dc:title」 和新設定 PROPVARIANT來呼叫 SetMetadataByName。 使用的查詢表達式表示應該設定數位相機架構中的「標題」屬性。 請注意,此表達式並非「/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_UNKOWN 的實值型別 (vt) ;表示 COM 介面實值型別。 接著,將 XMP 查詢編寫器(piXMPWriter)當作 PROPVARIANT的值,並使用 AddRef 方法來新增對它的參考。 最後,透過呼叫框架的 SetMetadataByName 方法設定 XMP 查詢寫入器,傳遞查詢表達式 “/”,以指向根區塊,並設置新的 PROPVARIANT。

注意

如果框架已經包含您嘗試新增的元數據區塊,則會新增您要新增的元數據,並覆寫現有的元數據。

 

移除元數據

查詢寫入器也可讓您透過呼叫 移除MetadataByName 方法來移除元數據。 RemoveMetadataByName 會接受查詢表達式,並在存在時移除元數據區塊或項目。 下列程式代碼示範如何移除先前新增的標題。

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

下列程式代碼示範如何移除整個 XMP 元數據區塊。

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

複製用於重新編碼的元數據

備註

只有在來源和目的地影像格式相同時,本節中的程序代碼才有效。 當編碼為不同的影像格式時,您無法在單一作業中複製影像的所有元數據。

 

若要在將影像重新編碼為相同的影像格式時保留元數據,有一種方法可用來複製單一作業中的所有元數據。 每個作業都遵循類似的模式;每個都會將譯碼框架的元數據直接設定為要編碼的新框架。

慣用的方法是以解碼後的框架之區塊讀取器來初始化新框架的區塊寫入器,以複製元數據。 下列程式代碼示範這個方法。

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

在此範例中,區塊讀取器和區塊寫入器會分別從來源畫面格和目的地框架取得。 然後,區塊寫入器會從區塊讀取器初始化。 這會使用區塊讀取器預先填入的元數據,初始化區塊讀取器。

複製元數據的另一種方法是使用編碼器的查詢寫入器來寫入查詢讀取器所參考的元數據區塊。 下列程式代碼示範這個方法。

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

在這裡,將查詢讀取器從解碼框架中獲取後,用作 PROPVARIANT 的屬性值,並將值的類型設置為 VT_UNKNOWN。 取得編碼器的查詢寫入器,並使用查詢表達式 「/」 在根導覽路徑上設定元數據。 您也可以在設定巢狀元數據區塊時,透過調整查詢表達式至所需位置來使用此方法。

同樣地,您可以使用圖像工廠的 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 映射中,XMP 區塊位於根元數據區塊,如 WIC 元數據概觀所示。 不過,在 TIFF 映射中,XMP 區塊會巢狀於根 IFD 區塊中。 下圖說明 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();
    }
}

如果 Commit 因為任何原因而失敗,您必須重新編碼影像,以確保將新的元數據新增至影像。

概念

Windows 映射元件概觀

WIC 元數據概觀

元數據查詢語言概觀

元數據擴充性概觀

指南:使用元數據重新編碼 JPEG 圖片