在经历了一百万次尝试和失败之后,我找到了答案。微软在here 和here 中关于如何创建位图不透明蒙版的说明非常令人困惑,听起来您需要黑白图像作为蒙版,但这远非事实。我们真正需要的是一张只有 alpha 值信息的图像。我也找不到任何将HRGN 转换为ID2D1Bitmap 的指令。所以我必须想出我自己的,我将在这里分享给任何可能遇到同样问题的人。
void HRGN_to_D2Bitmap(const DWORD bmpWidth, const DWORD bmpHeight, HRGN hShape, ID2D1RenderTarget* pRT, ID2D1Bitmap** ppBmpMask)
{
boost::scoped_ptr<unsigned char> pBmpBuff(new unsigned char[bmpWidth * bmpHeight]);
DWORD dwCount;
LPRGNDATA pRgnData;
memset(pBmpBuff.get(), 0, bmpWidth * bmpHeight);
dwCount = ::GetRegionData(hShape, 0, NULL);
boost::scoped_ptr<unsigned char> pRgnBuff(new unsigned char[dwCount]);
pRgnData = reinterpret_cast<LPRGNDATA>(pRgnBuff.get());
if (dwCount == ::GetRegionData(hShape, dwCount, pRgnData))
{
DWORD i, y;
RECT* pRect;
D2D1_BITMAP_PROPERTIES bmpPorp;
D2D1_SIZE_U bmpSize = D2D1::SizeU(bmpWidth, bmpHeight);
pRect = (RECT*)pRgnData->Buffer;
for (i = 0; i < pRgnData->rdh.nCount; i++)
{
for (y = (DWORD)pRect->top; ((y < (DWORD)pRect->bottom) && (y < bmpHeight)); y++)
memset(&pBmpBuff.get()[(y * bmpWidth) + pRect->left], 0xFFFFFFFF, pRect->right - pRect->left);
pRect++;
}
bmpPorp.dpiX = 0.0f;
bmpPorp.dpiY = 0.0f;
bmpPorp.pixelFormat.format = DXGI_FORMAT_A8_UNORM;
bmpPorp.pixelFormat.alphaMode = D2D1_ALPHA_MODE_STRAIGHT;
pRT->CreateBitmap(bmpSize, pBmpBuff.get(), bmpWidth, bmpPorp, ppBmpMask);
}
}
为简单起见,我省略了大部分错误检查。
当函数返回时,最后一个参数应该有一个有效的位图掩码(如果一切正常的话)供FillOpacityMask 的ID2D1RenderTarget 函数使用。
现在我们需要将我们的ID2D1Bitmap 变成ID2D1BitmapBrush。
D2D1_BITMAP_BRUSH_PROPERTIES propertiesXClampYClamp = D2D1::BitmapBrushProperties(
D2D1_EXTEND_MODE_CLAMP,
D2D1_EXTEND_MODE_CLAMP,
D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR
);
pRT->CreateBitmapBrush(pOrigBmp, propertiesXClampYClamp, &bkBrush);
pOrigBmp 是我们想要移动的图像,bkBrush 是指向ID2D1BitmapBrush 的指针。
如果您有 HBITMAP 或 C++ Builder 人是 TBitmap,您可以找到将位图转换为 ID2D1Bitmap here 的说明。
现在每次你想画你的窗口,你可以简单地这样做:
pRT->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
pRT->FillOpacityMask(pBmpMask, bkBrush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS);
pRT->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
为了移动图像,我们必须使用SetTransform。 pBmpMask 是使用 HRGN_to_D2Bitmap 创建的 ID2D1Bitmap。即:
ID2D1Bitmap* pBmpMask;
HRGN_to_D2Bitmap(bmpWidth, bmpHeight, hShape, pRT, &pBmpMask);
希望这会有所帮助。
山姆