实现 IWICBitmapFrameEncode

IWICBitmapFrameEncode

IWICBitmapFrameEncode 是编码器的对应 IWICBitmapFrameDecode 接口。 可以在帧级编码类上实现此接口,该类是为每个帧执行图像位的实际编码的类。

interface IWICBitmapFrameEncode : public IUnknown
{
   // Required methods
   HRESULT Initialize ( IPropertyBag2 *pIEncoderOptions );
   HRESULT SetSize ( UINT width,
               UINT height );
   HRESULT SetResolution ( double dpiX,
               double dpiY );
   HRESULT SetPixelFormat (WICPixelFormatGUID *pPixelFormat);
   HRESULT SetColorContexts ( UINT cCount,
               IWICColorContext **ppIColorContext );
   HRESULT GetMetadataQueryWriter ( IWICMetadataQueryWriter 
               **ppIMetadataQueryWriter );
   HRESULT SetThumbnail ( IWICBitmapSource *pIThumbnail );
   HRESULT WritePixels ( UINT lineCount,
               UINT cbStride,
               UINT cbBufferSize,
               BYTE *pbPixels );
   HRESULT WriteSource ( IWICBitmapSource *pIWICBitmapSource,
               WICRect *prc );
   HRESULT Commit ( void );

// Optional method
   HRESULT SetPalette ( IWICPalette *pIPalette );
};

Initialize

Initialize 是实例化 IWICBitmapFrameEncode 对象后对其调用的第一个方法。 此方法有一个参数,该参数可能设置为 NULL。 此参数表示编码器选项,与在容器级解码器的 CreateNewFrame 方法中创建的 IPropertyBag2 实例相同,并在该方法的 pIEncoderOptions 参数中传递回调用方。 当时,你使用表示帧级编码器支持的编码选项的属性填充了 IPropertyBag2 结构。 调用方现在已提供这些属性的值来指示某些编码选项参数,并将同一对象传回给你以初始化 IWICBitmapFrameEncode 对象。 在对图像位进行编码时,应应用指定的选项。

SetSize 和 SetResolution

SetSizeSetResolution 不言而喻。 调用方使用这些方法来指定编码图像的大小和分辨率。

SetPixelFormat

SetPixelFormat 用于请求对图像进行编码的像素格式。 如果不支持请求的像素格式,则应返回 pPixelFormat 中支持的最近像素格式的 GUID,这是一个 in/out 参数。

SetColorContexts

SetColorContexts 用于为此图像指定一个或多个有效的颜色上下文 (也称为颜色配置文件) 。 请务必指定颜色上下文,以便以后解码图像的应用程序可以从源颜色配置文件转换为用于显示或打印图像的设备的目标配置文件。 如果没有颜色配置文件,就无法在不同的设备上获得一致的颜色。 当最终用户的照片在不同的显示器上看起来不同,并且他们无法获取打印内容以匹配他们在屏幕上看到的内容时,这可能会令人沮丧。

GetMetadataQueryWriter

GetMetadataQueryWriter 返回一个 IWICMetadataQueryWriter,应用程序可以使用该 IWICMetadataQueryWriter 在图像帧上的元数据块中插入或编辑特定的元数据属性。

可以通过多种方式从 IWICComponentFactory 实例化 IWICMetadataQueryWriter。 可以从 IWICMetadataBlockWriter 创建它,就像从 IWICBitmapFrameDecode 接口上的 GetMetadataQueryReader 方法中的 IWICMetadataBlockReader 创建 IWICMetadataQueryReader 一样

IWICMetadataQueryWriter* piMetadataQueryWriter = NULL;
HRESULT hr;

hr = m_piComponentFactory->CreateQueryWriterFromBlockWriter( 
      static_cast<IWICMetadataBlockWriter*>(this), 
      &piMetadataQueryWriter);

还可以从现有的 IWICMetadataQueryReader 创建它,例如使用前面的方法获取的 IWICMetadataQueryReader

hr = m_piComponentFactory->CreateQueryWriterFromReader( 
      piMetadataQueryReader, pguidVendor, &piMetadataQueryWriter);

pguidVendor 参数允许指定在实例化元数据编写器时要使用的查询编写器的特定供应商。 例如,如果提供自己的元数据编写器,则可能需要指定自己的供应商 GUID。 如果没有首选项,可以将 NULL 传递给此参数。

SetThumbnail

SetThumbnail 用于提供缩略图。 所有图像都应在全局、每个帧或两者中提供缩略图。 GetThumbnailSetThumbnail 方法在容器级别是可选的,但如果编解码器从 GetThumbnail 方法返回WINCODEC_ERR_CODECNOTHUMBNAIL,Windows 图像处理组件 (WIC) 将为 Frame 0 调用 GetThumbnail 方法。 如果在任一位置都找不到缩略图,WIC 必须解码完整图像并将其缩放为缩略图大小,这可能会对较大的图像造成较大的性能损失。

缩略图的大小和分辨率应该能够快速解码和显示。 因此,缩略图是最常见的 JPEG 图像。 请注意,如果将 JPEG 用于缩略图,则无需编写 JPEG 编码器对缩略图进行编码,也不必编写 JPEG 解码器来解码缩略图。 应始终委托 WIC 平台随附的 JPEG 编解码器,以便对缩略图进行编码和解码。

WritePixels

WritePixels 是用于从内存中的位图传入扫描行进行编码的方法。 将重复调用 方法,直到所有扫描行都已传入。 lineCount 参数指示此调用中要写入的扫描行数。 cbStride 参数指示每个扫描行的字节数。 cbBufferSize 指示在 pbPixels 参数中传递的缓冲区的大小,该参数包含要编码的实际图像位。 如果累积调用中扫描行的组合高度大于 SetSize 方法中指定的高度,则返回WINCODEC_ERR_TOOMANYSCANLINES。

WICBitmapEncoderCacheOptionWICBitmapEncoderCacheInMemory 时,扫描行应缓存在内存中,直到所有扫描行都已传入。 如果编码器缓存选项为 WICBitmapEncoderCacheTempFile,则应将扫描行缓存在初始化对象时创建的临时文件中。 在这两种情况下,在调用方调用 Commit 之前,不应对图像进行编码。 如果缓存选项为 WICBitmapEncoderNoCache,则编码器应尽可能对接收到的扫描行进行编码。 (在某些格式中,这是不可能的,必须在调用 Commit 之前缓存扫描行。)

大多数原始编解码器不会实现 WritePixel,因为它们不支持更改原始文件中的图像位。 但是,原始编解码器仍应实现 WritePixels,因为在添加元数据时,它可能会增大文件大小,从而需要在磁盘上重写文件。 在这种情况下,必须能够复制现有图像位,这就是 WritePixels 方法的作用。

WriteSource

WriteSource 用于对 IWICBitmapSource 对象进行编码。 第一个参数是指向 IWICBitmapSource 对象的指针。 第二个参数是一个 WICRect,指定要编码的感兴趣区域。 只要每个矩形的宽度与要编码的最终图像的宽度相同,就可以连续多次调用此方法。 如果在 prc 参数中传递的矩形的宽度不同于 SetSize 方法中指定的宽度,则返回 WINCODEC_ERR_SOURCERECTDOESNOTMATCHDIMENSIONS。 如果累积调用的扫描行的组合高度大于 SetSize 方法中指定的高度,则返回WINCODEC_ERR_TOOMANYSCANLINES。

缓存选项使用此方法的方式与前面所述的 WritePixels 方法的工作方式相同。

提交

Commit 是将编码图像位序列化到文件流的方法,并循环访问请求将其元数据序列化到流的帧的所有元数据编写器。 如果编码器缓存选项为 WICBitmapEncoderCacheInMemory 或 WICBitmapEncoderCacheTempFile,则此方法还负责对图像进行编码,当缓存选项为 WICBitmapEncoderCacheTempFile 时, Commit 方法还应删除用于在编码之前缓存图像数据的临时文件。

在使用 CommitWriteSource 方法传入构成图像的所有扫描行或矩形之后,始终调用此方法。 通过对 WritePixels 或 WriteSource 的累积调用构成的最终矩形的大小必须与 SetSize 方法中指定的大小相同。 如果大小与预期大小不匹配,此方法应返回WINCODECERROR_UNEXPECTEDSIZE。

若要循环访问元数据编写器并告诉每个元数据编写器将其元数据序列化为流,请调用 GetWriterByIndex 以循环访问每个块的编写器,并在每个元数据编写器上调用 IWICPersistStream.Save。

IWICMetadataWriter* piMetadataWRiter = NULL;
IWICPersistStream* piPersistStream = NULL;
HRESULT hr;

for (UINT x=0; x < m_blockCount; x++) 
{
    hr = GetWriterByIndex(x, & piMetadataWriter);
hr = piMetadataWriter->QueryInterface(
IID_IWICPersistStream,(void**)&piPersistStream);

hr = piPersistStream->Save(m_piStream, 
WICPersistOptions.WicPersistOptionDefault, 
true);
...
}

SetPalette

只有具有索引格式的编解码器需要实现 SetPalette 方法。 如果图像使用索引格式,请使用此方法指定图像中使用的调色板。 如果编解码器没有索引格式,请从此方法返回WINCODEC_ERR_PALETTEUNAVAILABLE。

概念性

实现 IWICBitmapCodecProgressNotification (Encoder)

实现 IWICMetadataBlockWriter

如何编写WIC-Enabled编解码器

Windows 映像组件概述