GDI+是WindowsXp和windows Server 2003中的一個子系統,主要用於處理系統的繪制消息。GDI+是GDI的擴展,其繼承了GDI的有點並在其基礎上進行了改進,包括增加了一些GDI無法繪制的圖形函數,同時GDI+重新設計了編程模型,使開發圖形程序更加方便。作為圖形設備接口的GDI+使得應用程序開發人員在輸出屏幕和打印機信息的時候無需考慮具體顯示設備的細節,他們只需調用GDI+庫輸出的類的一些方法即可完成圖形操作,真正的繪圖工作由這些方法交給特定的設備驅動程序來完成,GDI+使得圖形硬件和應用程序相互隔離.從而使開發人員編寫設備無關的應用程序變得非常容易。
在GDI+中,顏色的表示除了紅綠藍三種分量外,增加了一種叫做Alpha的變量,其作用是用來表示顏色的透明度,取值范圍為0-255.本例中實現的圖像透明度的改變主要就是改變圖像中每一種顏色的Alpha的值來達到改變透明度的效果。
本例中在VS2010中開發,具體效果如下
打開圖片文件,默認透明度為0,相應的alpha值為1,單擊色彩處理菜單項,打開圖像透明度對話框,改變滑動塊的值後,圖片透明度相應改變
下面詳細介紹具體實現過程:
vs2010中GDI+的配置
根據本人實測,在VS2010中只需在資源文件stdafx.h中包含進Gdiplus.h頭文件中就可以了,並不需要在項目屬性中添加GDI+庫文件,左飛編寫的《數字圖像處理-原理與實踐》中說的在VS2005下好像要在項目屬性->配置屬性->鏈接器->輸入->附加依賴項中添加gdiplus.lib。本人機器上沒有VS2005,所以也不敢妄下結論。不過在VS2010下只需在stdafx.h中添加如下代碼即可
[cpp] #include <GdiPlus.h>
using namespace Gdiplus;
#include <GdiPlus.h>
using namespace Gdiplus; 2.改變圖像透明度的原理
之前說過,在GDI+中增加了一個alpha的變量用於表示圖像的透明度,可是由於在GDI+中不能直接改變圖像中的alpha的值(本人也是初學GDI+沒多久,這句對與否暫時不好說),因此我們要用到一個叫做ColorMatrix的結構體,他是一個5*5的數組,我們用其表示顏色的變換關系。下面是GDI+中ColorMatrix的定義
[cpp] typedef struct{
REAL m[5][5];
}ColorMatrix;
typedef struct{
REAL m[5][5];
}ColorMatrix; 其中REAL類型我在微軟的MSDN中並沒有查到具體定義,《數字圖像處理-原理與實踐》一書中,說其表示的一個單精度的浮點類型。
下面說一下上面提到的ColorMatrix,下面是GDI+下的一個顏色變換公式
1 0 0 0 0
0 1 0 0 0
[R G B A 1]=[r g b a 1] 0 0 1 0 0
0 0 0 1 0
0 0 0 0 1
解釋下,R/G/B/A表示顏色變換後的紅、綠、藍和透明度的分量,r/g/b/a表示顏色變換前圖像的紅、綠、藍和透明度的分量,後面是一個5*5的矩陣,這個矩陣就是ColorMatrix結構體的5*5數組。根據矩陣的乘法,我們要改變圖像的透明度,只需定義一個ColorMatrix結構體,將第四行第四列的數改成相應的透明度即可。
3.圖像透明度對話框實現
對話框很簡單,添加兩個控件一個是編輯框,給其綁定變量m_alpha,類型為REAL,另一個是滑動塊控件,然後在主對話框類重載消息WM_HSCROLL,重載後會在該對話框類自動生成一個OnHScroll的消息響應函數,我們主要的操作就是在這個函數類實現,下面是該函數類的代碼
[cpp] BOOL CImageDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
CSliderCtrl* pSlider;
pSlider=(CSliderCtrl*)GetDlgItem(IDC_SLIDER_ALPHA);//根據控件ID綁定控件
pSlider->SetRange(0,100);//設置滑動塊活動范圍
// TODO: 在此添加額外的初始化
return TRUE; // return TRUE unless you set the focus to a control
// 異常: OCX 屬性頁應返回 FALSE
}
BOOL CImageDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
CSliderCtrl* pSlider;
pSlider=(CSliderCtrl*)GetDlgItem(IDC_SLIDER_ALPHA);//根據控件ID綁定控件
pSlider->SetRange(0,100);//設置滑動塊活動范圍
// TODO: 在此添加額外的初始化
return TRUE; // return TRUE unless you set the focus to a control
// 異常: OCX 屬性頁應返回 FALSE
}
[cpp] void CImageDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// TODO: 在此添加消息處理程序代碼和/或調用默認值..........................................
CSliderCtrl*pSlider=(CSliderCtrl*)pScrollBar;
m_alpha=(100.0-pSlider->GetPos())/100.0;
UpdateData(FALSE);
void CImageDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// TODO: 在此添加消息處理程序代碼和/或調用默認值..........................................
CSliderCtrl*pSlider=(CSliderCtrl*)pScrollBar;
m_alpha=(100.0-pSlider->GetPos())/100.0;
UpdateData(FALSE);[cpp] //獲取View視圖類的指針並刷新視圖
//獲取View視圖類的指針並刷新視圖[cpp] CMainFrame *pMainFrame=(CMainFrame*)AfxGetMainWnd();
CGdiPlus_ColorView *pView=(CGdiPlus_ColorView*)pMainFrame->GetActiveView();
//pView->UpdateWindow();
pView->Invalidate();
//UpdateWindow();
CDialogEx::OnHScroll(nSBCode, nPos, pScrollBar);
}
CMainFrame *pMainFrame=(CMainFrame*)AfxGetMainWnd();
CGdiPlus_ColorView *pView=(CGdiPlus_ColorView*)pMainFrame->GetActiveView();
//pView->UpdateWindow();
pView->Invalidate();
//UpdateWindow();
CDialogEx::OnHScroll(nSBCode, nPos, pScrollBar);
} 4.Doc文檔類中的相關操作
添加變量image,用以保存打開的圖像文件,另重載文檔類中的OnOpenDocument函數
[cpp] public:
virtual BOOL OnOpenDocument(LPCTSTR lpszPathName);
Image* image;
public:
virtual BOOL OnOpenDocument(LPCTSTR lpszPathName);
Image* image; 在OnOpenDocument函數中將打開的圖像文件存入Image變量中
[cpp] BOOL CGdiPlus_ColorDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
if (!CDocument::OnOpenDocument(lpszPathName))
return FALSE;
// TODO: 在此添加您專用的創建代碼
image=Image::FromFile(lpszPathName);
//UpdateAllViews(NULL);
return TRUE;
}
BOOL CGdiPlus_ColorDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
if (!CDocument::OnOpenDocument(lpszPathName))
return FALSE;
// TODO: 在此添加您專用的創建代碼
image=Image::FromFile(lpszPathName);
//UpdateAllViews(NULL);
return TRUE;
}
5.View視圖類中的相關操作
首先要添加兩個變量,1個時alpha的值,另一個是指向圖像透明度對話框的指針;
[cpp] public:
REAL alpha;//圖像透明度
CImageDlg *dlg;//圖像透明度對話框指針
public:
REAL alpha;//圖像透明度
CImageDlg *dlg;//圖像透明度對話框指針
然後在資源文件中給菜單欄添加圖像處理這個菜單項,並為其綁定時間處理程序,在時間處理程序中用非模態方式顯示圖像透明度對話框
[cpp] void CGdiPlus_ColorView::OnImageAlpha()
{
// TODO: 在此添加命令處理程序代碼
dlg->Create(IDD_DIALOG1,this);
dlg->ShowWindow(SW_SHOW);//非模態對話框
}
void CGdiPlus_ColorView::OnImageAlpha()
{
// TODO: 在此添加命令處理程序代碼
dlg->Create(IDD_DIALOG1,this);
dlg->ShowWindow(SW_SHOW);//非模態對話框
} 最後在OnDraw函數中實現繪圖操作
[cpp] void CGdiPlus_ColorView::OnDraw(CDC* pDC)
{
CGdiPlus_ColorDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
if (pDoc->image==NULL)
{
return;
}
alpha=dlg->m_alpha;
void CGdiPlus_ColorView::OnDraw(CDC* pDC)
{
CGdiPlus_ColorDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
if (pDoc->image==NULL)
{
return;
}
alpha=dlg->m_alpha;[cpp] //獲得圖像的寬度和高度
int nWidth=pDoc->image->GetWidth();
int nHight=pDoc->image->GetHeight();
//聲明空白圖像
Bitmap bitmap(nWidth,nHight);
Rect rect(0,0,nWidth,nHight);
Graphics temp(&bitmap);//對新圖像進行繪制
ColorMatrix colorMartrix={
1,0,0,0,0,
0,1,0,0,0,
0,0,1,0,0,
0,0,0,alpha,0,
0,0,0,0,1};
ImageAttributes imageAttr;
imageAttr.SetColorMatrix(&colorMartrix);
temp.DrawImage(pDoc->image,rect,0,0,nWidth,nHight,UnitPixel,&imageAttr);
//創建於設備兼容的內存環境
CDC memDC;
CBitmap MemBitmap;
CRect ClientRect;
GetClientRect(ClientRect);
memDC.CreateCompatibleDC(NULL);
MemBitmap.CreateCompatibleBitmap(pDC,ClientRect.Width(),ClientRect.Height());
memDC.SelectObject(MemBitmap);
memDC.FillSolidRect(0,0,ClientRect.Width(),ClientRect.Height(),RGB(255,255,255));
Graphics graph(memDC.GetSafeHdc());
//Graphics graph(pDC->GetSafeHdc());//獲得當前設備的句柄
// graph.DrawImage(pDoc->image,0,0);
graph.DrawImage(&bitmap,0,0);
pDC->BitBlt(0,0,nWidth,nHight,&memDC,0,0,SRCCOPY);
// TODO: 在此處為本機數據添加繪制代碼
//獲得圖像的寬度和高度
int nWidth=pDoc->image->GetWidth();
int nHight=pDoc->image->GetHeight();
//聲明空白圖像
Bitmap bitmap(nWidth,nHight);
Rect rect(0,0,nWidth,nHight);
Graphics temp(&bitmap);//對新圖像進行繪制
ColorMatrix colorMartrix={
1,0,0,0,0,
0,1,0,0,0,
0,0,1,0,0,
0,0,0,alpha,0,
0,0,0,0,1};
ImageAttributes imageAttr;
imageAttr.SetColorMatrix(&colorMartrix);
temp.DrawImage(pDoc->image,rect,0,0,nWidth,nHight,UnitPixel,&imageAttr);
//創建於設備兼容的內存環境
CDC memDC;
CBitmap MemBitmap;
CRect ClientRect;
GetClientRect(ClientRect);
memDC.CreateCompatibleDC(NULL);
MemBitmap.CreateCompatibleBitmap(pDC,ClientRect.Width(),ClientRect.Height());
memDC.SelectObject(MemBitmap);
memDC.FillSolidRect(0,0,ClientRect.Width(),ClientRect.Height(),RGB(255,255,255));
Graphics graph(memDC.GetSafeHdc());
//Graphics graph(pDC->GetSafeHdc());//獲得當前設備的句柄
// graph.DrawImage(pDoc->image,0,0);
graph.DrawImage(&bitmap,0,0);
pDC->BitBlt(0,0,nWidth,nHight,&memDC,0,0,SRCCOPY);
// TODO: 在此處為本機數據添加繪制代碼
} 這裡面用了兩種繪圖方式,一種是直接向當前設備上下文輸出圖像,代碼中注釋部分。另一種是先創建與設備相兼容的內存環境,將圖片先繪制在此內存環境中再拷貝到屏幕,之所以采用此種方法是因為這樣可以去除視圖在不斷刷新過程中帶來的屏幕閃爍,可是本人實際的運行效果,在不斷移動滑塊的時候,視圖刷新依然有很明顯的閃爍,本人也添加了視圖類中的WM_ERASEBKGN消息,如下,但是依然不能解決其閃爍問題。
[cpp] BOOL CGdiPlus_ColorView::OnEraseBkgnd(CDC* pDC)
{
// TODO: 在此添加消息處理程序代碼和/或調用默認值
//return TRUE;
return CView::OnEraseBkgnd(pDC);
}
摘自 txg703003659的專欄