实现 IWICMetadataBlockReader

IWICMetadataBlockReader

图像中通常存在多个元数据块,每个块以不同的格式公开不同类型的信息。 在 Windows 映像组件 (WIC) 模型中,元数据处理程序是不同的组件,如解码器,可在运行时发现。 每种元数据格式都有一个单独的处理程序,其中每个元数据处理程序都可以与支持它所处理的元数据格式的任何图像格式一起使用。 因此,如果图像格式支持 EXIF、XMP、IPTC 或其他格式,则可以利用 WIC 附带的这些格式的标准元数据处理程序,而无需编写自己的格式。 当然,如果创建新的元数据格式,则必须为其编写元数据处理程序,该处理程序将在运行时发现和调用,就像标准格式一样。

注意

如果映像格式基于标记图像文件格式 (TIFF) 或 JPEG 容器,则无需 (编写任何元数据处理程序,除非) 开发新的或专有的元数据格式。 在 TIFF 和 JPEG 容器中,元数据块位于 IFD 中,每个容器具有不同的 IFD 结构。 WIC 为这两种容器格式提供 IFD 处理程序,用于导航 IFD 结构并委托标准元数据处理程序来访问其中元数据。 因此,如果映像格式基于其中任一容器,则可以自动利用 WIC IFD 处理程序。 但是,如果你的专有容器格式具有其自己唯一的顶级元数据结构,则必须编写一个处理程序,该处理程序可以导航该顶级结构并委托给相应的元数据处理程序,就像 IFD 处理程序 do.)

 

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 返回集合中请求索引处的元数据读取器。

参考

IWICMetadataBlockReader

概念性

实现 IWICBitmapFrameDecode

实现 IWICBitmapSourceTransform

如何编写WIC-Enabled CODEC

Windows 映像组件概述