就拿半透明来说,嵌入式下的半透明是困扰很多嵌入式编程人员的难题,就笔者来说,我寻找了大量国内,国外的网站,也咨询过几十位有多年嵌入式方面工作经验的人员,但是没有一个人能够给我良好的解决方案。 目前的实现方法大多数直接写硬件或者直接写显存这样的底层方法来实现。是后来,在笔者自己的努力下,比较完美的在应用层上解决了问题 ,实现高效率的半透明效果。
我们先谈谈window下常规半透明的实现方法。
常规半透明的实现方法是 :
2: 再获得源DC此位置像素点的颜色值,也将此颜色值拆分为R ,G ,B值(假设为R2 , G2 , B2),
3: 然后将此两颜色的R , G ,B值分别按如下公式进行运算。
New = Source * Alpha + ( 1 – Alpha) * Dest ;
分别计算:
NewR = R1 * Alpha + (1 – Alpha) * R2 ;
NewG = G1 * Alpha + (1 – Alpha) * G2 ;
NewB = B1 * Alpha + (1 – Alpha) * B2 ;
4:最后将计算得到的新NewR,NewG,NewB值合成最终的将显示出来的颜色值。
在WinCE4.2模拟器下做测试,如下一段代码
所以,最终我们需要用某种替代的方法来代替这个GetPixel和SetPixel函数 。
在Windows下,可以用GetDIBits和GetBitmapBits来一次性的将所有的像素点读取过来进行分析。
CRect rtTran 在目标DC上的半透明区域
COLORREF clrSrc 与目标区域进行Alpha混和的颜色
需要优化的地方
1: 传入透明度做为参数
这里半透明运算 ,没有用常规的拆分法来做 , 为了加快速度 , 将浮点运算改成了移位运算
为了方便 ,这里统一显示的是50%透明度的半透明效果
实际想改成任意透明度的话 ,也是非常方便的。详细修改方法 ,请查看我的另一篇关于Alpha
混和的文章。
2: 用RGBQUAD* pRgb 代替 BYTE *pbtPixel ; 一次进行多个数值的运算 。
3: 嵌入MMX汇编指令 ,加快运算速度 。
--------------------------------------------------------------*/
void DrawSemiTransparentRect(CDC *pDstDC, CRect rtTran, COLORREF clrSrc)
{
int nSavedDC = pDstDC->SaveDC(); //保存原始DC
int nWidth = rtTran.Width(); //半透明区域的宽度
int nHeight = rtTran.Height(); //半透明区域的高度
//拷屏 , 新建一个DC来拷贝目标区域
CDC bmpDC;
bmpDC.CreateCompatibleDC(pDstDC);
CBitmap bmp ;
bmp.CreateCompatibleBitmap(pDstDC , nWidth , nHeight);
CBitmap* pOldBmp = (CBitmap*)bmpDC.SelectObject(&bmp);
bmpDC.BitBlt(0 , 0 , nWidth , nHeight , pDstDC , rtTran.left , rtTran.top , SRCCOPY);
//获取bmpDC中的图形数据到BYTE数组
HDC hDIBDC = CreateCompatibleDC(NULL);
ZeroMemory(&hdr , sizeof(BITMAPINFO));
hdr.bmiHeader.biWidth = nWidth;
hdr.bmiHeader.biHeight = nHeight;
hdr.bmiHeader.biPlanes = 1;
hdr.bmiHeader.biBitCount = 32; /* 这里统一用32位图形 ,原因是32位图形结构相对固定 , 每个
像素用4个字节表示 。每行末尾不需要添加额外的字节。
而24位图形 , 每行末尾需要添加额外的字节 , 以保证每行的
字节数是4的整数倍
如果想缩减开销和字节数 , 可以采用24位的图形 ,不过就会多
出一些判断添加额外自己的代码 。*/
(BITMAPINFO *)&hdr,
DIB_RGB_COLORS,
(void **)&pbtPixels,
NULL,
0);
BitBlt(hDIBDC,0,0,nWidth,nHeight,bmpDC,0,0,SRCCOPY);
SelectObject(hDIBDC, hOldBmp);
//对BYTE数组进行Alpha混和
int nPixelSize = 4 ; //每个像素点用4个字节来存储
BYTE btSG = GetGValue(clrSrc);
BYTE btSB = GetBValue(clrSrc);
{
for(int j = 0 ; j < nWidth ; j ++)
{
BYTE btB = pbtPixels[i * nWidth * nPixelSize + j * nPixelSize ] ;
BYTE btG = pbtPixels[i * nWidth * nPixelSize + j * nPixelSize + 1 ] ;
BYTE btR = pbtPixels[i * nWidth * nPixelSize + j * nPixelSize + 2 ] ;
btG = (btSG + btG ) >> 1 ; //btG = btSG * 0.5 + (1-0.5) * btG;
btR = (btSR + btR ) >> 1 ; //btR = btSR * 0.5 + (1-0.5) * btR;
pbtPixels[i * nWidth * nPixelSize + j * nPixelSize + 1 ] = btG ;
pbtPixels[i * nWidth * nPixelSize + j * nPixelSize + 2 ] = btR ;
}
SetDIBitsToDevice(pDstDC->GetSafeHdc(),
rtTran.left,
rtTran.top,
nWidth,
nHeight,
0,
0,
0,
nHeight,
(void*)pbtPixels,
(BITMAPINFO*)&hdr,
DIB_RGB_COLORS);
//析构和清空
bmpDC.SelectObject(pOldBmp);
bmp.Detach();
delete [] pbtPixels ;
DeleteObject(hDIBDC);
pDstDC->RestoreDC(nSavedDC); //恢复初始DC
}
上面所有代码为Ricky黄俊峰所写 ,如欲转载 ,请注明出处 。 。 。
4万+



被折叠的 条评论
为什么被折叠?



