實作 IWICMetadataBlockReader
IWICMetadataBlockReader
影像中通常會有多個元數據區塊,每個區塊都會以不同的格式公開不同類型的資訊。 在 Windows Imaging Component (WIC) 模型中,元數據處理程式是與解碼器類似的獨立元件,可以在執行時發現。 每個元數據格式都有個別的處理程式,而且每個元數據處理程式都可以與任何支援其處理之元數據格式的影像格式搭配使用。 因此,如果您的影像格式支援 EXIF、XMP、IPTC 或其他格式,您可以利用隨附 WIC 之這些格式的標準元數據處理程式,而您不需要自行撰寫。 當然,如果您建立新的元數據格式,您必須為其撰寫元數據處理程式,這會在運行時間探索和叫用,就像標準元數據一樣。
注意
如果您的影像格式是以標記影像檔案格式 (TIFF) 或 JPEG 容器為基礎,則不需要撰寫任何元數據處理程式(除非您開發新的或專屬元數據格式)。 在 TIFF 和 JPEG 容器中,元數據區塊位於 IFD 中,每個容器都有不同的 IFD 結構。 WIC 為這兩種容器格式提供 IFD 處理程式,這些處理程式會巡覽 IFD 結構,並委派給標準元數據處理程式,以存取其中的元數據。 因此,如果您的影像格式是以這其中一個容器為基礎,您可以自動利用 WIC IFD 處理程式。 不過,如果您有專屬的容器格式,其本身具有唯一的最上層元數據結構,您必須撰寫處理程式,該處理程式可以巡覽該最上層結構並委派給適當的元數據處理程式,就像 IFD 處理程式所做的一樣。
WIC 為應用程式提供一層抽象概念的方式相同,讓應用程式能夠透過一組一致的介面來使用所有影像格式,WIC 為編解碼器作者提供元數據格式的抽象層。 如先前所述,編解碼器作者通常不需要直接使用影像中可能出現的各種元數據格式。 不過,每個編解碼器作者都會負責提供一種方式來列舉元數據區塊,以便探索並具現化每個區塊的適當元數據處理程式。
您必須在框架層級譯碼類別上實作這個介面。 如果您的影像格式公開任何個別影像框架以外的全域元數據,您可能也需要在容器層級譯碼器類別上實作它。
interface IWICMetadataBlockReader : IUnknown
{
// All methods required
HRESULT GetContainerFormat ( GUID *pguidContainerFormat );
HRESULT GetCount ( UINT *pcCount );
HRESULT GetEnumerator ( IEnumUnknown **ppIEnumMetadata );
HRESULT GetReaderByIndex ( UINT nIndex, IWICMetadataReader **ppIMetadataReader );
}
GetContainerFormat
GetContainerFormat 與 實作 IWICBitmapDecoder上的 GetContainerFormat 方法相同。
GetCount
GetCount 會傳回與框架相關聯的最上層元數據區塊數目。
GetEnumerator
GetEnumerator 傳回一個列舉器,呼叫者可以用來遍歷框架中的元數據區塊,並讀取其元數據。 若要實作這個方法,您必須為每個元數據區塊建立元數據讀取器,並實作列舉對象來列舉元數據讀取器集合。 列舉對象必須實作 IEnumUnknown,以便在您在 ppIEnumMetadata 參數中傳回它時,將其轉換成 IEnumUnknown。
實作列舉物件時,您可以在第一次建立 IWICMetadataBlockReader 物件或第一次建立列舉物件時,建立所有元數據讀取器,或者您可以在 IEnumUnknown::Next 方法 的實作中輕鬆建立它們。 在許多情況下,以延遲方式建立它們會更有效率,但在下列範例中,為了節省空間,區塊讀取器全都會在建構函式中建立。
public class MetadataReaderEnumerator : public IEnumUnknown
{
UINT m_current;
UINT m_blockCount;
IWICMetadataReader** m_ppMetadataReader;
IStream* m_pStream;
MetadataReaderEnumerator()
{
// Set m_blockCount to the number of metadata blocks in the frame.
...
m_ppMetadataReader = IWICMetadataReader*[m_blockCount];
m_current = 0;
for (UINT x=0; x < m_blockCount; x++)
{
// Find the position in the file where the xth
// block of metadata lives and seek m_piStream
// to that position.
...
m_pComponentFactory->CreateMetadataReaderFromContainer(
GUID_ContainerFormatTiff,
NULL,
WICPersistOptions.WICPersistOptionsDefault |
WICMetadataCreationOptions.WICMetadataCreationDefault,
m_pStream, &m_ppMetadataReader[x]);
}
}
// Implementation of IEnumUnknown and IUnknown interfaces
...
}
若要建立元數據讀取器,您可以使用 CreateMetadataReaderFromContainer 方法。 叫用此方法時,您會在 guidContainerFormat 參數中傳入容器格式的 GUID。 如果您有偏好的元數據讀取器廠商,您可以在 pGuidVendor 參數中提供您慣用廠商的 GUID。 例如,如果您的公司寫入元數據處理程式,而且您想要在存在時使用自己的處理程式,您可以傳入廠商 GUID。 在大部分情況下,您只要傳遞 NULL,讓系統選取適當的元數據讀取器。 如果您確實要求特定廠商,且該廠商已安裝計算機上的元數據讀取器,WIC 會傳回該廠商的讀取器。 不過,如果要求的廠商未在計算機上安裝元數據讀取器,而且如果有適當的元數據讀取器可供使用,即使該讀取器不是來自慣用的廠商,還是會傳回該讀取器。 如果計算機上沒有適用於該類型元數據的元數據讀取器,元件工廠將傳回「未知元數據處理程式」,它會將元數據區塊視為二進位大型物件(BLOB),並且會從檔案中反序列化該元數據區塊,而不嘗試剖析。
針對 dwOptions 參數,請在適當的 WICMetadataCreationOptions與適當的 WICPersistOptions 之間執行 OR 運算。 WICPersistOptions 描述容器的配置方式。Little-endian 是預設值。
enum WICPersistOptions
{
WICPersistOptionDefault,
WICPersistOptionLittleEndian,
WICPersistOptionBigEndian,
WICPersistOptionStrictFormat,
WICPersistOptionNoCacheStream,
WICPersistOptionPreferUTF8
};
WICMetadataCreationOptions 指定在電腦上找不到可讀取特定區塊中繼資料格式的讀取器時,是否返回 UnknownMetadataHandler。 WICMetadataCreationAllowUnknown 是預設值,您應該一律允許建立 UnknownMetadtataHandler。 UnknownMetadataHandler 會將無法辨識的元數據視為 BLOB。 它無法解析,但會將其作為 BLOB 寫入數據流,並在編碼時寫回數據流時保持原樣。 這可讓您安全地為未隨附於系統的專屬元數據或元數據格式建立元數據處理程式。 因為元數據會保持不變,即使計算機上沒有可辨識它的處理程式,在稍後安裝適當的元數據處理程式時,元數據仍會存在且可讀取。 如果您不允許建立 UnknownMetadataHandler,替代方式就是捨棄或覆寫無法辨識的元數據。 這是數據遺失的形式。
注意事項
如果您為專有元數據撰寫自己的元數據處理程式,就不應包含對元數據區塊本身之外的任何內容的參考。 即使 UnknownMetadataHandler 會保留元數據不變,但編輯檔案時,元數據仍會移動,而且當發生這種情況時,任何對本身區塊外任何參考都不會再有效。
enum WICMetadataCreationOptions
{
WICMetadataCreationDefault = 0x00000000,
WICMetadataCreationAllowUnknown = WICMetadataCreationDefault,
WICMetadataCreationFailUnknown = 0x00010000,
WICMetadataCreationMask = 0xFFFF0000
};
pIStream 參數是您解碼的實際數據流。 在傳入數據流之前,您應該先尋找您要要求讀取器的元數據區塊開頭。 IStream 中目前位置之元數據區塊的適當元數據讀取器,將會在 ppiReader 參數中傳回。
GetReaderByIndex
GetReaderByIndex 傳回集合中要求索引處的元數據讀取器。
相關主題
-
參考
-
概念