如何在MFC中使用Direct2D将SVG文件转换为Bitmap?
在MFC中用Direct2D实现SVG转Bitmap并用于控件
要在MFC里搞定SVG转Bitmap,核心是把Direct2D的SVG渲染能力和MFC的GDI环境打通——毕竟MFC控件大多依赖GDI。你之前试的是UWP示例,和桌面MFC的环境不匹配,所以得调整适配。下面是具体步骤和代码:
1. 项目配置
先给MFC项目加上Direct2D的依赖:
- 头文件:
#include <d2d1.h> #include <d2d1svg.h> #include <wincodec.h> - 链接库(项目属性→链接器→输入→附加依赖项):
d2d1.lib;d2d1svg.lib;windowscodecs.lib;
2. 维护Direct2D核心对象
在你的MFC窗口类(比如CMyDialog或CMyView)里添加成员变量:
ID2D1Factory* m_pD2DFactory = nullptr; ID2D1HwndRenderTarget* m_pRenderTarget = nullptr; ID2D1SvgDocument* m_pSvgDoc = nullptr; HBITMAP m_hBitmap = nullptr; // 最终用于MFC控件的GDI位图
3. 初始化Direct2D环境
在窗口的OnInitDialog(对话框)或OnCreate(视图)里完成初始化:
BOOL CMyDialog::OnInitDialog() { CDialogEx::OnInitDialog(); // 创建Direct2D工厂 HRESULT hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pD2DFactory); if (SUCCEEDED(hr)) { // 获取窗口客户区大小 RECT rc; GetClientRect(&rc); // 创建绑定到MFC窗口的渲染目标 D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top); D2D1_RENDER_TARGET_PROPERTIES rtProps = D2D1::RenderTargetProperties(); rtProps.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED); hr = m_pD2DFactory->CreateHwndRenderTarget( rtProps, D2D1::HwndRenderTargetProperties(m_hWnd, size), &m_pRenderTarget); } // 加载SVG文件 if (SUCCEEDED(hr)) { CString strSvgPath = _T("你的SVG文件路径.svg"); // 也可以用SVG的viewBox尺寸替换窗口尺寸,适配更准确 hr = m_pRenderTarget->CreateSvgDocument( (LPCWSTR)strSvgPath, D2D1::SizeF(rc.right - rc.left, rc.bottom - rc.top), &m_pSvgDoc); } // 转成GDI Bitmap if (SUCCEEDED(hr)) { m_hBitmap = SvgToGdiBitmap(m_pSvgDoc, m_pD2DFactory); } return TRUE; }
4. 实现SVG转GDI Bitmap的核心函数
这个函数负责把SVG渲染到离屏Direct2D Bitmap,再转成HBITMAP:
HBITMAP SvgToGdiBitmap(ID2D1SvgDocument* pSvgDoc, ID2D1Factory* pD2DFactory) { if (!pSvgDoc || !pD2DFactory) return nullptr; // 获取SVG的实际尺寸(从viewBox) D2D1_RECT_F viewBox = pSvgDoc->GetViewBox(); float width = viewBox.right - viewBox.left; float height = viewBox.bottom - viewBox.top; // 创建离屏Direct2D Bitmap作为渲染目标 ID2D1BitmapRenderTarget* pBitmapRt = nullptr; HRESULT hr = pD2DFactory->CreateBitmapRenderTarget( D2D1::RenderTargetProperties(), D2D1::SizeU((UINT32)width, (UINT32)height), &pBitmapRt); if (SUCCEEDED(hr)) { pBitmapRt->BeginDraw(); pBitmapRt->Clear(D2D1::ColorF(D2D1::ColorF::Transparent)); // 绘制SVG到Bitmap pBitmapRt->DrawSvgDocument(pSvgDoc); hr = pBitmapRt->EndDraw(); if (SUCCEEDED(hr)) { // 获取Direct2D Bitmap ID2D1Bitmap* pD2DBitmap = nullptr; pBitmapRt->GetBitmap(&pD2DBitmap); // 转成HBITMAP HBITMAP hBitmap = nullptr; BITMAPINFO bmi = {0}; bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = (LONG)width; bmi.bmiHeader.biHeight = -(LONG)height; // GDI以顶部为原点,需翻转 bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 32; bmi.bmiHeader.biCompression = BI_RGB; UINT8* pBits = nullptr; HDC hdc = GetDC(nullptr); hBitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, (void**)&pBits, nullptr, 0); ReleaseDC(nullptr, hdc); if (hBitmap && pBits) { // 从Direct2D Bitmap复制像素 pD2DBitmap->CopyFromMemory(nullptr, pBits, (UINT32)width * 4); } pD2DBitmap->Release(); pBitmapRt->Release(); return hBitmap; } pBitmapRt->Release(); } return nullptr; }
5. 在MFC控件中使用Bitmap
比如在CStatic控件上显示:
void CMyDialog::OnPaint() { CPaintDC dc(this); // 获取静态控件的DC CStatic* pStatic = (CStatic*)GetDlgItem(IDC_STATIC_SVG); if (pStatic && m_hBitmap) { CDC* pStaticDC = pStatic->GetDC(); HDC hStaticDC = pStaticDC->GetSafeHdc(); BITMAP bm; GetObject(m_hBitmap, sizeof(BITMAP), &bm); // 按控件尺寸拉伸绘制 StretchBlt(hStaticDC, 0, 0, pStatic->GetClientRect().Width(), pStatic->GetClientRect().Height(), CreateCompatibleDC(hStaticDC), 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY); DeleteDC(CreateCompatibleDC(hStaticDC)); pStatic->ReleaseDC(pStaticDC); } }
6. 清理资源
在窗口的OnDestroy或PostNcDestroy里释放COM对象和Bitmap:
void CMyDialog::OnDestroy() { CDialogEx::OnDestroy(); if (m_pSvgDoc) m_pSvgDoc->Release(); if (m_pRenderTarget) m_pRenderTarget->Release(); if (m_pD2DFactory) m_pD2DFactory->Release(); if (m_hBitmap) DeleteObject(m_hBitmap); }
关键注意点
- DPI适配:如果程序需要支持高DPI,创建渲染目标时要指定DPI,或调用
SetDpi方法,避免SVG模糊。 - SVG路径:MFC中注意路径正确性,优先用绝对路径,或把SVG作为资源嵌入后从资源流加载。
- Alpha通道:如果SVG有透明背景,转HBITMAP时要保留Alpha,绘制时需处理透明效果。
内容的提问来源于stack exchange,提问作者latosvarun
相关产品推荐
相关产品推荐

