日前遇到一个问题,在分层窗口上使用gdi+ 绘制文本的时候,在绘制的文字区域,文字产生了透明的洞,鼠标会穿透。
通过现象分析,应该是文字区域的透明度直接干成了0,所以产生了一个洞。因为分层窗口透明度为0的地方直接会穿透,所以鼠标也会穿透。
解决方法:
1 将要绘制的文本先绘制在内存位图上
2 位图的句柄选入到内存dc上
3 使用AlphaBlend 将内存dc 上的图绘制到窗口上。
如果绘制结果在边缘出现了杂色,那么需要在调用AlphaBlend函数前进行预乘处理。
预乘大概算法如下:
for(int i = 0; i <位图宽; i++)
{
for(int j = 0; j < 位图高; j++)
{
unsigned char* pucColor;//待处理的像素,一个像素4个字节。
pucColor[0] = pucColor[0] * pucColor[3] / 255;//red = red * alpha / 255
pucColor[1] = pucColor[1] * pucColor[3] / 255; //green = green * alpha / 255
pucColor[2] = pucColor[2] * pucColor[3] / 255;//blue = blue * alpha / 255
}
}
意思就是当前的像素的每个颜色分量值 * 该像素值的透明比例。
如下是解决gdi+ drawstring 透明问题的伪代码:
HWND cur_wnd = layerwnd; //当前绘制的分层窗口句柄
HFONT hFont = m_pManager->GetFont(GetFont()); //将要用于绘制文本的字体句柄
Gdiplus::Font font(hDC, hFont); //hDC:当前窗口的句柄
Gdiplus::RectF rc(10, 100, 300, 300);//位图中的绘制位置
Gdiplus::Graphics* pGraphics = new Gdiplus::Graphics(hDC);
Gdiplus::Color color(254, 255, 0, 0);
Gdiplus::SolidBrush redBrush(color);
Gdiplus::SolidBrush greenBrush(Gdiplus::Color(255, 0, 255, 0));
//pGraphics->DrawString(L"1111111111111111111xxxxxxxxxxx", -1, &font, rc,NULL, &greenBrush); //这个会产生透明的洞
Gdiplus::Bitmap bitmap(180, 100);//内存位图
Gdiplus::Graphics bitmapGraphics(&bitmap);//内存画布
bitmapGraphics.Clear(Gdiplus::Color(0, 255, 255, 255));//将改颜色作用于位图上
bitmapGraphics.SetCompositingMode(Gdiplus::CompositingModeSourceOver); //这句可以删除,主要是作用于绘制对象间的作用,譬如在同一个位置绘制一个圆和正方形,那么在此处到底是覆盖还是混合
bitmapGraphics.FillEllipse(&greenBrush, 30, 30, 150, 70);
Gdiplus::RectF rc2(30, 30, 150, 70);
Gdiplus::TextRenderingHint trh = Gdiplus::TextRenderingHintSystemDefault;
bitmapGraphics.SetTextRenderingHint(trh);
bitmapGraphics.SetSmoothingMode(Gdiplus::SmoothingModeHighQuality);
bitmapGraphics.SetInterpolationMode(Gdiplus::InterpolationModeHighQualityBicubic);
Gdiplus::StringFormat stringFormat = Gdiplus::StringFormat::GenericTypographic();
bitmapGraphics.DrawString(L"1111111111111111111xxxxxxxxxxx", -1, &font, rc2,&stringFormat, &redBrush);//在位图上绘制字符串
HBITMAP save_bitmap = NULL;
bitmap.GetHBITMAP(NULL, &save_bitmap); //取出位图中的句柄
HDC mem_dc = CreateCompatibleDC(NULL); //创建内存dc
HBITMAP old_bitmap = (HBITMAP)SelectObject(mem_dc, save_bitmap);//将位图句柄选入内存dc
POINT pt = { 0,0 };
BLENDFUNCTION oBF = { 0 };
oBF.BlendOp = AC_SRC_OVER;
oBF.BlendFlags = 0;
oBF.SourceConstantAlpha = 255;
oBF.AlphaFormat = AC_SRC_ALPHA;
AlphaBlend(hDC, 0, 0, 392, 182, mem_dc, 0, 0, 180, 100, oBF);//将当前窗口的hdc 和内存dc 混合。既将当前位图中的话绘制到窗口上。
SelectObject(mem_dc, old_bitmap);
DeleteObject(save_bitmap);
DeleteDC(mem_dc);
参考链接:https://qa.1r1g.com/sf/ask/90636381/
https://www.orcode.com/question/1473876_k57fa4.html
https://www.cnblogs.com/xzy1210/p/3622818.html(DrawText 出现此类问题,问题的原因一样)