現在,.net引入了一個功能非常強大的新類 ----- CImage.有了CImage類,Visual C++在圖像方面的缺憾將一去不復返。CImage是MFC和ATL共享的新類,它能從外部磁盤中調入一個JPEG、GIF、BMP和PNG格式的圖像文件加以顯示,而且這些文件格式可以相互轉換。例如通過簡單的幾句,就可以實現CImage類和CBitmap類實例的:
HBITMAP hBitmap=image.Detach();
CBitmap bmp;
bmp.Attach(hBitmap);
它具有下列最酷特性:
1、AlphaBlend支持像素級的顏色混合,從而實現透明和半透明的效果。
2、PlgBlt能使一個矩形區域的位圖映射到一個平行四邊形區域中,而且還可能使用位屏蔽操作。
3、TransparentBlt在目標區域中產生透明圖像,SetTransparentColor用來設置某種顏色是透明色。
4、MaskBlt在目標區域中產生源位圖與屏蔽位圖合成的效果。
由於CImage在不同的Windows操作系統中其某些性能是不一樣的,因此在使用時要特別注意。例如,CImage::PlgBlt和 CImage::MaskBlt只能在 Windows NT 4.0 或更高版本中使用,但不能運行在Windows 95/98 應用程序中。CImage::AlphaBlend和CImage::TransparentBlt也只能在 Windows 2000/98或其更高版本中使用。即使在Windows 2000運行程序還必須將stdafx.h文件中的WINVER和_WIN32_WINNT的預定義修改成0x0500才能正常使用。
使用CImage的一般方法
使用CImage的一般方法是這樣的過程:
(1) 打開應用程序的stdafx.h文件添加CImage類的包含文件:
#include <atlimage.h>
(2) 定義一個CImage類對象,然後調用CImage::Load方法裝載一個外部圖像文件。
(3) 調用CImage::Draw方法繪製圖像。Draw方法具有如下定義:
BOOL Draw( HDC hDestDC, int xDest, int yDest, int nDestWidth, int nDestHeight, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight ); BOOL Draw( HDC hDestDC, const RECT& rectDest, const RECT& rectSrc ); BOOL Draw( HDC hDestDC, int xDest, int yDest ); BOOL Draw( HDC hDestDC, const POINT& pointDest ); BOOL Draw( HDC hDestDC, int xDest, int yDest, int nDestWidth, int nDestHeight ); BOOL Draw( HDC hDestDC, const RECT& rectDest ); |
其中,hDestDC用來指定繪製的目標設備環境句柄,(xDest, yDest)和pointDest用來指定圖像顯示的位置,這個位置和源圖像的左上角點相對應。nDestWidth和nDestHeight分別指定圖像要顯示的高度和寬度,xSrc、ySrc、nSrcWidth和nSrcHeight用來指定要顯示的源圖像的某個部分所在的位置和大小。 rectDest和rectSrc分別用來指定目標設備環境上和源圖像所要顯示的某個部分的位置和大小。
需要說明的是,Draw方法綜合了StretchBlt、TransparentBlt和AlphaBlend函數的功能。默認時,Draw的功能和 StretchBlt相同。但當圖像含有透明色或Alpha通道時,它的功能又和TransparentBlt、AlphaBlend相同。因此,在一般情況下,我們都應該儘量調用CImage::Draw方法來繪製圖像。
例如,下面的示例Ex_Image是實現這樣的功能:當選擇"文件"ò"打開"菜單命令後,彈出一個文件打開對話框。當選定一個圖像文件後,就會在窗口客戶區中顯示該圖像文件內容。這個示例的具體步驟如下:
(1) 創建一個默認的單文檔程序項目Ex_Image。
(2) 打開stdafx.h文件中添加CImage類的包含文件atlimage.h。
(3) 在CEx_ImageView類添加ID_FILE_OPEN的COMMAND事件映射程序,並添加下列代碼:
void CEx_ImageView::OnFileOpen() { CString strFilter; CSimpleArray<GUID> aguidFileTypes; HRESULT hResult; // 獲取CImage支持的圖像文件的過濾字符串 hResult = m_Image.GetExporterFilterString(strFilter,aguidFileTypes, _T( "All Image Files") ); if (FAILED(hResult)) { MessageBox("GetExporterFilter調用失敗!"); return; } CFileDialog dlg(TRUE, NULL, NULL, OFN_FILEMUSTEXIST, strFilter); if(IDOK != dlg.DoModal()) return; m_Image.Destroy(); // 將外部圖像文件裝載到CImage對象中 hResult = m_Image.Load(dlg.GetFileName()); if (FAILED(hResult)) { MessageBox("調用圖像文件失敗!"); return; } // 設置主窗口標題欄內容 CString str; str.LoadString(AFX_IDS_APP_TITLE); AfxGetMainWnd()->SetWindowText(str + " - " +dlg.GetFileName()); Invalidate(); // 強制調用OnDraw } |
(4) 定位到CEx_ImageView::OnDraw函數處,添加下列代碼:
void CEx_ImageView::OnDraw(CDC* pDC) { CEx_ImageDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!m_Image.IsNull()) { m_Image.Draw(pDC->m_hDC,0,0); } } |
(5) 打開Ex_ImageView.h文件,添加一個公共的成員數據m_Image:
public: CImage m_Image; |
(6) 編譯並運行。單擊"打開"工具按鈕,在彈出的對話框中指定一個圖像文件後,單擊"打開"按鈕,其結果如圖7.21所示。
CImage::Save方法能將一個圖像文件按另一種格式來保存,它的原型如下:
HRESULT Save( LPCTSTR pszFileName, REFGUID guidFileType= GUID_NULL); |
其中,pszFileName用來指定一個文件名,guidFileType用來指定要保存的圖像文件格式,當爲GUID_NULL時,其文件格式由文件的擴展名來決定,這也是該函數的默認值。它還可以是GUID_BMPFile(BMP文件格式)、GUID_PNGFile(PNG文件格式)、 GUID_JPEGFile(JPEG文件格式)和GUID_GIFFile(GIF文件格式)。
例如,下面的過程是在Ex_Image示例基礎上進行的,我們在CEx_ImageView類添加ID_FILE_SAVE_AS的COMMAND事件映射程序,並添加下列代碼:
void CEx_ImageView::OnFileSaveAs()
{
if (m_Image.IsNull()) {
MessageBox("你還沒有打開一個要保存的圖像文件!");
return;
}
CString strFilter;
strFilter = "位圖文件|*.bmp|JPEG 圖像文件|*.jpg| \
GIF 圖像文件|*.gif|PNG 圖像文件|*.png||";
CFileDialog dlg(FALSE,NULL,NULL,NULL,strFilter);
if ( IDOK != dlg.DoModal())
return;
// 如果用戶沒有指定文件擴展名,則爲其添加一個
CString strFileName;
CString strExtension;
strFileName = dlg.m_ofn.lpstrFile;
if (dlg.m_ofn.nFileExtension == 0)
{
switch (dlg.m_ofn.nFilterIndex)
{
case 1:
strExtension = "bmp"; break;
case 2:
strExtension = "jpg"; break;
case 3:
strExtension = "gif"; break;
case 4:
strExtension = "png"; break;
default:
break;
}
strFileName = strFileName + '.' + strExtension;
}
// 圖像保存
HRESULT hResult = m_Image.Save(strFileName);
if (FAILED(hResult))
MessageBox("保存圖像文件失敗!");
CImage::Save方法能將一個圖像文件按另一種格式來保存,它的原型如下:
HRESULT Save( LPCTSTR pszFileName, REFGUID guidFileType= GUID_NULL); |
其中,pszFileName用來指定一個文件名,guidFileType用來指定要保存的圖像文件格式,當爲GUID_NULL時,其文件格式由文件的擴展名來決定,這也是該函數的默認值。它還可以是GUID_BMPFile(BMP文件格式)、GUID_PNGFile(PNG文件格式)、 GUID_JPEGFile(JPEG文件格式)和GUID_GIFFile(GIF文件格式)。
例如,下面的過程是在Ex_Image示例基礎上進行的,我們在CEx_ImageView類添加ID_FILE_SAVE_AS的COMMAND事件映射程序,並添加下列代碼:
void CEx_ImageView::OnFileSaveAs()
{
if (m_Image.IsNull()) {
MessageBox("你還沒有打開一個要保存的圖像文件!");
return;
}
CString strFilter;
strFilter = "位圖文件|*.bmp|JPEG 圖像文件|*.jpg| \
GIF 圖像文件|*.gif|PNG 圖像文件|*.png||";
CFileDialog dlg(FALSE,NULL,NULL,NULL,strFilter);
if ( IDOK != dlg.DoModal())
return;
// 如果用戶沒有指定文件擴展名,則爲其添加一個
CString strFileName;
CString strExtension;
strFileName = dlg.m_ofn.lpstrFile;
if (dlg.m_ofn.nFileExtension == 0)
{
switch (dlg.m_ofn.nFilterIndex)
{
case 1:
strExtension = "bmp"; break;
case 2:
strExtension = "jpg"; break;
case 3:
strExtension = "gif"; break;
case 4:
strExtension = "png"; break;
default:
break;
}
strFileName = strFileName + '.' + strExtension;
}
// 圖像保存
HRESULT hResult = m_Image.Save(strFileName);
if (FAILED(hResult))
MessageBox("保存圖像文件失敗!");
變成黑白圖片
由於許多圖像文件使用顏色表來發揮顯示設備的色彩顯示能力,因而將一張彩色圖片變成黑色圖片時需要調用CImage::IsIndexed來判斷是否使用顏色表,若是則修改顏色表,否則直接將像素進行顏色設置。例如下面的代碼:
void CEx_ImageView::MakeBlackAndwhite(CImage* image) { if (image->IsNull()) return; if (!image->IsIndexed()) { // 直接修改像素顏色 COLORREF pixel; int maxY = image->GetHeight(), maxX = image->GetWidth(); byte r,g,b,avg; for (int x=0; x<maxX; x++) { for (int y=0; y<maxY; y++) { pixel = image->GetPixel(x,y); r = GetRValue(pixel); g = GetGValue(pixel); b = GetBValue(pixel); avg = (int)((r + g + b)/3); image->SetPixelRGB(x,y,avg,avg,avg); } } } else { // 獲取並修改顏色表 int MaxColors = image->GetMaxColorTableEntries(); RGBQUAD* ColorTable; ColorTable = new RGBQUAD[MaxColors]; image->GetColorTable(0,MaxColors,ColorTable); for (int i=0; i<MaxColors; i++) { int avg = (ColorTable[i].rgbBlue + ColorTable[i].rgbGreen + ColorTable[i].rgbRed)/3; ColorTable[i].rgbBlue = avg; ColorTable[i].rgbGreen = avg; ColorTable[i].rgbRed = avg; } image->SetColorTable(0,MaxColors,ColorTable); delete(ColorTable); } } |
至此,我們介紹了GDI+和CImage的一般使用方法和技巧。當然,它們本身還有許多更深入的方法,由於篇幅所限,這裏不再一一討論。