VC图片的半透明处理
半透明原理:?
假設(shè)LCD是256色的。顏色格式為332(RGB)?
顯存中的每一個(gè)字節(jié)的數(shù)據(jù)對(duì)應(yīng)一個(gè)象素點(diǎn)。?
在數(shù)據(jù)寫入顯存之前,讀取相應(yīng)相素點(diǎn)值,然后與新的數(shù)據(jù)按一定的規(guī)則混合之后,再寫入相應(yīng)像素點(diǎn)的顯存。?
這樣主要問(wèn)題關(guān)鍵是混合算法。?
混合算法目前在游戲上常用到的算法是AlphaBlend。計(jì)算公式如下?
假設(shè)一幅圖象是A,另一幅透明的圖象是B,那么透過(guò)B去看A,看上去的圖象C就是B和A的混合圖象,設(shè)B圖象的透明度為alpha(取值為0-1,1為完全透明,0為完全不透明),Alpha混合公式如下:?
R(C)=(1-alpha)*R(B)+alpha*R(A)?
G(C)=(1-alpha)*G(B)+alpha*G(A)?
B(C)=(1-alpha)*B(B)+alpha*B(A)?
R(x)、G(x)、B(x)分別指顏色x的RGB分量原色值。從上面的公式可以知道,Alpha其實(shí)是一個(gè)決定混合透明度的數(shù)值。應(yīng)用Alpha混合技術(shù),可以實(shí)現(xiàn)游戲中的許多特效,比如火光、煙霧、陰影、動(dòng)態(tài)光源等半透明效果。
uC/GUI系統(tǒng)分為好幾個(gè)層面。簡(jiǎn)單地可以歸結(jié)為:?
1、硬件驅(qū)動(dòng)層?
2、基本2D圖形庫(kù)?
3、窗體?
層次越高,涉及的內(nèi)容越多,修改的工作量就越大。 如果想修改最少的代碼實(shí)現(xiàn)半透明功能,最好在硬件驅(qū)動(dòng)層找切入口。?
在硬件驅(qū)動(dòng)層中有個(gè)宏定義 LCD_WRITE_MEM(Off,data) *((U8*)(DC+(((U32)(Off)))))=(data),從文檔可以看到該宏定義的功能就是向顯存寫入像素點(diǎn)的值。?
流程如下:?
a、讀取相應(yīng)象素點(diǎn)值?
b、與新的象素點(diǎn)值按照混合算法轉(zhuǎn)換。?
c、將轉(zhuǎn)換結(jié)果寫入顯存對(duì)應(yīng)位置。?
/設(shè)置透明度為0,完全不透明,先執(zhí)行清屏。?
GUI_SetBkColor(GUI_WHITE);?
GUI_SetColor(GUI_WHITE);?
GUI_Clear();?
/填充一個(gè)方框?
GUI_SetColor(GUI_RED);?
GUI_FillRect(0,0,80,30);?
*****這里設(shè)置透明度為80透明之后再執(zhí)行?
GUI_SetColor(GUI_GREEN);?
GUI_FillRect(50,5,200,30);?
GUI_CONTEXT?
typedef struct {?
/* Variables in LCD module */?
LCD_COLORINDEX_UNION LCD;?
LCD_RECT ClipRect;?
U8 DrawMode;?
U8 SelLayer;?
U8 TextStyle;?
U8 TransPara;?
/* Variables in GL module */?
GUI_RECT* pClipRect_HL; /* High level clip rectangle ... Speed optimization so drawing routines can optimize */?
U8 PenSize;?
U8 PenShape;?
U8 LineStyle;?
U8 FillStyle;?
/* Variables in GUICHAR module */?
const GUI_FONT GUI_UNI_PTR * pAFont;?
const GUI_UC_ENC_APILIST * pUC_API; /* Unicode encoding API */?
I16P LBorder;?
I16P DispPosX, DispPosY;?
I16P DrawPosX, DrawPosY;?
I16P TextMode, TextAlign;?
GUI_COLOR Color, BkColor; /* Required only when changing devices and for speed opt (caching) */?
/* Variables in WM module */?
#if GUI_WINSUPPORT?
const GUI_RECT* WM__pUserClipRect;?
GUI_HWIN hAWin;?
int xOff, yOff;?
#endif?
/* Variables in MEMDEV module (with memory devices only) */?
#if GUI_SUPPORT_DEVICES?
const tLCDDEV_APIList* pDeviceAPI; /* function pointers only */?
GUI_HMEM hDevData;?
GUI_RECT ClipRectPrev;?
#endif?
/* Variables in Anitaliasing module */?
#if GUI_SUPPORT_AA?
const tLCD_HL_APIList* pLCD_HL; /* Required to reroute drawing (HLine & Pixel) to the AA module */?
U8 AA_Factor;?
U8 AA_HiResEnable;?
#endif?
} GUI_CONTEXT; 包含了整個(gè)系統(tǒng)作圖的最基本信息。而且這個(gè)結(jié)構(gòu)體所聲明的變量GUI_Context也是硬件作圖層(硬件驅(qū)動(dòng)層)所唯一依賴的變量。?
在結(jié)構(gòu)體中發(fā)現(xiàn),需要增加透明度信息。?
于是在結(jié)構(gòu)體中增加一條:U8 BlendPara;/混合算法參數(shù)Alpha;?
現(xiàn)在來(lái)一個(gè)情景分析。?
1、在畫圖前設(shè)置該變量值。0---100之間。?
2、在LCD_WRITE_MEM時(shí)使用它。這樣半透明和透明效果就都實(shí)現(xiàn)了。?
用2D圖形庫(kù)作圖測(cè)試確實(shí)能實(shí)現(xiàn)半透明效果。?
再測(cè)試窗體時(shí)你會(huì)發(fā)現(xiàn)一個(gè)問(wèn)題。在基于WM_Window的所有控件上使作半透明效果會(huì)出現(xiàn)問(wèn)題:?
在反復(fù)刷新(即反復(fù)產(chǎn)生WM_PAINT)消息時(shí),該窗體的顏色一直在變量,而且由淺及深或由深及淺反復(fù)變化
實(shí)現(xiàn)AlphaBlend混合的代碼.?
主要的算法是:?
r = (BYTE)((((rForeground - rBackground)*delta) >> ALPHA) + rBackground);?
g = (BYTE)((((gForeground - gBackground)*delta) >> ALPHA) + gBackground);?
b = (BYTE)((((bForeground - bBackground)*delta) >> ALPHA) + bBackground);?
下面是具體實(shí)現(xiàn)。(代碼可成功運(yùn)行)?
// 一共2^8 + 1個(gè)等級(jí),0為透明,256為不透明,中間的值為半透明?
#define ALPHA 8?
#define FRAMEPENWIDTH 2 // 文本框的寬度?
#define FRAMECOLOR RGB(192,192,192) // 文本框的顏色?
#define SHADOWWIDTH 1 // 陰影的寬度(為了有立體感)?
#define SHADOWCOLOR RGB(0,0,0) //?陰影的顏色?
#define TEXTCOLOR RGB(0,0,192) // 文本的顏色?
// 文本框的寬度缺省100像素,寬度、高度可以動(dòng)態(tài)調(diào)整?
#define DEFAULTOUTPUTWIDTH 100?
VOID ShowTransparentText(?
HWND hDstWnd, // 在那個(gè)窗口透明顯示?
DWORD Alpha, // Alpha通道值(0 < Alpha < 256)?
COLORREF crForeground, // 文本框底色?
LPCTSTR lpszTxt, // 文本?
DWORD dwDelayTime // 顯示多長(zhǎng)時(shí)間?
)?
{?
COLORREF crBackground;?
BYTE r, g, b;?
BYTE rBackground, gBackground, bBackground;?
BYTE rForeground, gForeground, bForeground;?
INT x, y;?
INT nDstPosX, nDstPosY;?
INT nWidth, nHeight;?
HDC hWorkDC, hSaveDC, hDstDC;?
HANDLE hBitmap, hBitmap2;?
HFONT hf, hfSave;?
LOGFONT lf;?
RECT rect;?
DWORD delta;?
//創(chuàng)建文本框字體?
lf.lfHeight = 14;?
lf.lfWidth = 0;?
lf.lfEscapement = 0;?
lf.lfOrientation = 0;?
lf.lfWeight = FW_NORMAL; //FW_BOLD?
lf.lfItalic = FALSE;?
lf.lfUnderline = FALSE;?
lf.lfStrikeOut = 0;?
lf.lfCharSet = ANSI_CHARSET;?
lf.lfOutPrecision = OUT_DEFAULT_PRECIS;?
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;?
lf.lfQuality = DEFAULT_QUALITY;?
lf.lfPitchAndFamily = DEFAULT_PITCH | FF_SWISS;?
_tcscpy(lf.lfFaceName, TEXT("Tahoma"));?
VERIFY(hf = CreateFontIndirect(&lf));?
hDstDC = GetDC(hDstWnd);?
hWorkDC = CreateCompatibleDC(hDstDC);?
hfSave = (HFONT)SelectObject(hWorkDC, hf);?
nWidth = DEFAULTOUTPUTWIDTH;?
nHeight = DEFAULTOUTPUTWIDTH;?
SetRect(&rect, 0,0,nWidth,nHeight);?
DrawText(hWorkDC, lpszTxt, lstrlen(lpszTxt), &rect, DT_CALCRECT|DT_LEFT|DT_WORDBREAK);?
// 自畫立體邊框?
nWidth = rect.right - rect.left + (FRAMEPENWIDTH + SHADOWWIDTH) * 2;?
nHeight = rect.bottom - rect.top + (FRAMEPENWIDTH + SHADOWWIDTH) * 2;?
hBitmap = CreateCompatibleBitmap(hDstDC, nWidth, nHeight);?
SelectObject(hWorkDC, hBitmap);?
hSaveDC = CreateCompatibleDC(hDstDC);?
hBitmap2 = CreateCompatibleBitmap(hDstDC, nWidth, nHeight);?
SelectObject(hSaveDC, hBitmap2);?
GetClientRect(hDstWnd, &rect);?
nDstPosX = rect.left + (rect.right - rect.left - nWidth)/2;?
nDstPosY = rect.top + (rect.bottom - rect.top - nHeight)/2;?
BitBlt(hWorkDC, 0, 0, nWidth, nHeight, hDstDC, nDstPosX, nDstPosY, SRCCOPY);?
BitBlt(hSaveDC, 0, 0, nWidth, nHeight, hDstDC, nDstPosX, nDstPosY, SRCCOPY);?
delta = Alpha%(1<<ALPHA); // 假若Alpha的值操作256,取模?
// 因?yàn)? , 256 對(duì)256取模都為0, 但是0為透明,256為不透明?
if((0 == delta) && (Alpha == (1<<ALPHA)))?
{?
delta = Alpha;?
}?
rForeground = GetRValue(crForeground);?
gForeground = GetGValue(crForeground);?
bForeground = GetBValue(crForeground);?
for(y = SHADOWWIDTH + SHADOWWIDTH; y< (nHeight - (SHADOWWIDTH + SHADOWWIDTH)); y++)?
{?
for(x = SHADOWWIDTH + SHADOWWIDTH; x < (nWidth - (SHADOWWIDTH + SHADOWWIDTH)); x++)?
{?
crBackground = GetPixel(hWorkDC, x, y);?
rBackground = GetRValue(crBackground);?
gBackground = GetGValue(crBackground);?
bBackground = GetBValue(crBackground);?
r = (BYTE)((((rForeground - rBackground)*delta) >> ALPHA) + rBackground);?
g = (BYTE)((((gForeground - gBackground)*delta) >> ALPHA) + gBackground);?
b = (BYTE)((((bForeground - bBackground)*delta) >> ALPHA) + bBackground);?
SetPixel(hWorkDC, x, y, RGB(r,g,b));?
}?
}?
// 由于Smartphone不提供FrameRect函數(shù),所以自行實(shí)現(xiàn)該功能。?
// 畫出外框?
for(y = 0; y< FRAMEPENWIDTH; y++)?
{?
for(x = 0; x < nWidth; x++)?
{?
SetPixel(hWorkDC, x, y, FRAMECOLOR);?
SetPixel(hWorkDC, x, nHeight - y - 1, FRAMECOLOR);?
}?
}?
for(x = 0; x< FRAMEPENWIDTH; x++)?
{?
for(y = 0; y < nHeight; y++)?
{?
SetPixel(hWorkDC, x, y, FRAMECOLOR);?
SetPixel(hWorkDC, nWidth - x -1, y, FRAMECOLOR);?
}?
}?
// 畫出陰影框?
for(y = FRAMEPENWIDTH; y< (FRAMEPENWIDTH+SHADOWWIDTH); y++)?
{?
for(x = FRAMEPENWIDTH; x < (nWidth - FRAMEPENWIDTH); x++)?
{?
SetPixel(hWorkDC, x, y, SHADOWCOLOR);?
SetPixel(hWorkDC, x, nHeight - y - 1, SHADOWCOLOR);?
}?
}?
for(x = FRAMEPENWIDTH; x< (FRAMEPENWIDTH+SHADOWWIDTH); x++)?
{?
for(y = FRAMEPENWIDTH; y < (nHeight - FRAMEPENWIDTH); y++)?
{?
SetPixel(hWorkDC, x, y, SHADOWCOLOR);?
SetPixel(hWorkDC, nWidth - x -1, y, SHADOWCOLOR);?
}?
}?
// 輸出透明字?
SetRect(&rect, (FRAMEPENWIDTH+SHADOWWIDTH), (FRAMEPENWIDTH+SHADOWWIDTH), nWidth - (FRAMEPENWIDTH+SHADOWWIDTH), nHeight - (FRAMEPENWIDTH+SHADOWWIDTH));?
SetBkMode(hWorkDC, TRANSPARENT);?
SetTextColor(hWorkDC, TEXTCOLOR);?
DrawText(hWorkDC, lpszTxt, lstrlen(lpszTxt), &rect, DT_LEFT|DT_WORDBREAK);?
BitBlt(hDstDC, nDstPosX, nDstPosY, nWidth, nHeight, hWorkDC, 0, 0, SRCCOPY);?
DeleteObject(SelectObject(hWorkDC, hfSave));?
DeleteObject(hBitmap);?
DeleteDC(hWorkDC);?
// 延遲制定時(shí)間,最好用WaitForSingleObject, 這樣用戶既可以終止等待,SetEvent即可?
// 或者超時(shí),即相當(dāng)于Sleep功能?
Sleep(dwDelayTime);?
// 恢復(fù)原來(lái)的背景?
BitBlt(hDstDC, nDstPosX, nDstPosY, nWidth, nHeight, hSaveDC, 0, 0, SRCCOPY);?
DeleteObject(hBitmap2);?
DeleteDC(hSaveDC);?
ReleaseDC(hDstWnd, hDstDC);?
}
//wince半透明效果的實(shí)現(xiàn)
使用windows ce(5.0以上的版本)的一個(gè)api AlphaBlend,用法和BitBlt差不多:
BLENDFUNCTION bf;
bf.AlphaFormat=0;
bf.BlendFlags=0;
bf.BlendOp=AC_SRC_OVER;
bf.SourceConstantAlpha=100;//透明度0-255
AlphaBlend(hBackDC,0,70,73,20,hMaskDC,0,0,73,20,bf);
可以在WindowsCE里用
#include <wingdi.h>
//還要在Project -- setting -- link 里連接上msimg32.lib
VC用AlphaBlend實(shí)現(xiàn)半透明位圖
Requirements:
?Windows NT/2000/XP: Included in Windows 2000 and later.
?Windows 95/98/Me: Included in Windows 98 and later.
?Header: Declared in Wingdi.h; include Windows.h.
?Library: Included as a resource in Msimg32.dll.
?
示例:
?
void CTestDlg::SaveBitmap(CDC* pDC,CRect rect,CString filename)
{?
?CDC* memDC=new CDC;
?memDC->CreateCompatibleDC(pDC);
?CBitmap* bmp=new CBitmap;
?bmp->CreateCompatibleBitmap(pDC,rect.Width(),rect.Height());
?CBitmap* oldbitmap=memDC->SelectObject(bmp);
?//此時(shí)的bmp就相當(dāng)于一張桌布,在memDC中畫線etc都是畫在這張桌布上
?if(!memDC->BitBlt(0,0,rect.Width(),rect.Height(),pDC,0,0,SRCCOPY))
?{
?? AfxMessageBox("BitBlt Error!");
?? return;
?}
?memDC->Ellipse(0,0,100,100);
?memDC->SelectObject(oldbitmap);
?
?BITMAPINFO bi;
?bi.bmiHeader.biSize=sizeof(bi.bmiHeader);
?bi.bmiHeader.biWidth=rect.Width();
?bi.bmiHeader.biHeight=rect.Height();
?bi.bmiHeader.biPlanes=1;
?bi.bmiHeader.biBitCount=16;
?bi.bmiHeader.biCompression=BI_RGB;
?bi.bmiHeader.biSizeImage=0;
?bi.bmiHeader.biXPelsPerMeter=0;
?bi.bmiHeader.biYPelsPerMeter=0;
?bi.bmiHeader.biClrUsed=0;
?bi.bmiHeader.biClrImportant=0;
?
?int bitsize=rect.Width()*rect.Height()*2;
?BYTE* bits=new BYTE[bitsize];
?::GetDIBits(memDC->m_hDC,*bmp,0,rect.Height(),bits,&bi,DIB_RGB_COLORS);?
???
?BITMAPFILEHEADER bf;
?bf.bfType=(int)'M'*256+'B';
?bf.bfSize=bitsize;//sizeof(bf);
?bf.bfOffBits=sizeof(bi.bmiHeader)+sizeof(bf);
?bf.bfReserved1=0;
?bf.bfReserved2=0;
?
?CFile f(filename,CFile::modeCreate|CFile::modeWrite);
?f.Write(&bf,sizeof(bf));//注意是先寫bf,再寫bi
?f.Write(&bi,sizeof(bi));
?f.Write(bits,bitsize);
?f.Close();
?
?delete[] bits;
?delete bmp;
?delete memDC;
}?
?
?
將memDC上的位圖半透明覆蓋到pDC上
BLENDFUNCTION bm;
bm.BlendOp=AC_SRC_OVER;
bm.BlendFlags=0;
bm.SourceConstantAlpha=100;
bm.AlphaFormat=0;?
AlphaBlend(pDC->m_hDC,0,0,rect.Width(),rect.Height(),memDC->m_hDC,0,0,rect.Width(),rect.Height(),bm);?
總結(jié)
以上是生活随笔為你收集整理的VC图片的半透明处理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 并列句(2021-07-25)
- 下一篇: 物联网是大家都看好的创业方向