- Visual C++程序开发范例宝典(软件工程师典藏版)
- 刘志铭 李贺 高茹编著
- 517字
- 2020-06-27 11:09:48
3.3 图片效果
图片特效设计丰富了计算机的内容,也为程序设计增添了不少色彩。本节主要通过图片马赛克效果、图片百叶窗效果、电影胶片特效和翻转图片效果几个实例来介绍如何对图片进行特效设计。
实例099 图片马赛克效果
这是一个可以提高基础技能的实例
实例位置:光盘\mingrisoft\03\099
实例说明
本实例实现了图片的马赛克效果,主要通过使用“编辑”/“马赛克”菜单命令,将图片以若干小块的方式渐渐显示出来,直到整张图片显示出来,如图3.17所示。
技术要点
图3.17 图片马赛克效果
本实例主要应用DrawDib库进行图像的绘制,使用该库可以提高图像的显示速度,它是图像处理的常用库,库里包含许多关于图像处理的函数,使用起来比较方便。要使用DrawDib库必须先用DrawDibOpen打开HDRAWDIB对象,然后通过HDRAWDIB对象进行图像绘制,HDRAWDIB对象是DrawDib库的设备环境句柄。
本实例的绘制过程是使用函数DrawDibOpen打开HDRAWDIB对象,然后使用函数CreateDIBSection创建与设备无关的位图,通过BitBlt函数将图像绘制在内存设备环境中,最后利用函数DrawDibDraw使用特效显示图像。
CreateDIBSection函数是创建与设备无关的位图,语法如下:
HBITMAP CreateDIBSection(HDC hdc,CONST BITMAPINFO *pbmi, UINT iUsage,VOID *ppvBits, HANDLE hSection,DWORD dwOffset);
参数说明:
● hdc:设备环境句柄。
● pbmi:BITMAPINFO结构对象。
● iUsage:说明BITMAPINFO结构中bmiColors的数据类型。
● ppvBits:与设备无关位图数据的缓存。
● hSection:可以创建位图对象的句柄。
● dwOffset:位图数据在文件中的位置。
DrawDibDraw函数是绘制与设备无关位图到屏幕上,语法如下:
BOOL DrawDibDraw(HDRAWDIB hdd,HDC hdc,int xDst,int yDst,int dxDst,int dyDst, LPBITMAPINFOHEADER lpbi,LPVOID lpBits,int xSrc,int ySrc,int dxSrc,int dySrc,UINT wFlag);
参数说明:
● hdd:HDRAWDIB对象句柄。
● hdc:设备环境句柄。
● xDst:目标矩形左顶点x轴坐标。
● yDst:目标矩形左顶点y轴坐标。
● dxDst:目标矩形的宽度。
● dyDst:目标矩形的高度。
● lpbi:BITMAPINFOHEADER结构对象。
● lpBits:位图数据缓存。
● xSrc:源矩形左顶点x轴坐标。
● ySrc:源矩形左顶点y轴坐标。
● dxSrc:源矩形的宽度。
● dySrc:源矩形的高度。
● wFlag:绘制的标识。
实现过程
(1)新建一个基于单文档的应用程序。
(2)在工程中加入对vfw32.lib的引用。
(3)在头文件中加入“#include "vfw.h"”语句。
(4)添加菜单项,设置ID属性为ID_VIEW,Caption属性为“马赛克”,并通过类向导添加菜单响应函数OnView。
(5)在CMosaicViewView类的头文件中声明变量:
class CMosaicViewView : public CView { protected: CMosaicViewView(); DECLARE_DYNCREATE(CMosaicViewView) //加入变量声明 BITMAP bm; HBITMAP m_bmpSrc; COLORREF*m_clrSrc; CSize m_size; HDRAWDIB m_hDrawDib; }
(6)在构造函数中初始化HDRAWDIB对象,代码如下:
CMosaicViewView::CMosaicViewView() { m_hDrawDib=NULL; m_hDrawDib=DrawDibOpen(); HBITMAP hBmp= (HBITMAP)LoadImage(NULL,"bitmap.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);//加载图片资源 HDC hMemDC=CreateCompatibleDC(NULL); if(hMemDC) { GetObject(hBmp,sizeof(bm),&bm); m_size=CSize(bm.bmWidth,bm.bmHeight); BITMAPINFOHEADER RGB32BITSBITMAPINFO= {sizeof(BITMAPINFOHEADER),bm.bmWidth,bm.bmHeight, 1,32,BI_RGB,0,0,0,0}; m_bmpSrc=CreateDIBSection(hMemDC,(BITMAPINFO*)&RGB32BITSBITMAPINFO, DIB_RGB_COLORS,(VOID**)&m_clrSrc,NULL,0); if(m_bmpSrc) { HBITMAP hOldBmp=(HBITMAP)SelectObject(hMemDC,m_bmpSrc); HDC hDC=CreateCompatibleDC(hMemDC); //创建兼容的设备上下文 if(hDC) { HBITMAP hOldBmp2=(HBITMAP)SelectObject(hDC,hBmp); //选入图像 BitBlt(hMemDC,0,0,bm.bmWidth,bm.bmHeight,hDC,0,0,SRCCOPY); //绘制图像 SelectObject(hDC,hOldBmp2); DeleteDC(hDC); } SelectObject(hMemDC,hOldBmp); } DeleteDC(hMemDC); } }
(7)在析构函数中实现HDRAWDIB对象的关闭和销毁,代码如下:
CMosaicViewView::~CMosaicViewView() { if(m_hDrawDib!=NULL) { DrawDibClose(m_hDrawDib); m_hDrawDib=NULL; } if(m_bmpSrc!=NULL) DeleteObject(m_bmpSrc); }
(8)“查看”/“马赛克”菜单命令的实现函数用于实现绘制图像,代码如下:
void CMosaicViewView::OnView() { if(m_bmpSrc==NULL||m_hDrawDib==NULL)return; Invalidate(); int nTileSize=10; int nTileNum=((m_size.cx+nTileSize-1)/nTileSize)*((m_size.cy+nTileSize-1)/nTileSize); POINT *pt=new POINT[nTileNum]; int x=0; int y=0; int i; for(i=0;i<nTileNum;i++) { pt[i].x=x; pt[i].y=y; x=x+nTileSize; if(x>m_size.cx) { x=0; y=y+nTileSize; } } BITMAPINFOHEADER RGB32BITSBITMAPINFO= {sizeof(BITMAPINFOHEADER),m_size.cx,m_size.cy, 1,32,BI_RGB,0,0,0,0,0};//设置位图头结构 CPaintDC dc(this); DrawDibRealize(m_hDrawDib,dc.GetSafeHdc(),TRUE); double fMax=RAND_MAX; for(i=nTileNum-1;i>=0;i--) { int n=(int)((double)nTileNum*rand()/fMax); x=pt[n].x; y=pt[n].y; DrawDibDraw(m_hDrawDib,dc.GetSafeHdc(),10+x,10+y,nTileSize,nTileSize, &RGB32BITSBITMAPINFO,(LPVOID)m_clrSrc, x,y,nTileSize,nTileSize,DDF_BACKGROUNDPAL); pt[n].x=pt[i].x; pt[n].y=pt[i].y; Sleep(20); } delete[] pt; DrawDibDraw(m_hDrawDib,dc.GetSafeHdc(),10,10,m_size.cx,m_size.cy, &RGB32BITSBITMAPINFO,(LPVOID)m_clrSrc, 0,0,m_size.cx,m_size.cy,DDF_BACKGROUNDPAL); }
举一反三
根据本实例,读者可以:
实现图片的淡入淡出效果。
实例100 图片百叶窗效果
这是一个可以提高基础技能的实例
实例位置:光盘\mingrisoft\03\100
实例说明
图3.18 图片百叶窗效果
在一些多媒体教学软件中,常常可以看到图像的显示特效,包括图像之间的过渡特效,这些特效给软件本身增色不少。本实例实现将图片以百叶窗的形式显示出来,运行效果如图3.18所示。
技术要点
本实例主要通过在一个循环语句中使用DrawDibDraw函数来绘制图像,DrawDibDraw函数和BitBlt函数作用相同,都是将一个设备环境中的数据复制到另一个设备环境中,DrawDibDraw函数语法如下:
BOOL DrawDibDraw(HDRAWDIB hdd,HDC hdc,int xDst,int yDst,int dxDst,int dyDst,LPBITMAPINFOHEADER lpbi,LPVOID lpBits, int xSrc,int ySrc,int dxSrc,int dySrc,UINT wFlags);
参数说明:
● hdd:HDRAWDIB对象。
● hdc:设备环境句柄。
● xDst:目标图像左顶点x轴坐标。
● yDst:目标图像左顶点y轴坐标。
● dxDst:目标图像的宽度。
● dyDst:目标图像的高度。
● lpbi:LPBITMAPINFOHEADER结构对象。
● lpBits:存储图像数据的缓存。
● xSrc:源图像左顶点x轴坐标。
● ySrc:源图像左顶点y轴坐标。
● dxSrc:源图像的宽度。
● dySrc:源图像的高度。
● wFlags:表示绘画标记。
实现过程
(1)新建一个基于单文档的应用程序。
(2)向工程中加入图片资源,ID属性设置为IDB_SHUTTER。在工程中添加对vfw32.lib库的引用。
(3)修改ID属性为IDR_MAINFRAME菜单资源,在“查看”菜单下新建子菜单,设置ID属性为ID_VIEW,设置Caption属性为“百叶”,并添加实现函数OnView。
(4)在头文件ShutterView.h中添加文件的引用和变量声明:
#include "vfw.h" HBITMAP m_bmpSrc; COLORREF*m_clrSrc; CSize m_size; HDRAWDIB m_hDrawDib;
(5)在CShutterView方法中完成对HDRAWDIB对象的创建,代码如下:
CShutterView::CShutterView() { bstart=FALSE; m_hDrawDib=NULL; m_hDrawDib=DrawDibOpen(); //加载图片资源 HBITMAP hBmp=(HBITMAP)LoadImage(NULL,"bitmap.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE); HDC hMemDC=CreateCompatibleDC(NULL); //创建兼容的设备上下文 if(hMemDC) { GetObject(hBmp,sizeof(bm),&bm); m_size=CSize(bm.bmWidth,bm.bmHeight); //获得位图的宽和高 BITMAPINFOHEADER RGB32BITSBITMAPINFO= {sizeof(BITMAPINFOHEADER),bm.bmWidth,bm.bmHeight,1,32,BI_RGB,0,0,0,0,0}; m_bmpSrc=CreateDIBSection(hMemDC,(BITMAPINFO*)&RGB32BITSBITMAPINFO, DIB_RGB_COLORS,(VOID**)&m_clrSrc,NULL,0); if(m_bmpSrc) { HBITMAP hOldBmp=(HBITMAP)SelectObject(hMemDC,m_bmpSrc); HDC hDC=CreateCompatibleDC(hMemDC); if(hDC) { HBITMAP hOldBmp2=(HBITMAP)SelectObject(hDC,hBmp); BitBlt(hMemDC,0,0,bm.bmWidth,bm.bmHeight,hDC,0,0,SRCCOPY); //绘制图像 SelectObject(hDC,hOldBmp2); DeleteDC(hDC); } SelectObject(hMemDC,hOldBmp); } DeleteDC(hMemDC); } }
(6)开始显示百叶窗效果,代码如下:
void CShutterView::OnView() { bstart=TRUE; this->Invalidate(); }
(7)在OnDraw中实现百叶窗效果,代码如下:
void CShutterView::OnDraw(CDC* pDC) { CShutterDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if(bstart) { if(m_bmpSrc==NULL||m_hDrawDib==NULL)return; Invalidate(); BOOL bDone=FALSE; int i=0,j; BITMAPINFOHEADER REG32BITSBITMAPINFO= {sizeof(BITMAPINFOHEADER),bm.bmWidth,bm.bmHeight,1,32,BI_RGB,0,0,0,0,0}; DrawDibRealize(m_hDrawDib,pDC->GetSafeHdc(),true); for(i=0;i<20;i++) { for(j=i;j<m_size.cy;j+=20) DrawDibDraw(m_hDrawDib,pDC->GetSafeHdc(),j,0,1, m_size.cy,®32BITSBITMAPINFO,(LPVOID)m_clrSrc, j,0,1,m_size.cy,DDF_BACKGROUNDPAL); Sleep(200); } bstart=FALSE; } }
举一反三
根据本实例,读者可以:
开发横向百叶窗。
实例101 电影胶片特效
这是一个可以提高基础技能的实例
实例位置:光盘\mingrisoft\03\101
实例说明
本实例主要模仿电影播放时的效果实现图片从程序的一侧移动出来。选择“编辑”/“移动”菜单命令,图片就会从程序窗体的一侧移动出来,结果如图3.19所示。
图3.19 电影胶片特效
技术要点
本实例主要应用了DrawDib库进行图像的绘制,有关该类库的介绍可参见实例099图片马赛克效果。
实现过程
(1)新建一个基于单文档的应用程序。
(2)在工程中加入对vfw32.lib的应用。
(3)在头文件中加入“#include "vfw.h"”。
(4)添加菜单项,设置ID属性为ID_VIEW,Caption属性为“移动”,并通过类向导添加菜单响应函数OnView。
(5)在CFilmMoveViewView类的头文件中声明变量:
class CFilmMoveViewView : public CView { protected: //加入变量声明 HBITMAP m_bmpSrc; COLORREF*m_clrSrc; CSize m_size; HDRAWDIB m_hDrawDib; BITMAP bm; }
(6)在构造函数中初始化HDRAWDIB对象,代码如下:
CFilmMoveViewView::CFilmMoveViewView() { m_hDrawDib=NULL; m_hDrawDib=DrawDibOpen(); HBITMAP hBmp= (HBITMAP)LoadImage(NULL,"bitmap.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE); HDC hMemDC=CreateCompatibleDC(NULL); if(hMemDC) { GetObject(hBmp,sizeof(bm),&bm); m_size=CSize(bm.bmWidth,bm.bmHeight); BITMAPINFOHEADER RGB32BITSBITMAPINFO= {sizeof(BITMAPINFOHEADER),bm.bmWidth,bm.bmHeight, 1,32,BI_RGB,0,0,0,0}; m_bmpSrc=CreateDIBSection(hMemDC,(BITMAPINFO*)&RGB32BITSBITMAPINFO, DIB_RGB_COLORS,(VOID**)&m_clrSrc,NULL,0); if(m_bmpSrc) { HBITMAP hOldBmp=(HBITMAP)SelectObject(hMemDC,m_bmpSrc); HDC hDC=CreateCompatibleDC(hMemDC); if(hDC) { HBITMAP hOldBmp2=(HBITMAP)SelectObject(hDC,hBmp); BitBlt(hMemDC,0,0,bm.bmWidth,bm.bmHeight,hDC, 0,0,SRCCOPY); SelectObject(hDC,hOldBmp2); DeleteDC(hDC); } SelectObject(hMemDC,hOldBmp); } DeleteDC(hMemDC); } }
(7)在析构函数中实现HDRAWDIB对象的关闭和销毁,代码如下:
CFilmMoveViewView::~CFilmMoveViewView() { if(m_hDrawDib!=NULL) { DrawDibClose(m_hDrawDib); m_hDrawDib=NULL; } if(m_bmpSrc!=NULL) DeleteObject(m_bmpSrc); }
(8)“查看”/“移动”菜单的实现函数用于实现绘制图像,代码如下:
void CFilmMoveViewView::OnView() { if(m_bmpSrc==NULL||m_hDrawDib==NULL)return; Invalidate(); BOOL bDone=false; int i=0; BITMAPINFOHEADER RGB32BITSBITMAPINFO= {sizeof(BITMAPINFOHEADER),m_size.cx,m_size.cy,1,32,BI_RGB,0,0,0,0,0}; CPaintDC dc(this); while(!bDone) { if(i>m_size.cx) { i=m_size.cx; bDone=true; } DrawDibRealize(m_hDrawDib,dc.GetSafeHdc(),true); DrawDibDraw(m_hDrawDib,dc.GetSafeHdc(),10+m_size.cx-i,10,i, m_size.cy,&RGB32BITSBITMAPINFO,(LPVOID)m_clrSrc, 0,0,i,m_size.cy,DDF_BACKGROUNDPAL); i+=10; Sleep(50); } }
举一反三
根据本实例,读者可以:
演示屏幕动画;
开发简单影片放映程序。
实例102 翻转图片效果
这是一个可以提高基础技能的实例
实例位置:光盘\mingrisoft\03\102
实例说明
本实例实现图片的翻转效果,选择“编辑”/“翻转”菜单命令,图片就会翻转90°。图像翻转前如图3.20所示,图像翻转后如图3.21所示。
图3.20 图像翻转前
图3.21 图像翻转后
技术要点
本实例主要应用了DrawDib库进行图像的绘制,有关该库的介绍可参见实例099图片马赛克效果。
实现过程
(1)新建一个基于单文档的应用程序。
(2)在工程中加入对vfw32.lib的引用。
(3)在头文件加入“#include "vfw.h"”。
(4)加入菜单项,设置ID属性为ID_VIEW,Caption属性为“翻转”,通过类向导添加菜单响应函数OnView。
(5)在CRotateViewView类的头文件中声明变量:
class CRotateViewView : public CView { protected: //加入变量声明 HBITMAP m_bmpSrc; COLORREF*m_clrSrc; CSize m_sizeSrc; HBITMAP m_bmpDst; COLORREF *m_clrDst; CSize m_sizeDst; HDRAWDIB m_hDrawDib; int m_nType; BITMAP bm; }
(6)在构造函数中初始化HDRAWDIB对象,代码如下:
CRotateViewView::CRotateViewView() { m_bmpSrc=NULL; m_bmpDst=NULL; m_nType=0; m_hDrawDib=DrawDibOpen(); HBITMAP hBmp=(HBITMAP)LoadImage(NULL,"bitmap.bmp",IMAGE_BITMAP,0,0, LR_LOADFROMFILE); HDC hMemDC=CreateCompatibleDC(NULL); if(hMemDC) { GetObject(hBmp,sizeof(bm),&bm); m_sizeSrc=m_sizeDst=CSize(bm.bmWidth,bm.bmHeight); BITMAPINFOHEADER RGB32BITSBITMAPINFO= {sizeof(BITMAPINFOHEADER),bm.bmWidth,bm.bmHeight,1,32, BI_RGB,0,0,0,0,0}; m_bmpSrc=CreateDIBSection(hMemDC,(BITMAPINFO*)&RGB32BITSBITMAPINFO, DIB_RGB_COLORS,(VOID**)&m_clrSrc,NULL,0); m_bmpDst=CreateDIBSection(hMemDC,(BITMAPINFO*)&RGB32BITSBITMAPINFO, DIB_RGB_COLORS,(VOID**)&m_clrDst,NULL,0); if(m_bmpSrc&&m_bmpDst) { HBITMAP hOldBmp=(HBITMAP)SelectObject(hMemDC,m_bmpSrc); HDC hDC=CreateCompatibleDC(hMemDC); if(hDC) { HBITMAP hOldBmp2=(HBITMAP)SelectObject(hDC,hBmp); BitBlt(hMemDC,0,0,bm.bmWidth,bm.bmHeight,hDC,0,0, SRCCOPY); SelectObject(hMemDC,m_bmpDst); BitBlt(hMemDC,0,0,bm.bmWidth,bm.bmHeight,hDC,0,0, SRCCOPY); SelectObject(hMemDC,hOldBmp2); DeleteObject(hDC); } SelectObject(hMemDC,hOldBmp); } DeleteObject(hMemDC); DeleteObject(hBmp); } }
(7)在析构函数中实现HDRAWDIB对象的关闭和销毁,代码如下:
CRotateViewView::~CRotateViewView() { if(m_hDrawDib!=NULL) { DrawDibClose(m_hDrawDib); m_hDrawDib=NULL; } if(m_bmpDst!=NULL) DeleteObject(m_bmpDst); if(m_bmpSrc!=NULL) DeleteObject(m_bmpSrc); }
(8)在函数OnDraw中绘制图像,代码如下:
void CRotateViewView::OnDraw(CDC* pDC) { CRotateViewDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if(m_hDrawDib!=NULL&&m_bmpSrc!=NULL&&m_bmpDst!=NULL) { BITMAPINFOHEADER RGB32BITSBITMAPINFO= {sizeof(BITMAPINFOHEADER),m_sizeDst.cx,m_sizeDst.cy, 1,32,BI_RGB,0,0,0,0,0}; DrawDibRealize(m_hDrawDib,pDC->GetSafeHdc(),TRUE); DrawDibDraw(m_hDrawDib,pDC->GetSafeHdc(),0,0,m_sizeDst.cx, m_sizeDst.cy,&RGB32BITSBITMAPINFO,(LPVOID)m_clrDst,0,0, m_sizeDst.cx,m_sizeDst.cy,DDF_BACKGROUNDPAL); } }
(9)“查看”/“翻转”菜单的实现函数的代码如下:
void CRotateViewView::OnView() { if(m_nType==1)return; if(m_bmpSrc!=NULL&&m_bmpDst!=NULL) { m_sizeDst.cx=m_sizeSrc.cy; m_sizeDst.cy=m_sizeSrc.cx; LONG x,y; for(y=0;y<m_sizeSrc.cy;y++) { for(x=0;x<m_sizeSrc.cx;x++) { m_clrDst[y+(m_sizeDst.cy-x-1)*m_sizeDst.cx]= m_clrSrc[x+y*m_sizeSrc.cx]; } } m_nType=1; Invalidate(); }}
举一反三
根据本实例,读者可以:
开发图像的合成与处理的相关程序。
实例103 图片浮雕效果
这是一个可以提高基础技能的实例
实例位置:光盘\mingrisoft\03\103
实例说明
在应用软件的启动界面或主界面当中,可以在窗体上绘制艺术图案以增强软件界面的美观性,本实例演示的是将一幅图片绘制成浮雕图案。运行程序,单击“浮雕”按钮,效果如图3.22所示。
图3.22 图片浮雕效果
技术要点
浮雕效果实际上是将图片中每一点像素都进行了处理,首先循环遍历每一点的像素,分别取出像素的R、G、B元素值把这些值减去相邻像素的元素值再加上128,因为这些元素值的取值在0~255 之间,所以计算后超出了255则将元素值赋值为255,小于0则赋值为0。将这3个元素值重新组合赋予原来的像素。这样颜色就有了阶梯感。
实现过程
(1)新建一个基于对话框的应用程序。
(2)在窗体上添加一个图片控件和两个按钮控件。
(3)主要程序代码如下:
void CRelievoDlg::RelievoImage() { CDC*pDC=m_image.GetDC(); //获得设备上下文 CRect m_rect ; m_image.GetClientRect(m_rect); //获得控件的客户区域 COLORREF color1,color2; BYTE r,g,b; for (int i = 0; i<m_rect.right;i++) for (int j = 0;j<m_rect.bottom;j++) { color1=pDC->GetPixel(i,j); //获得每一点的颜色 color2 = pDC->GetPixel(i+1,j+1); r = GetRValue(color1)-GetRValue(color2)+128; g = GetGValue(color1)-GetGValue(color2)+128; b = GetRValue(color1)-GetRValue(color2)+128; //设置浮雕效果 if(r>255) r = 255; else if(r<0) r = 0; if(g>255) g = 255; else if(r<0) g = 0; if(b>255) b = 255; else if(r<0) b = 0; pDC->SetPixel(i,j,RGB(r,g,b)); //设置颜色 } }
举一反三
根据本实例,读者可以:
绘制雕刻效果。