維尼的蜂巢

RealTime??!! It’s amazing!!!!

不規則視窗分析 八月 22, 2005

Filed under: HeartStory — kevinlin @ 5:09 上午
      要說的是,所謂不規則圖的繪製,意思是說一張圖(圖永遠是規則的),上面有個不規則圖形,把這張圖繪製到某一界面上時,要求只繪製位圖上那個不規則圖形,其它地方保持背景不變。比如說畫個太陽,不能把太陽所在的矩形的背景全部覆蓋,而應該只覆蓋太陽部分,本文將全面介紹繪製方法,以及它們的優劣!(我從我的code中抄過來,並將變量數改成通用名字,可能有手誤的地方)
      我說的這些方法都是在VC中的,VB中應該可以方便的用其它格式的圖片如gif,可以為透明!
       程式中的w和h為圖的寬度和高度。

方法一:
       首先把不規則圖形以外的地方(即要求是透明的地方),弄成圖形中不會出現的顏色(用圖像處理軟件),如白色,然後用下面的程式:
//包涵#include “Wingdi.h"
//並在設置中的link中加入:msimg32.lib

CBitmap YourBmp;
YourBmp.LoadBitmap(IDB_XXXX); //要顯示的位圖

CDC* pDC=GetDC();

CDC YourDC;
YourDC.CreateCompatibleDC(pDC);
YourDC.SelectObject(&Yourbmp);

TransparentBlt(pDC->m_hDC,0,0,w,h,YourDC.m_hDC,0,0,w,h,
    RGB(255,255,255) //在位圖中視為透明的顏色的RGB值
 );

ReleaseDC(pDC);

評價:程式編製簡單,但運行速度慢,有閃爍(用一張208*15的位圖測試),所以還是不要圖方便!

 

方法二:
       做一張蒙板位圖,大小與要繪製的位圖一樣,解析度也一樣,讓蒙板對應於圖形區域的地方為純白色,其餘地方(要求透明的地方)為純黑色。

CBitmap YourBmp;
YourBmp.LoadBitmap(IDB_XXXX); //要顯示的位圖

CBitmap YourMasker;
YourMasker.LoadBitmap(IDB_XXXX); //蒙板位圖

CBitmap background;
background.LoadBitmap(IDB_XXXX); //背景位圖

CDC* pDC=GetDC();

CDC YourDC;
YourDC.CreateCompatibleDC(pDC);
YourDC.SelectObject(&Yourbmp);

CDC MaskerDC;
MaskerDC.CreateCompatibleDC(pDC);
MaskerDC.SelectObject(&YourMasker);

CDC backgroundDC;
backgroundDC.CreateCompatibleDC(pDC);
backgroundDC.SelectObject(&background);

CBitmap TempBitmap; //臨時位圖
TempBitmap.CreateCompatibleBitmap(pDC,w,h);

CDC TempDC;
TempDC.CreateCompatibleDC(pDC);

TempDC.SelectObject(&TempBitmap);

TempDC.BitBlt(0,0,w,h,pDC,0,0,SRCCOPY);
TempDC.BitBlt(0,0,w,h,&YourDC,0,0,SRCAND);
TempDC.BitBlt(0,0,w,h,&MaskerDC,0,0,SRCPAINT);
TempDC.BitBlt(0,0,w,h,&YourDC,0,0,SRCAND);
pDC->BitBlt(0,0,w,h,&TempDC,0,0,SRCCOPY);

上面5行為核心碼,基本演算法就是先在臨時的TempDC中畫好位圖(透明區域已表現出來),再一次性的(最後一行)繪製到屏幕,這樣防止閃爍,但要多佔CPU資源和內存,在我的2.4G CPU上測試,CPU使用率也不到1%(每100毫秒運行一次上面的程序),可以接受。

ReleaseDC(pDC);

評價:程式複雜,但視覺效果較好!

 

方法三:
做一張蒙板位圖,大小與要繪製的位圖一樣,解析度也一樣,讓蒙板對應於圖形區域的地方為純白色,其餘地方(要求透明的地方)為純黑色。

CBitmap YourBmp;
YourBmp.LoadBitmap(IDB_XXXX); //要顯示的位圖

CBitmap YourMasker;
YourMasker.LoadBitmap(IDB_XXXX); //蒙板位圖

CDC* pDC=GetDC();

CDC YourDC;
YourDC.CreateCompatibleDC(pDC);
YourDC.SelectObject(&Yourbmp);

CDC MaskerDC;
MaskerDC.CreateCompatibleDC(pDC);
MaskerDC.SelectObject(&YourMasker);

pDC->BitBlt(0,0,w,h,&YourDC,0,0,SRCAND);
pDC->BitBlt(0,0,w,h,&MaskerDC,0,0,SRCPAINT);
pDC->BitBlt(0,0,w,h,&YoureDC,0,0,SRCAND);

ReleaseDC(pDC);

評價:該方法和方法二本質上一樣,方法二先把要顯示的位圖存起來最後一次顯示,方法三則分三步顯示位圖,所以屏幕上繪製的圖像要變化三次才能達到透明的效果,所以還是稍有閃爍,但比方法一好得多,在資源的消耗上比方法三要少,處於折衷位置!推薦使用方法三,它在效率和視覺上都表現的很好,而且window在移動游標的時候也是用這種方法,沒有任何理由比微軟都是這樣用的這個理由更充分,畢竟大家都在用他的作業系統!

 

方法四:
       這個立法我沒有經過實驗,因為沒有找到ICO製作工具,方法就是把要顯示的位圖做成ICO,自定義ICO應該可以自定義大小吧,不太確定,
大家都知道ICO可以透明,想哪兒透明就哪兒透明,然後就DrawIcon或DrawImage函數把它繪製上營幕,如果這個方法可行,那就是最簡單的
了,只要一行程序!

 

方法五:
       用CreateHatchBrush函數把要顯示的位圖做成刷子,再把要顯示的位圖輪廓做成一個區域(要做區域,可以根據位圖上的顏色輕鬆做出來,前提是先把要求為透明的地方弄成位圖中不會出現的顏色),再用FillRgn函數用做成的刷子去刷這個區域,最後就達到效果了。該方法應該要求區域是連續的,而且左上角第一點不能為透明,所以應該沒有什麼實用價值!但我想可以用BitBlt函數來改善這種狀況。

 

方法六:
        用AlphaBlend函數,以下程序只有在Vc++.net下才能通過,因為使用了透明位圖的概念,而2000以前的系統是不理解透明位圖的。

//包涵#include “Wingdi.h"

CBitmap YourBmp;
YourBmp.LoadBitmap(IDB_XXXX); //要顯示的位圖

CDC* pDC=GetDC();

CDC YourDC;
YourDC.CreateCompatibleDC(pDC);
YourDC.SelectObject(&YourBmp);

BLENDFUNCTION b;
b.BlendOp=AC_SRC_OVER; //定值
b.BlendFlags=0; //定值
b.SourceConstantAlpha=255; //不用總體透明度,用每一象素點自己的alpha值
b.AlphaFormat=AC_SRC_ALPHA;

//vc++6.0中沒有AC_SRC_ALPHA的定義,只有AC_SRC_NO_ALPHA的定義,這正是在vc++6.0中無法使用的原因。

AlphaBlend(pDC->m_hDC,0,0,w,h,GateDC.m_hDC,0,0,w,h,b);

ReleaseDC(pDC);

評價:方法簡單,但要求2000以上系統,而且事先必需要做個32位位圖並給plpha賦適當的值(以下會討論),目前我還沒有找到一個做32位位圖的軟件,所以還只有用程序來實現,好在我實現了這樣一個函數!

 

做32位透明位圖的方法!
        該函數只能把24位轉成32位,大家可以改動一下就能轉換其它位的位圖了,調用函數前,請把需要透明的地方弄成位圖中不會出現的
顏色,假設為白色。
    註:該函數是寫給我自己用的,沒有作任何錯誤判斷,假設我不會犯錯誤,如果要想更完美,可以自己加上錯誤的捕捉。

 BITMAPFILEHEADER bf;
 BITMAPINFOHEADER bi;

 CFileDialog dlg

(TRUE,NULL,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,"bmp 文件(*.bmp)|*.bmp||");
 CString filename;
 CFile file;

 if(IDOK==dlg.DoModal())
 {
  filename=dlg.GetPathName();
  file.Open(filename,CFile::modeRead | CFile::shareDenyNone); //打開要轉換的位圖文件
  file.Read(&bf,sizeof(bf));
  file.Read(&bi,sizeof(bi));
 }
 ///////////////////////////////////////////////
 UpdateData(); //取得edit框中的輸入,edit框與CString變量name相連,該輸入作為轉換後的輸出文件的文件名
 CFile Output;
 Output.Open(name,CFile::modeCreate | CFile::modeWrite,NULL);

 DWORD FImageSize=bi.biSizeImage; //轉換前的圖像數據大小<

 

 

One Response to “不規則視窗分析”

  1. […] 二月 14, 2008 於 10:49 上午 (VC++/C++/C) 之前有一篇不規則視窗六種方法,其實標題不是下的很好,應該是不規則圖形繪製,那一篇主要就是繪製圖形時,將alpha=0的給去除掉。 這一篇才是真正的不規則視窗的實作。 […]


發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 變更 )

Twitter picture

You are commenting using your Twitter account. Log Out / 變更 )

Facebook照片

You are commenting using your Facebook account. Log Out / 變更 )

Google+ photo

You are commenting using your Google+ account. Log Out / 變更 )

連結到 %s