明輝手游網(wǎng)中心:是一個免費提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺!

在MFC下完成圖像放大鏡

[摘要]信息產(chǎn)業(yè)部電子第二十二研究所青島分所 郎銳 一、 引言 當(dāng)我們想仔細觀察某個細微的東西時,一般都會使用放大鏡。而要看清顯示在計算機屏幕上的圖片或文字時通常也 可以借助于Windows操作系統(tǒng)附帶...
信息產(chǎn)業(yè)部電子第二十二研究所青島分所 郎銳  

一、 引言

當(dāng)我們想仔細觀察某個細微的東西時,一般都會使用放大鏡。而要看清顯示在計算機屏幕上的圖片或文字時通常也
可以借助于Windows操作系統(tǒng)附帶的放大程序來實現(xiàn)。但該程序只能以固定的放大倍數(shù)去進行觀看,有時并不能滿足我們
的需要。本文就通過MFC基本類庫提供的StretchBlt函數(shù)來實現(xiàn)對屏幕圖象的局部放大,并且可以隨意放大、縮小,選取
到合適的放大倍數(shù)來對圖像的細節(jié)進行觀察。

二、 設(shè)計與實現(xiàn)

本程序主要用來對圖像的局部進行可調(diào)倍數(shù)的放大,應(yīng)當(dāng)具有以下主要功能:

1. 移動MOUSE放大顯示圖像的不同部位
2. 左擊增加放大倍率、右擊減少放大倍率。  

從光學(xué)角度來看,對物體的放大成像是通過把較小的真實物體顯示成尺寸較大的虛像來實現(xiàn)的。因此我們可以用類
似的原理,把圖像中待放大的區(qū)間從較小的顯示范圍拉伸到一個比較大的顯示范圍即可達到圖像放大的效果,兩個區(qū)間
的比值也就是圖像的放大倍率?梢酝ㄟ^縮小源區(qū)間的范圍或擴大放大區(qū)間的范圍來實現(xiàn)放大倍率的調(diào)整。在MFC基本類
庫中提供有CDC類的StretchBlt函數(shù)可以將一幅位圖從一個源矩形以一定的光柵操作拷貝到另外一個不同大小的目標(biāo)矩形
中去,因此可以用此函數(shù)來實現(xiàn)圖象放大的功能,其函數(shù)原形聲明如下:

BOOL StretchBlt( int x, int y, //目標(biāo)矩形的坐標(biāo)原點
int nWidth, int nHeight, //目標(biāo)矩形的長度和寬度  
CDC* pSrcDC, //源設(shè)備環(huán)境句柄
int xSrc, int ySrc, //源矩形的坐標(biāo)原點
int nSrcWidth, int nSrcHeight, //源矩形的長度和寬度
DWORD dwRop ); //光柵操作標(biāo)志

當(dāng)指定的源和目標(biāo)矩形的寬度或高度不一樣時,StretchBlt函數(shù)將創(chuàng)建一個位圖的鏡像。如果是寬度有變化,就沿x軸
創(chuàng)建鏡像;如果是高度上有變化就沿y軸創(chuàng)建鏡像。而且該函數(shù)可以在內(nèi)存中對源圖象做拉伸或壓縮處理后再拷貝到目標(biāo)矩
形中去。

要放大圖像首先要把圖像顯示出來,一般可以從文件動態(tài)裝載或者直接從資源中用LoadBitMap讀取位圖資源。下面的代
碼放在視類的OnDraw函數(shù)中,用以在第一次調(diào)用時將位圖裝載并顯示出來,以后再被調(diào)用只是負責(zé)重畫:

……
static bool load;
if (!load)
{
BITMAP bm;
load = !load;
//裝載位圖到 m_pBitmap
m_pBitmap->LoadBitmap(IDB_BITMAP1);
//創(chuàng)建相關(guān)的設(shè)備環(huán)境
m_pdcMem->CreateCompatibleDC(pDC);
//將位圖從m_ pBitmap中裝載到m_pdcMem中
m_pdcMem->SelectObject(m_pBitmap);
m_pBitmap->GetObject(sizeof(bm),&bm);
m_sizeSource.cx = bm.bmWidth;
m_sizeSource.cy = bm.bmHeight;
m_sizeDest = m_sizeSource;
//把位圖從m_pdcMem中裝載到當(dāng)前正在使用的設(shè)備環(huán)境中
pDC->StretchBlt(0,0,m_sizeSource.cx,m_sizeSource.cy,m_pdcMem,0,0,m_sizeSource.cx,m_sizeSource.cy,mana);
}
else
{
//重畫圖像
pDC->StretchBlt(0,0,m_sizeSource.cx,m_sizeSource.cy,m_pdcMem,0,0,m_sizeSource.cx,m_sizeSource.cy,mana);
SetCursor(NULL);//隱藏鼠標(biāo)
}

要實現(xiàn)前面提到的第一個功能:移動MOUSE放大顯示圖像的不同部位,顯然首先要在WM_MOUSEMOVE消息的響應(yīng)函數(shù)里編寫
代碼。以整形變量s和d來分別表示所選取的源和目標(biāo)區(qū)域的大小,再通過消息響應(yīng)函數(shù)OnMouseMove的入口參數(shù)point來確定當(dāng)
前的鼠標(biāo)位置就可以計算出我們要選取的源和目標(biāo)區(qū)域在圖像的位置。放大的工作只需通過StretchBlt函數(shù)將源區(qū)域中所在的
圖像拉伸到目標(biāo)矩形那么大,并拷貝給目標(biāo)區(qū)域即可實現(xiàn)所選區(qū)域的放大效果,下面是部分主要代碼:

……
//確定目標(biāo)區(qū)域、源區(qū)域的坐標(biāo)位置
CRect srect,drect,mrect;
srect.left = point.x - s;
srect.top = point.y - s;
srect.right = point.x + s;
srect.bottom = point.y + s;
drect.left = point.x - d;
drect.top = point.y - d;
drect.right = point.x + d;
drect.bottom = point.y + d;

mrect.left = oldx - d;
mrect.top = oldy - d;
mrect.right = oldx + d;
mrect.bottom = oldy + d;
dd = 2*d;
//獲取可用設(shè)備環(huán)境句柄
CDC * pDC = GetDC();
OnPrepareDC(pDC);
if (recover)
{
pDC->BitBlt(mrect.left,mrect.top,dd,dd,m_pdcMem,mrect.left,mrect.top,mana);
}
//隱藏鼠標(biāo)
SetCursor(NULL);
//拉伸放大
pDC->StretchBlt(drect.left,drect.top,drect.Width(),drect.Height(),m_pdcMem,srect.left,srect.top,srect.Width(),srect.Height(),SRCCOPY);
//保存當(dāng)前鼠標(biāo)位置備用
oldx = point.x; oldy = point.y;
//釋放設(shè)備環(huán)境句柄
ReleaseDC(pDC);
recover = true;
……

為了實現(xiàn)第二個功能:左擊增加放大倍率、右擊減少放大倍率,可以分別在消息WM_LBUTTONDOWN和消息WM_RBUTTONDOWN中添加改
變選取區(qū)域大小的代碼來實現(xiàn)。如果選取源矩形不變而改變目標(biāo)矩形的大小會隨著放大倍數(shù)的增大,顯示區(qū)域也不斷增大,當(dāng)放大到
一定程度的時候會另人無法忍受,因此選取通過縮放源矩形大小來控制放大倍數(shù)的方案:

void CZoomInView::OnRButtonDown(UINT nFlags, CPoint point)  
{
if (s < 60)  
{
SetCursor(NULL);
s+=3;
OnMouseMove(nFlags, point);
}  
CView::OnRButtonDown(nFlags, point);
}
……
void CZoomInView::OnLButtonDown(UINT nFlags, CPoint point)  
{
if(s>5)
{
s-=3;  
SetCursor(NULL);
OnMouseMove(nFlags, point);
}
CView::OnLButtonDown(nFlags, point);
}

小結(jié):本文通過對MFC庫函數(shù)StretchBlt的使用來實現(xiàn)了對圖像位圖的局部細節(jié)的放大功能。本程序只是通過了一個簡單的例子做了講
解,重點放在StretchBlt函數(shù)的應(yīng)用上,功能上也只實現(xiàn)了對本程序客戶區(qū)圖象的放大,如要對屏幕上其他程序和桌面進行放大則還需
要引入系統(tǒng)鉤子(HOOK)的技術(shù)來實現(xiàn),并且需要把處理代碼放到動態(tài)連接庫中才可以實現(xiàn)全局鉤子。本程序在Windows 98下,以
Microsoft Visual C++ 6.0編譯通過。