如何将一组Direct2D位图保存为动态图像?解决帧覆盖问题
问题根源
你直接复用了同一个IWICBitmapFrameEncode对象写入所有帧,WIC的帧编码器实例是绑定单帧的,重复调用WriteSource只会覆盖当前实例对应的帧,而非添加新帧。
正确实现步骤
针对多帧图像格式(如GIF),需要为每帧创建独立的IWICBitmapFrameEncode实例,流程如下:
- 创建并初始化
IWICImagingFactory和IWICBitmapEncoder(指定支持多帧的格式,比如GUID_ContainerFormatGif)
- 创建并初始化
- 为每一张Direct2D位图执行以下操作:
- 调用
IWICBitmapEncoder::CreateNewFrame获取新的IWICBitmapFrameEncode实例 - 设置当前帧的属性(如GIF的延迟时间、帧处理方式等,可选但建议设置,否则可能播放异常)
- 将Direct2D位图转换为WIC位图(可通过
ID2D1DeviceContext::CreateBitmapRenderTarget绘制,或直接锁定内存拷贝) - 调用
IWICBitmapFrameEncode::WriteSource写入当前帧的WIC位图数据 - 调用
IWICBitmapFrameEncode::Commit提交当前帧
- 所有帧处理完成后,调用
IWICBitmapEncoder::Commit完成整个编码过程
- 所有帧处理完成后,调用
代码示例(C++)
// 假设已初始化pImagingFactory、pEncoder(绑定到输出流),并有Direct2D位图数组pD2DBitmaps for (auto& pD2DBitmap : pD2DBitmaps) { CComPtr<IWICBitmapFrameEncode> pFrameEncode; HRESULT hr = pEncoder->CreateNewFrame(&pFrameEncode, nullptr); if (FAILED(hr)) break; // 设置GIF帧属性:延迟100ms,播放后恢复背景色 PROPVARIANT propVar; PropVariantInit(&propVar); propVar.vt = VT_UI2; propVar.uiVal = 10; // GIF延迟单位为1/100秒,此处对应100ms pFrameEncode->SetMetadataQueryValue(L"/grctlext/Delay", &propVar); PropVariantClear(&propVar); propVar.vt = VT_UI1; propVar.bVal = 2; // 帧处理方式:恢复到背景色 pFrameEncode->SetMetadataQueryValue(L"/grctlext/Disposal", &propVar); PropVariantClear(&propVar); // 初始化帧编码器 hr = pFrameEncode->Initialize(nullptr); if (FAILED(hr)) break; // 将Direct2D位图转换为WIC位图 CComPtr<IWICBitmap> pWICBitmap; hr = pImagingFactory->CreateBitmap( static_cast<UINT>(pD2DBitmap->GetSize().width), static_cast<UINT>(pD2DBitmap->GetSize().height), GUID_WICPixelFormat32bppBGRA, WICBitmapCacheOnLoad, &pWICBitmap ); if (FAILED(hr)) break; CComPtr<ID2D1RenderTarget> pRenderTarget; hr = pD2DDeviceContext->CreateBitmapRenderTarget( pWICBitmap, D2D1::RenderTargetProperties(), &pRenderTarget ); if (FAILED(hr)) break; pRenderTarget->BeginDraw(); pRenderTarget->DrawBitmap(pD2DBitmap); hr = pRenderTarget->EndDraw(); if (FAILED(hr)) break; // 写入帧数据 hr = pFrameEncode->WriteSource(pWICBitmap, nullptr); if (FAILED(hr)) break; // 提交当前帧 hr = pFrameEncode->Commit(); if (FAILED(hr)) break; } // 提交整个编码器,完成多帧图像写入 pEncoder->Commit();
额外注意事项
- 确保编码器格式支持多帧(如GIF、TIFF),JPEG等单帧格式无法保存多帧图像
- Direct2D转WIC位图的方式可按需优化,直接锁定内存拷贝比RenderTarget绘制更高效
- 对于GIF,可通过
IWICBitmapEncoder::SetMetadataQueryValue设置全局循环次数,路径为/appext/ApplicationExtensions/LoopCount
内容的提问来源于stack exchange,提问作者DGAF
相关产品推荐
相关产品推荐

