信息产业部电子第二十二研究所青岛分所 郎锐
一、 引言
当我们想仔细观察某个细微的东西时,一般都会使用放大镜。而要看清显示在计算机屏幕上的图片或文字时通常也
可以借助于Windows操作系统附带的放大程序来实现。但该程序只能以固定的放大倍数去进行观看,有时并不能满足我们
的需要。本文就通过MFC基本类库提供的StretchBlt函数来实现对屏幕图象的局部放大,并且可以随意放大、缩小,选取
到合适的放大倍数来对图像的细节进行观察。
二、 设计与实现
本程序主要用来对图像的局部进行可调倍数的放大,应当具有以下主要功能:
1. 移动MOUSE放大显示图像的不同部位
2. 左击增加放大倍率、右击减少放大倍率。
从光学角度来看,对物体的放大成像是通过把较小的真实物体显示成尺寸较大的虚像来实现的。因此我们可以用类
似的原理,把图像中待放大的区间从较小的显示范围拉伸到一个比较大的显示范围即可达到图像放大的效果,两个区间
的比值也就是图像的放大倍率。可以通过缩小源区间的范围或扩大放大区间的范围来实现放大倍率的调整。在MFC基本类
库中提供有CDC类的StretchBlt函数可以将一幅位图从一个源矩形以一定的光栅操作拷贝到另外一个不同大小的目标矩形
中去,因此可以用此函数来实现图象放大的功能,其函数原形声明如下:
BOOL StretchBlt( int x, int y, //目标矩形的坐标原点
int nWidth, int nHeight, //目标矩形的长度和宽度
CDC* pSrcDC, //源设备环境句柄
int xSrc, int ySrc, //源矩形的坐标原点
int nSrcWidth, int nSrcHeight, //源矩形的长度和宽度
DWORD dwRop ); //光栅操作标志
当指定的源和目标矩形的宽度或高度不一样时,StretchBlt函数将创建一个位图的镜像。如果是宽度有变化,就沿x轴
创建镜像;如果是高度上有变化就沿y轴创建镜像。而且该函数可以在内存中对源图象做拉伸或压缩处理后再拷贝到目标矩
形中去。
要放大图像首先要把图像显示出来,一般可以从文件动态装载或者直接从资源中用LoadBitMap读取位图资源。下面的代
码放在视类的OnDraw函数中,用以在第一次调用时将位图装载并显示出来,以后再被调用只是负责重画:
……
static bool load;
if (!load)
{
BITMAP bm;
load = !load;
//装载位图到 m_pBitmap
m_pBitmap->LoadBitmap(IDB_BITMAP1);
//创建相关的设备环境
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中装载到当前正在使用的设备环境中
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);//隐藏鼠标
}
要实现前面提到的第一个功能:移动MOUSE放大显示图像的不同部位,显然首先要在WM_MOUSEMOVE消息的响应函数里编写
代码。以整形变量s和d来分别表示所选取的源和目标区域的大小,再通过消息响应函数OnMouseMove的入口参数point来确定当
前的鼠标位置就可以计算出我们要选取的源和目标区域在图像的位置。放大的工作只需通过StretchBlt函数将源区域中所在的
图像拉伸到目标矩形那么大,并拷贝给目标区域即可实现所选区域的放大效果,下面是部分主要代码:
……
//确定目标区域、源区域的坐标位置
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;
//获取可用设备环境句柄
CDC * pDC = GetDC();
OnPrepareDC(pDC);
if (recover)
{
pDC->BitBlt(mrect.left,mrect.top,dd,dd,m_pdcMem,mrect.left,mrect.top,mana);
}
//隐藏鼠标
SetCursor(NULL);
//拉伸放大
pDC->StretchBlt(drect.left,drect.top,drect.Width(),drect.Height(),m_pdcMem,srect.left,srect.top,srect.Width(),srect.Height(),SRCCOPY);
//保存当前鼠标位置备用
oldx = point.x; oldy = point.y;
//释放设备环境句柄
ReleaseDC(pDC);
recover = true;
……
为了实现第二个功能:左击增加放大倍率、右击减少放大倍率,可以分别在消息WM_LBUTTONDOWN和消息WM_RBUTTONDOWN中添加改
变选取区域大小的代码来实现。如果选取源矩形不变而改变目标矩形的大小会随着放大倍数的增大,显示区域也不断增大,当放大到
一定程度的时候会另人无法忍受,因此选取通过缩放源矩形大小来控制放大倍数的方案:
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);
}
小结:本文通过对MFC库函数StretchBlt的使用来实现了对图像位图的局部细节的放大功能。本程序只是通过了一个简单的例子做了讲
解,重点放在StretchBlt函数的应用上,功能上也只实现了对本程序客户区图象的放大,如要对屏幕上其他程序和桌面进行放大则还需
要引入系统钩子(HOOK)的技术来实现,并且需要把处理代码放到动态连接库中才可以实现全局钩子。本程序在Windows 98下,以
Microsoft Visual C++ 6.0编译通过。
……