实现 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 。 验证是否可以解码容器中的每个帧后,如果可以解码部分但不是所有帧,请声明 WICBitmapDecoderCapabilityCanDecodeSomeImages ;如果可以解码所有帧,则声明 WICBitmapDecoderCapabilityCanDecodeAllImages;如果无法解码其中任何帧,则不声明 WICBitmapDecoderCapabilityCanDecodeAllImages 。 (这两个枚举是互斥的;如果返回 WICBitmapDecoderCapabilityCanDecodeAllImages,则将忽略 WICBitmapDecoderCapabilityCanDecodeSomeImages 。) 验证是否可以枚举图像容器中的元数据块后声明 WICBitmapDecoderCapabilityCanEnumerateMetadata 。 无需为每个帧中的缩略图检查。 如果存在全局缩略图并且可以对其进行解码,则可以声明 WICBitmapDecoderCapabilityCanDecodeThumbnail。 如果没有全局缩略图,则尝试解码帧 0 的缩略图。 如果这两个位置中的任何一个位置都没有缩略图,请不要声明此功能。

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

Initialize

选择 解码器对特定图像进行解码后,应用程序将调用初始化。 图像流将传递给解码器,调用方可以选择指定 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 返回图像预览。 有关预览版的详细讨论,请参阅 Implementing IWICBitmapEncoder 接口上的 Implementing 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编解码器

Windows 映像组件概述