实现 IWICBitmapDecoder

IWICBitmapDecoder

当应用程序请求解码器时,与编解码器的第一个交互点是通过 IWICBitmapDecoder 接口。 这是容器级接口,它提供对容器的顶级属性的访问,最重要的是它包含的帧。 这是容器级解码器类的主要接口。

interface IWICBitmapDecoder : IUnknown
{
// Required methods
   HRESULT QueryCapability (IStream *pIStream, 
      DWORD *pdwCapabilities );
   HRESULT Initialize ( IStream *pIStream,
      WICDecodeOptions cacheOptions );
   HRESULT GetContainerFormat ( GUID *pguidContainerFormat );
   HRESULT GetDecoderInfo ( IWICBitmapDecoderInfo **pIDecoderInfo );
   HRESULT GetFrameCount ( UINT *pCount );
   HRESULT GetFrame ( UINT index, 
      IWICBitmapFrameDecode **ppIBitmapFrame );

// Optional methods
   HRESULT GetPreview ( IWICBitmapSource **ppIPreview );
   HRESULT GetThumbnail ( IWICBitmapSource **ppIThumbnail );
   HRESULT GetColorContexts ( UINT cCount, 
      IWICColorContext **ppIColorContexts, 
      UINT *pcActualCount );
   HRESULT GetMetadataQueryReader ( IWICMetadataQueryReader **ppIMetadataQueryReader);
   HRESULT CopyPalette ( IWICPalette *pIPalette );
}

某些图像格式具有全局缩略图、颜色上下文或元数据,而许多图像格式仅按帧提供这些格式。 访问这些项目的方法在 IWICBitmapDecoder 上是可选的,但在 IWICBitmapFrameDecode 上是必需的。 同样,某些编解码器不使用索引像素格式,因此不需要在任一接口上实现 CopyPalette 方法。 有关可选 IWICBitmapDecoder 方法的详细信息,请参阅 实现 IWICBitmapFrameDecode,其中最常实现它们。

QueryCapability

QueryCapability 是用于编解码器仲裁的方法。 (请参阅Windows映像组件工作原理主题) 中的发现和仲裁。 如果两个编解码器能够解码相同的图像格式,或者发生模式冲突时,两个编解码器使用相同的标识模式,则此方法允许你选择最能处理任何特定图像的编解码器。

调用此方法时,Windows映像组件 (WIC) 传递包含图像的实际流。 必须验证是否可以解码图像中的每个帧并通过元数据块进行枚举,以便准确声明此解码器相对于传递给它的特定文件流的功能。 这适用于所有解码器,但对于基于标记图像文件格式 (TIFF) 容器的图像格式尤其重要。 发现过程的工作原理是将注册表中与解码器关联的模式与实际映像文件中的模式匹配。 在注册表中声明标识模式可确保始终为图像格式的图像检测解码器。 但是,对于其他格式的图像,仍可检测到解码器。 例如,所有 TIFF 容器都包含 TIFF 模式,这是 TIFF 图像格式的有效标识模式。 这意味着,在发现期间,对于基于 TIFF 样式容器的任何图像格式,在图像文件中至少会发现两种识别模式。 一个是 TIFF 模式,另一种模式是实际的图像格式模式。 虽然不太可能,但其他不相关的图像格式之间也可能存在模式冲突。 这就是为什么发现和仲裁是一个两个阶段的过程。 请始终验证传递给 QueryCapability 的图像流实际上是你自己的图像格式的有效实例。 此外,如果编解码器解码了不拥有该规范的图像格式, 则 QueryCapability 实现应检查是否存在任何在编解码器未实现的图像格式规范下可能有效的功能。 这将确保用户不会遇到不必要的解码失败,也不会通过编解码器获得意外结果。

在对映像执行任何操作之前,必须保存流的当前位置,以便在从方法返回之前将其还原到其原始位置。 指定功能的 WICBitmapDecoderCapabilities 枚举定义如下:

enum WICBitmapDecoderCapabilities
{   
   WICBitmapDecoderCapabilitySameEncoder,
   WICBitmapDecoderCapabilityCanDecodeAllImages,
   WICBitmapDecoderCapabilityCanDecodeSomeImages,
   WICBitmapDecoderCapabilityCanEnumerateMetadata,
   WICBitmapDecoderCapabilityCanDecodeThumbnail
}

仅当编码器是编码图像的编码器时,才应声明 WICBitmapDecoderCapabilitySameEncoder 。 验证是否可以解码容器中的每个帧后,如果可以解码部分但并非所有帧,则声明 WICBitmapDecodeDecodeCanDecodeSomeImages (如果可以解码所有帧),或者如果无法解码其中任何帧,则声明 WICBitmapDecodeAllImages 。 (这两个枚举互斥:如果返回 WICBitmapDecoderCapabilityCanDecodeAllImagesWICBitmapDecoderCapabilityCanDecodeSomeImages 将被忽略。) 声明 WICBitmapDecoderCapabilityCanEnumerateMetadata 后,验证是否可以通过映像容器中的元数据块进行枚举。 无需检查每个帧中的缩略图。 如果有全局缩略图,可以对其进行解码,则可以声明 WICBitmapDecoderCapabilityCanDecodeThumbnail。 如果没有全局缩略图,则尝试解码 Frame 0 的缩略图。 如果上述任一位置中没有缩略图,请不要声明此功能。

在确定解码器对传递给此方法的图像流的功能后,使用 WICBitmapDecoderCapabilities 执行 OR 操作,你已验证此解码器是否可以在此图像上执行,并返回结果。 在返回之前,请记得将流还原到其原始位置。

初始化

在选择解码器对特定图像进行解码后,应用程序将调用初始化。 图像流传递给解码器,调用方可以选择指定 WICDecodeOptions 缓存选项来处理文件中的元数据。

enum WICDecodeOptions
{
   WICDecodeMetadataCacheOnDemand,
   WICDecodeMetadataCacheOnLoad
}

某些应用程序使用元数据比其他应用程序更多。 大多数应用程序不需要访问图像文件中的所有元数据,并且会根据需要请求特定元数据。 其他应用程序宁愿提前缓存所有元数据,而不是每次需要访问元数据时保持文件流打开和执行磁盘 I/O。 如果调用方未指定元数据缓存选项,则默认缓存行为应按需缓存。 这意味着,在应用程序发出针对该元数据的特定请求之前,不应将元数据加载到内存中。 如果应用程序指定 WICDecodeMetadataCacheOnLoad,则应立即在内存中加载元数据并缓存。 在加载时缓存元数据时,可以在缓存元数据后释放文件流。

GetContainerFormat

若要实现 GetContainerFormat,只需返回初始化解码器的图像的图像格式的 GUID。 此方法也在 IWICMetadataBlockReaderIWICBitmapEncoder 上实现。

GetDecoderInfo

GetDecoderInfo 返回 IWICBitmapDecoderInfo 对象。 若要获取 IWICBitmapDecoderInfo 对象,只需将解码器的 GUID 传递给 IWICImagingFactory 上的 CreateComponentInfo 方法,然后请求其上的 IWICBitmapDecoderInfo 接口,如以下示例所示。

IWICComponentInfo* pComponentInfo = NULL;
HRESULT hr;
 
hr = m_pImagingFactory->CreateComponentInfo(CLSID_This, &pComponentInfo);

hr = pComponentInfo->QueryInterface(IID_IWICBitmapDecoderInfo, (void**)ppIDecoderInfo);

GetFrameCount

GetFrameCount 只返回容器中的帧数。 某些容器格式支持多个帧,而另一些则仅支持每个容器的一个帧。

GetFrame

GetFrameIWICBitmapDecoder 接口上的一个重要方法,因为帧包含实际图像位,并且从此方法返回的帧解码器对象是执行所请求图像的实际解码的对象。 这是编写解码器时需要实现的另一个对象。 有关帧解码器的详细信息,请参阅 实现 IWICBitmapFrameDecode

GetPreview

GetPreview 返回图像预览。 有关预览的详细讨论,请参阅实现 IWICBitmapEncoder 接口上的实现 IWICBitmapEncoder 方法。

如果图像格式包含嵌入的 JPEG 预览,强烈建议不要编写 JPEG 解码器来解码它,而是委托给 WIC 平台随附的 JPEG 解码器,以便解码预览和缩略图。 为此,请在流中查找预览图像数据的开头,并在 IWICImagingFactory 上调用 CreateDecoderFromStream 方法。

IWICBitmapDecoder* pPreviewDecoder = NULL;
IWICBitmapFrameDecode* pPreviewFrame = NULL;
IWICBitmapSource* pPreview = NULL;
HRESULT hr;

hr = m_pImagingFactory->CreateDecoderFromStream(
                               m_pStream, NULL, 
                               WICDecodeMetadataCacheOnDemand, &pPreviewDecoder);
hr = pPreviewDecoder->GetFrame(0, pPreviewFrame);
hr = pPreviewFrame->QueryInterface(IID_IWICBitmapSource, (void**)&pPreview);

参考

IWICBitmapDecoder

IWICBitmapFrameDecode

概念性

解码器接口

实现 IWICBitmapCodecProgressNotification (解码器)

如何编写 WIC-Enabled CODEC

Windows映像组件概述