最近在用GDI+做个东西,想实现两幅带有Alpha通道的图像(比如PNG图像)的透明渐变。方法很简单,用双缓冲的办法,但是不同的是,先把下面那幅图,也就是下图的图B,先画到内存Graphics中,然后再用设置ColorMatrix的方法,在B图上按一定透明度混合A图,最后直接把整个内存位图一起输出到屏幕上!
实现代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | Bitmap* CreateTransGradientMemBmp(Bitmap *pBkgndBmp, Bitmap *pFgndBmp, int nWidth, int nHeight, REAL rTransparence) { Bitmap* pMemBmp = new Bitmap(nWidth, nHeight); static ColorMatrix clrMatrix = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; clrMatrix.m[3][3] = rTransparence; Graphics memGraph(pMemBmp); memGraph.DrawImage(pBkgndBmp, 0, 0); ImageAttributes imgAttr; imgAttr.SetColorMatrix(&clrMatrix, ColorMatrixFlagsDefault, ColorAdjustTypeBitmap); memGraph.DrawImage(pFgndBmp, Rect(0, 0, nWidth, nHeight), 0, 0, nWidth, nHeight, UnitPixel, &imgAttr); return pMemBmp; } |
理论上的情况,这种方法的效果应该是很好的!可是设置一个15ms的定时器来画的时候,过几秒就闪一下,而且还会引起整个父窗口的重绘,我完全无语了!以前就听说过GDI+很慢,没想到这么慢,唉!
但是,无意中搜索到本文的读者真的有福了!因为我折腾了两天终于找到了解决办法!
现在说说我实现的思路:
如上图,首先需要得到(父)窗口背景图的内存DC,只需要知道此窗口的DC和需要截取的区域就行了,这个原理和截图软件的原理是一样的,只要窗口不带透明度,此法的显示效果还是比较好的!为什么需要用窗口背景图先与待处理的图像混合呢?因为透明渐变两幅不同的图像,如果只是直接在屏幕DC上直接Alpha混合的话,势必有可能存在下面那幅图像没被上面那幅图像挡住的情况,就很影响显示效果了!而创建成长宽相等的内存图像,就正好可以挡住下面那幅图像,而背景又是(父)窗口的背景,这样给用户的感觉就会是,下面那幅图像渐渐变淡消失,而上面那幅图像渐渐变得清晰。
这样得到C、D两幅内存图像后,再用类似之前讲的办法,但是这回应该用GDI的技术了。将C、D AlphaBlend到新的内存DC上。当然也可以直接在其中一个中处理,但是如果要反复使用这两幅图的话,就应该用新的内存DC了。
最后不用说了,直接BitBlt到屏幕上
最后罗嗦一句,虽然想起来步骤比GDI+的方法多多了,但是屏幕根本不会闪烁,实际效果要好很多!
相关代码(函数就懒得解释了,大家看代码就懂了):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | CDC* GetParentBkgnd(CWnd *pWnd, CPoint ptDrawStart, int nWidth, int nHeight) { CDC* pDC = pWnd->GetDC(); CWnd* pWndParent = pWnd->GetParent(); CDC* pParentDC = pWndParent->GetDC(); //得到图像绘制开始点在父窗口上的坐标 pWnd->ClientToScreen(&ptDrawStart); pWndParent->ScreenToClient(&ptDrawStart); //初始化内存DC CDC* pMemDC = new CDC; pMemDC->CreateCompatibleDC(pParentDC); CBitmap memBitmap; memBitmap.CreateCompatibleBitmap(pParentDC, nWidth, nHeight); pMemDC->SelectObject(&memBitmap); //拷贝父窗口背景到内存DC pMemDC->BitBlt(0, 0, nWidth, nHeight, pParentDC, ptDrawStart.x, ptDrawStart.y, SRCCOPY); //释放 pWndParent->ReleaseDC(pParentDC); pWnd->ReleaseDC(pDC); return pMemDC; } CDC* CreateMixDC(CDC* pParentMemDC, Bitmap* pBmp) { int nWidth = pBmp->GetWidth(), nHeight = pBmp->GetHeight(); //照原样先拷贝一份 CDC* pMemDCDst = new CDC; pMemDCDst->CreateCompatibleDC(pParentMemDC); CBitmap memBitmap; memBitmap.CreateCompatibleBitmap(pParentMemDC, nWidth, nHeight); pMemDCDst->SelectObject(&memBitmap); pMemDCDst->BitBlt(0, 0, nWidth, nHeight, pParentMemDC, 0, 0, SRCCOPY); //画上图像 Graphics memGraph(pMemDCDst->m_hDC); memGraph.DrawImage(pBmp, 0, 0, nWidth, nHeight); memGraph.ReleaseHDC(pMemDCDst->m_hDC); return pMemDCDst; } void AlphaGradientDraw(CWnd* pWnd, CDC* pFgndMemDC, CDC* pBkgndMemDC, CPoint ptDrawStart, int nWidth, int nHeight, int nTransparence) { BLENDFUNCTION bf; bf.BlendOp = AC_SRC_OVER; bf.BlendFlags = 0; bf.AlphaFormat = 0; bf.SourceConstantAlpha = nTransparence; CDC* pDC = pWnd->GetDC(); //创建内存DC CDC memDC; memDC.CreateCompatibleDC(pDC); CBitmap memBitmap; memBitmap.CreateCompatibleBitmap(pDC, nWidth, nHeight); memDC.SelectObject(&memBitmap); //在内存中先画好 //memDC.BitBlt(0, 0, nWidth, nHeight, pDC, 0, 0, SRCCOPY); memDC.BitBlt(0, 0, nWidth, nHeight, pBkgndMemDC, 0, 0, SRCCOPY); AlphaBlend(memDC.m_hDC, 0, 0, nWidth, nHeight, pFgndMemDC->m_hDC, 0, 0, nWidth, nHeight, bf); //直接输出 pDC->BitBlt(ptDrawStart.x, ptDrawStart.y, nWidth, nHeight, &memDC, 0, 0, SRCCOPY); pWnd->ReleaseDC(pDC); } |


kita搶走沙花一只,話說不斷的糾結就會出現解決方法麼,雖然kita是看不懂的說
抢沙发是个好习惯
当然,在冬日坐沙发最舒服了的说
这个看起来有意思啊。沙发?
你更新缓存后看看
啊,完全看不懂
能过来支持一下已经不错了
图像处理….不错.看不懂。
因为我喜欢界面嘛,所以必然要涉及一点这方面的知识啦
看得头晕晕的
纯粹看不懂的说…
定期写一点专业的东西给搜索进来的读者看的
神马,不懂,,博客转型之后就都这样了吗
我完全是个悲剧。。。
怎么了?
过来看看,没玩过GDI+,一般2D也很少用透明位图……不过好像直接操作位图的像素!
光用GDI+,效果没DirectX好,效率奇低
但是你看看迅雷7,它也是基于GDI+做的界面,但是你感觉到很卡,界面闪烁了吗?
直接学3D游戏多好,用DirectX或者openGL
请问你的代码高亮是什么插件实现的?
WP-Syntax
想了解一下,贵博客的插入代码插件是使用的什么插件。谢谢分享。
wp-syntex
不用GDI+,直接pnglib…
用非官方的,怕有bug,又怕网上资料少,有bug自己也解决不了…