如何从ID2D1Bitmap中获取像素数据?含ID2D1BitmapRenderTarget场景
从ID2D1Bitmap中提取像素数据的解决方案
要从ID2D1Bitmap中获取像素数据,核心问题是默认的ID2D1Bitmap通常驻留在GPU内存,无法直接被CPU访问。以下是两种可靠的实现方案:
方案1:创建可CPU读取的D2D位图并复制数据
通过创建带有D2D1_BITMAP_OPTIONS_CPU_READ标志的ID2D1Bitmap,将原位图内容复制到该可访问的位图后,再通过Map方法获取像素指针:
// 前提:已获取原ID2D1Bitmap对象pOriginalBitmap,以及对应的ID2D1RenderTarget* pRenderTarget D2D1_SIZE_U bitmapSize = pOriginalBitmap->GetSize(); D2D1_PIXEL_FORMAT pixelFormat = pOriginalBitmap->GetPixelFormat(); // 创建支持CPU读取的位图 ID2D1Bitmap* pReadableBitmap = nullptr; HRESULT hr = pRenderTarget->CreateBitmap( bitmapSize, nullptr, 0, D2D1_BITMAP_PROPERTIES{ pixelFormat, pRenderTarget->GetDpiX(), pRenderTarget->GetDpiY() }, D2D1_BITMAP_OPTIONS_CPU_READ, &pReadableBitmap ); if (SUCCEEDED(hr)) { // 将原位图绘制到可读取位图 pRenderTarget->SetTarget(pReadableBitmap); pRenderTarget->BeginDraw(); pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::Transparent)); pRenderTarget->DrawBitmap(pOriginalBitmap); hr = pRenderTarget->EndDraw(); if (SUCCEEDED(hr)) { // 映射位图获取像素数据 D2D1_MAPPED_RECT mappedRect; hr = pReadableBitmap->Map(D2D1_MAP_OPTIONS_READ, &mappedRect); if (SUCCEEDED(hr)) { BYTE* pPixelData = static_cast<BYTE*>(mappedRect.pBits); UINT32 rowPitch = mappedRect.pitch; // 示例:遍历PBGRA格式的像素 for (UINT y = 0; y < bitmapSize.height; ++y) { UINT32* pRow = reinterpret_cast<UINT32*>(pPixelData + y * rowPitch); for (UINT x = 0; x < bitmapSize.width; ++x) { UINT32 pixel = pRow[x]; // 拆分通道:PBGRA -> RGBA BYTE b = pixel & 0xFF; BYTE g = (pixel >> 8) & 0xFF; BYTE r = (pixel >> 16) & 0xFF; BYTE a = (pixel >> 24) & 0xFF; // 处理单个像素逻辑 } } pReadableBitmap->Unmap(); } } pReadableBitmap->Release(); }
方案2:通过WIC位图转换获取像素
利用Windows Imaging Component(WIC)将D2D位图转换为WIC位图,再通过WIC的Lock接口读取像素:
// 前提:已获取pOriginalBitmap、ID2D1Factory* pD2DFactory、IWICImagingFactory* pWicFactory D2D1_SIZE_U bitmapSize = pOriginalBitmap->GetSize(); // 创建WIC位图(匹配D2D常用的PBGRA格式) IWICBitmap* pWicBitmap = nullptr; HRESULT hr = pWicFactory->CreateBitmap( bitmapSize.width, bitmapSize.height, GUID_WICPixelFormat32bppPBGRA, WICBitmapCacheOnLoad, &pWicBitmap ); if (SUCCEEDED(hr)) { // 创建关联WIC位图的D2D渲染目标 ID2D1RenderTarget* pWicRenderTarget = nullptr; hr = pD2DFactory->CreateWicBitmapRenderTarget( pWicBitmap, D2D1::RenderTargetProperties(), &pWicRenderTarget ); if (SUCCEEDED(hr)) { // 绘制原位图到WIC渲染目标 pWicRenderTarget->BeginDraw(); pWicRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::Transparent)); pWicRenderTarget->DrawBitmap(pOriginalBitmap); hr = pWicRenderTarget->EndDraw(); if (SUCCEEDED(hr)) { // 锁定WIC位图读取数据 WICRect lockRect = {0, 0, static_cast<int>(bitmapSize.width), static_cast<int>(bitmapSize.height)}; IWICBitmapLock* pBitmapLock = nullptr; hr = pWicBitmap->Lock(&lockRect, WICBitmapLockRead, &pBitmapLock); if (SUCCEEDED(hr)) { UINT bufferSize = 0; BYTE* pPixelData = nullptr; hr = pBitmapLock->GetDataPointer(&bufferSize, &pPixelData); if (SUCCEEDED(hr)) { UINT rowPitch = 0; pBitmapLock->GetStride(&rowPitch); // 像素处理逻辑同方案1 } pBitmapLock->Release(); } } pWicRenderTarget->Release(); } pWicBitmap->Release(); }
关键注意事项
- 像素格式:D2D默认使用
DXGI_FORMAT_B8G8R8A8_UNORM(PBGRA)格式,处理时要注意通道顺序,避免颜色错乱 - 内存管理:所有COM对象使用完毕后必须调用
Release()释放,防止内存泄漏 - 性能优化:GPU到CPU的数据传输存在开销,尽量减少像素读取的频率;如果需要多次读取,可复用可CPU读取的位图对象
内容的提问来源于stack exchange,提问作者Generic Name
相关产品推荐
相关产品推荐

