附例:一种对图象进行局部放大的有效方法
在实际工作中,对图象进行局部放大,以便更加清楚、细致的观察图象的某个部位,是经常遇到的问题。在Visual C++6.0中,巧妙、灵活的运用CDC类的StretchBlt()函数以及有效的完成对鼠标的消息映射等,就能实现这一目的;这里所实现的对图象进行局部放大的操作是:
(1)移动MOUSE鼠标,放大显示图象的不同部位。
(2)左击鼠标放大倍率。
(3)右击鼠标减少倍率。
实现结果:见以下图1和图2所示
图1:原照片 图2:局部放大后的照片
一、StretchBlt()函数
CDC类定义设备环境对象类,其对象提供操作设备环境(如显示器或打印机等)的成员函数,以及操作与窗口客户区相关的显示描述表的成员函数。StrechBlt()就是CDC类中的一个函数,它将位图从源矩形和设备移进目的矩形,并为适应目的矩形框,还可能压缩或放大位图。StrechBlt函数原形如下:
BOOL StretchBlt(int x,int y,int nWidth,int nHeight,CDC *pSrcDC,int xSrc,int ySrc,int nSrcWidth,int nSrcHeight,DWORD dwRop);
其返回值是:若位图绘制成功,则返回非0值,否则返回值为0。
参数:x 目标矩形左上角的逻辑x坐标; y 目标矩形左上角的逻辑y坐标;
nWidth 目标矩形的逻辑宽度; nHeight 目标矩形的逻辑高度;
pSrcDC 指定源设备环境; XSrc 源矩形左上角的逻辑x坐标;
YSrc 源矩形左上角的逻辑y坐标; nSrcWidth 源矩形的逻辑宽度;
nSrcHeight 源矩形的逻辑高度; dwRop 指定要执行的光栅操作;
说明:将位图从源矩形拷贝到目标矩形中,并按需要拉伸或压缩位图,使其适应目标矩形的大小。
二、实现过程:
(1)建立一个单文档SDI应用程序,名为:图象放大镜
(2)在视图类的View.h的public中添加以下数据成员:
CSize m_sizeDest;
CSize m_sizeSource;
CBitmap *m_pBitmap;//位图类指针
CDC *m_pdcMem;//CDC类指针
int oldx,oldy,s,d;
bool recover;//布尔类型变量,即:真或假
long mana;
(3)在资源中加入你自己喜欢的位图,并设ID为:IDB_BITMAP1
Insert->Resource->点黑BITMAP->New->Import->你找到一个你喜欢的位图图形,加到项目中。
(4)在视图类的View.cpp的构造函数中,进行初始化数据成员
CMyView::CMyView()
{
// TODO: add construction code here
m_pdcMem=new CDC;//CDC类
m_pBitmap=new CBitmap;//位图类
recover=true;//赋给布尔类型变量为真
s=30; d=45;
mana=SRCCOPY;
}
(5)在视图类的View.cpp的析构函数中,对用完后的数据成员进行释放
CMyView::~CMyView()
{
delete m_pdcMem;//释放为CDC类开辟的一片单元
delete m_pBitmap;//释放为位图类开辟的一片单元
}
注意:1、将主框架类MainFrm.h中的保护模式protected:下的
CStatusBar m_wndStatusBar; 剪切到公共模式public:下
2、在视图类执行文件CMyView.cpp中,加入:#include “MainFrm.h”
(6)在视图类的View.cpp的显示函数OnDraw()中编程:
void CMyView::OnDraw(CDC* pDC)
{
CMyDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
static bool load;
if(!load)
{
BITMAP bm;
load = !load;
m_pBitmap->LoadBitmap(IDB_BITMAP1); //位图类中的成员函数,
//从程序的可执行文件中调入指定的位图资源,并连接位图到对
//象,初始化对象,参数是:位图资源ID号
m_pdcMem->CreateCompatibleDC(pDC); //CDC类成员函数,创建
//一个内存设备环境,以便位图在内存中保存下来,并与指定设备(窗口
//设备)环境相兼容,参数是:设备环境指针
m_pdcMem->SelectObject(m_pBitmap);//将位图对象选入内存设备环境中
//参数是:指向一个要选择的CBitmap对象的指针
m_pBitmap->GetObject(sizeof(bm),&bm);//sizeof是运算符,它的目的是返
//回操作数所占的内存空间大小(字节数),这里bm是数据类型,计算bm
//类型数据所占的字节数,&bm是BITMAP对象bm的引用,即地址
m_sizeSource.cx=bm.bmWidth;
m_sizeSource.cy=bm.bmHeight;
m_sizeDest=m_sizeSource;
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);
}
// TODO: add draw code for native data here
}
(7)将鼠标移动消息WM_MOUSEMOVE映射到视图类中,并编程:
view->Clswizard->在ClassName中找到WM_MOUSEMOVE点黑->Add Function
->Edit Code
void CMyView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CString cord;
int dd;
CRect srect,drect,mrect;
CMainFrame *pFrame=(CMainFrame *)AfxGetApp()->m_pMainWnd;
CStatusBar *pStatus=&pFrame->m_wndStatusBar;
if(pStatus)
{
cord.Format("X=%d,Y=%d",point.x,point.y);
pStatus->SetPaneText(1,cord);
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);
}
pDC->StretchBlt(drect.left,drect.top,drect.Width(),
drect.Height(),m_pdcMem,srect.left,srect.top,
srect.Width(),srect.Height(),SRCCOPY);
//将位图从源矩形和设备移进目的矩形,为适应目的矩形框,
//可能压缩或放大位图。MFC类库大全353页
oldx=point.x;
oldy=point.y;
ReleaseDC(pDC);
}
recover=true;
CView::OnMouseMove(nFlags, point);
}
(8)将鼠标右键按下消息WM_RBUTTONDOWN映射到视图类中,并编程
view->Clswizard->在ClassName中找到WM_RBUTTONDOWN点黑->
Add Function->Edit Code
void CMyView::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if(d>5)
{
{ CDC *pDC=GetDC();
pDC->StretchBlt(oldx-d,oldy-d,2*d,2*d,m_pdcMem,oldx-d,
oldy-d,2*d,2*d,mana);
d-=10;
ReleaseDC(pDC);
CMyView::OnMouseMove(nFlags, point);
}
CView::OnRButtonDown(nFlags, point);
}
}
(9)将鼠标左键按下消息WM_LBUTTONDOWN映射到视图类中,并编程
view->Clswizard->在ClassName中找到WM_LBUTTONDOWN点黑->
Add Function->Edit Code
void CMyView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if(d<150)
{
d+=10;
CMyView::OnMouseMove(nFlags, point);
}
CView::OnLButtonDown(nFlags, point);
}
(10)编译并运行,将鼠标放在图像某处,见某处有放大,再不停按鼠标左键,见逐渐放大,再按鼠标右键,见逐渐缩小。
在实际工作中,对图象进行局部放大,以便更加清楚、细致的观察图象的某个部位,是经常遇到的问题。在Visual C++6.0中,巧妙、灵活的运用CDC类的StretchBlt()函数以及有效的完成对鼠标的消息映射等,就能实现这一目的;这里所实现的对图象进行局部放大的操作是:
(1)移动MOUSE鼠标,放大显示图象的不同部位。(2)左击鼠标放大倍率。
(3)右击鼠标减少倍率。
实现结果:见以下图1和图2所示:
图1:原图象 图2:局部放大后的图象
一、StretchBlt()函数
CDC类定义设备环境对象类,其对象提供操作设备环境(如显示器或打印机
等)的成员函数,以及操作与窗口客户区相关的显示描述表的成员函数。StrechBlt()就是CDC类中的一个函数,它将位图从源矩形和设备移进目的矩形,并为适应目的矩形框,还可能压缩或放大位图。StrechBlt函数原形如下:
BOOL StretchBlt(int x,int y,int nWidth,int nHeight,CDC *pSrcDC,int xSrc,int ySrc,int nSrcWidth,int nSrcHeight,DWORD dwRop);
其返回值是:若位图绘制成功,则返回非0值,否则返回值为0。
参数:x 目标矩形左上角的逻辑x坐标; y 目标矩形左上角的逻辑y坐标;
nWidth 目标矩形的逻辑宽度; nHeight 目标矩形的逻辑高度;
pSrcDC 指定源设备环境; XSrc 源矩形左上角的逻辑x坐标;
YSrc 源矩形左上角的逻辑y坐标; nSrcWidth 源矩形的逻辑宽度;
nSrcHeight 源矩形的逻辑高度; dwRop 指定要执行的光栅操作;
说明:将位图从源矩形拷贝到目标矩形中,并按需要拉伸或压缩位图,使其适应目标矩形的大小。
二、制作图象放大镜的程序设计过程:
(1)建立一个单文档SDI应用程序,名为:放大镜
(2)在视图类的View.h的public中添加以下数据成员:
CSize m_sizeDest;
CSize m_sizeSource;
CBitmap *m_pBitmap;//位图类指针
CDC *m_pdcMem;//CDC类指针
int oldx,oldy,s,d;
bool recover;//布尔类型变量,即:真或假
long mana;
(3)在资源中加入你自己喜欢的位图,并设ID为:IDB_BITMAP1
Insert->Resource->点黑BITMAP->New->Import->找到一个你喜欢的位图图形,加到项目中。
(4)在视图类的View.cpp的构造函数中,进行初始化数据成员
CMyView::CMyView()
{
// TODO: add construction code here
m_pdcMem=new CDC;//CDC类
m_pBitmap=new CBitmap;//位图类
recover=true;//赋给布尔类型变量为真
s=30; d=45;
mana=SRCCOPY;
}
(5)在视图类的View.cpp的析构函数中,对用完后的数据成员进行释放
CMyView::~CMyView()
{
delete m_pdcMem;//释放为CDC类开辟的一片单元
delete m_pBitmap;//释放为位图类开辟的一片单元
}
注意:1、将主框架类MainFrm.h中的保护模式protected:下的
CStatusBar m_wndStatusBar; 剪切到公共模式public:下
2、在视图类执行文件CMyView.cpp中,加入:#include “MainFrm.h”
(6)在视图类的View.cpp的显示函数OnDraw()中编程:
void CMyView::OnDraw(CDC* pDC)
{
CMyDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
static bool load;
if(!load)
{
BITMAP bm;
load = !load;
m_pBitmap->LoadBitmap(IDB_BITMAP1); //位图类中的成员函数,
//从程序的可执行文件中调入指定的位图资源,并连接位图到对象,
//初始化对象,参数是:位图资源ID号
m_pdcMem->CreateCompatibleDC(pDC); //CDC类成员函数,创建一个
//内存设备环境,以便位图在内存中保存下来,并与指定设备(窗口设备)
//环境相兼容,参数是:设备环境指针
m_pdcMem->SelectObject(m_pBitmap);//将位图对象选入内存设备环境中,
//参数是:指向一个要选择的CBitmap对象的指针。
m_pBitmap->GetObject(sizeof(bm),&bm);//sizeof是运算符,它的目的是返
//回操作数所占的内存空间大小(字节数),这里bm是数据类型,计算bm
//类型数据所占的字节数,&bm是BITMAP对象bm的引用,即地址
m_sizeSource.cx=bm.bmWidth;
m_sizeSource.cy=bm.bmHeight;
m_sizeDest=m_sizeSource;
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);
}
// TODO: add draw code for native data here
}
(7)将鼠标移动消息WM_MOUSEMOVE映射到视图类中,并编程:
view->Clswizard->在ClassName中找到WM_MOUSEMOVE点黑->
Add Function->Edit Code
void CMyView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CString cord;
int dd;
CRect srect,drect,mrect;
CMainFrame *pFrame=(CMainFrame *)AfxGetApp()->m_pMainWnd;
CStatusBar *pStatus=&pFrame->m_wndStatusBar;
if(pStatus)
{
cord.Format("X=%d,Y=%d",point.x,point.y);
pStatus->SetPaneText(1,cord);
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);
}
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;
CView::OnMouseMove(nFlags, point);
}
(8)将鼠标右键按下消息WM_RBUTTONDOWN映射到视图类中,并编程
view->Clswizard->在ClassName中找到WM_RBUTTONDOWN点黑->
Add Function->Edit Code
void CMyView::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if(d>5)
{
{ CDC *pDC=GetDC();
pDC->StretchBlt(oldx-d,oldy-d,2*d,2*d,m_pdcMem,oldx-d,
oldy-d,2*d,2*d,mana);
d-=10;
ReleaseDC(pDC);
CMyView::OnMouseMove(nFlags, point);
}
CView::OnRButtonDown(nFlags, point);
}
}
(9)将鼠标左键按下消息WM_LBUTTONDOWN映射到视图类中,并编程
view->Clswizard->在ClassName中找到WM_LBUTTONDOWN点黑->
Add Function->Edit Code
void CMyView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if(d<150)
{
d+=10;
CMyView::OnMouseMove(nFlags, point);
}
CView::OnLButtonDown(nFlags, point);
}
(10)编译并运行,将鼠标放在图像某处,见某处有放大,再不停按鼠标左键,见逐渐放大,再按鼠标右键,见逐渐缩小。
三、小结
Visual C++6.0有很强的图形图象设计功能,而其CDC类的StretchBlt函数对
位图操作又有拉伸与压缩的独特功能;因而用Visual C++6.0进行图形局部放大处理极为方便。该方法的实现,使我们对Visual C++的技术内涵又有了进一步的了解。相信以后通过不断学习与运用,能掌握更多的技巧,为教学、生产与科研服务。