实现图像的特殊效果的显示的基本思路是要么是 *** 作图像的像素,要么是对图像分块按一定的方向或次序,分阶段的显示或擦除对应的图像块。对于第二种显示的思路,其中的要点是:1.划分图像块;2.确定图像块的 *** 作次序;3.显示或清除对应的图像块;4.在两个连续显示的图像块之间插入一个固定的延迟。其中图像块的划分决定了图像的显示方式,图像块的显示顺序决定了显示的方向和细分的依据。不同的效果决定了不同的分块方法和显示次序,我们将在后面的各种特效显示中介绍如何分块和决定次序。为了使图像的显示过程明显的表现出来,实现显示的特效,就需要在图像块的依此显示中插入固定的延迟。也许读者朋友会想到利用sleep()函数或用Settime()来实现延迟,由于Windows是个基于消息的多任务 *** 作系统,这些方法所产生的延迟时间对于图像的显示来说是不精确的,为了实现与机器无关的更精确的时间延迟,可以采用timeGetTime()函数来产生微秒级的延迟。使用这个函数时为了编译不产生错误,要在连接设置中引入Winmm.lib库,并要包含头文件Mmsystem.h。这里我们首先给出一个延迟函数,它用来实现固定时间的延迟:
void DelayTime(DWORD time)
{
DWORD BeginTime ,EndTime
BeginTime=timeGetTime()//得到当前的系统时间、单位为微秒;
do
{
EndTime=timeGetTime()//再次得到当前的系统时间;
}
while((EndTime-BeginTime)
}
一、 *** 作位图的像素实现显示的特效
我们首先介绍直接 *** 作图像中的像素的灰度值来实现图像显示的特效、这里我们主要介绍如何实现图像的浮雕和雕刻效果。经常看电视的朋友们不知注意到没有,有些电视连续剧在每集片头或片尾部分都有显示一些滚圆特殊效果的图像,比如前一阵子中央一套放的《长征》和《康熙王朝》,这些特效称为图像的浮雕效果和图像的雕刻效果,经过这些特效处理后的图像增强了观众们的视觉效果,它们看上去仿佛是使用3D技术作的,这也许就是为什么这种技术那么流行的原因吧。其实,我们完全可以用一些简单的数字图像处理算法来实现这些看似复杂高深的显示效果。下面以一个标准的Lena灰度图像为原图,给出了处理后的效果图,同时给出了VC开发平台上的部分实现源代码。
1.浮雕图像
浮雕图象效果是指图像的前景前向凸出背景。所谓的浮雕概念是指标绘图像上的一个像素和备备清它左上方的那个像素之间差值的一种处理过程,为了使图像保持一定的亮度并呈现灰色,我在处理过程中为这个差值加了一个数值为128的常量。需要读者注意的是,当设置一个像素值的时候,它和它左上方的像素都要被用到,为了避免用到已经设置过的像素,应该从图像的右下方的像素开始处理,下面是实现的源代码:
void CDibView::OnFDImage() //产生浮雕效果图函数
{
HANDLE data1handle//用来存放图像数据的句柄;
LPBITMAPINFOHEADER lpBi//图像的信息头结构;
CDibDoc *pDoc=GetDocument()//得到文挡指针;
HDIB hdib//用来存放图像数据的句柄;
unsigned char *pData//指向原始图像数据的指针;
unsigned char *data//指向处理后图像数据的指针;
hdib=pDoc->m_hDIB//拷贝存放已经读取的图像文件数据句仿前柄;
lpBi=(LPBITMAPINFOHEADER)GlobalLock((HGLOBAL)hdib)//获取图像信息头
pData=(unsigned char*)FindDIBBits((LPSTR)lpBi)
//FindDIBBits是我定义的一个函数、根据图像的结构得到位图的灰度值数据、
pDoc->SetModifiedFlag(TRUE)
//设置文档修改标志为真、为后续的修改存盘作准备;
data1handle=GlobalAlloc(GMEM_SHARE,WIDTHBYTES(lpBi->biWidth*8)*lpBi->biHeight) //声明一个缓冲区用来暂存处理后的图像数据;
data=(unsigned char*)GlobalLock((HGLOBAL)data1handle)//得到该缓冲区的指针;
AfxGetApp()->BeginWaitCursor()
int i,j,buf
for( i=lpBi->biHeighti>=2i )//从图像右下角开始对图像的各个像素进行浮雕处理;
for( j=lpBi->biWidthj>=2j )
{
//浮雕处理
buf=*(pData+(lpBi->biHeight-i)*WIDTHBYTES(lpBi->biWidth*8)+j)-*(pData+(lpBi->biHeight-i+1)*WIDTHBYTES(lpBi->biWidth*8)+j-1)+128
if(buf>255) buf=255
if(buf<0)buf=0*(data+(lpBi->biHeight-i)*WIDTHBYTES(lpBi->biWidth*8)+j)=(BYTE)buf
}
for( j=0jbiHeightj++)
for( i=0ibiWidthi++)
//重新写回原始图像的数据缓冲区
*(pData+i*WIDTHBYTES(lpBi->biWidth*8)+j)=*(data+i*WIDTHBYTES(lpBi->biWidth*8)+j)AfxGetApp()->EndWaitCursor()
pDoc->m_hDIB =hdib//将处理过的图像数据写回pDoc中的图像缓冲区;
GlobalUnlock((HGLOBAL)hdib)//解锁、释放缓冲区;
GlobalUnlock((HGLOBAL)data1handle)
GlobalFree((HGLOBAL)hdib)
GlobalFree((HGLOBAL)data1handle)
Invalidate(TRUE)//显示图像
}
2.雕刻图像
上面讲述了通过求一个像素和它左上方像素之间的差值并加上一个常数的方法生成浮雕效果的灰度图像,雕刻图像与之相反,它是通过取一个像素和它右下方的像素之间的差值并加上一个常数,这里我也取128,经过这样处理,就可以得到雕刻图像,这时候图像的前景凹陷进背景之中。同样需要读者注意的是为了避免重复使用处理过的图像像素,处理图像时要从图像的左上方的像素开始处理。实现代码如下:
void CDibView::OnDKImage()
{
// TOD Add your command handler code here
HANDLE data1handle//这里的内部变量与前面的含义一致、这里不再赘述;
LPBITMAPINFOHEADER lpBi
CDibDoc *pDoc=GetDocument()
HDIB hdib
unsigned char *pData
unsigned char *data
hdib=pDoc->m_hDIB//拷贝图像数据的句柄;
lpBi=(LPBITMAPINFOHEADER)GlobalLock((HGLOBAL)hdib)
pData=(unsigned char*)FindDIBBits((LPSTR)lpBi)
pDoc->SetModifiedFlag(TRUE)
data1handle=GlobalAlloc(GMEM_SHARE,WIDTHBYTES(lpBi->biWidth*8)*lpBi->biHeight)//申请缓冲区;
data=(unsigned char*)GlobalLock((HGLOBAL)data1handle)//得到新的缓冲去的指针; AfxGetApp()->BeginWaitCursor()
int i,j,buf;
for( i=0i<=lpBi->biHeight-2i++)//对图像的各个像素循环进行雕刻处理;
for( j=0j<=lpBi->biWidth-2j++)
{
buf=*(pData+(lpBi->biHeight-i)*WIDTHBYTES(lpBi->biWidth*8)+ j)-*(pData+(lpBi->biHeight-i-1)*WIDTHBYTES(lpBi->biWidth*8)+j+1)+128//雕刻处理;
if(buf>255) buf=255
if(buf<0)buf=0
*(data+(lpBi->biHeight-i)*WIDTHBYTES(lpBi->biWidth*8)+j)=(BYTE)buf
}
for( j=0jbiHeightj++)
for( i=0ibiWidthi++)//重新将处理后的图像数据写入原始的图像缓冲区内;*(pData+i*WIDTHBYTES(lpBi->biWidth*8)+j)=*(data+i*WIDTHBYTES(lpBi->biWidth*8)+j)
pDoc->m_hDIB =hdib//将处理过的图像数据写回pDoc中的图像缓冲区;
GlobalUnlock((HGLOBAL)hdib)//解锁、释放缓冲区;
GlobalUnlock((HGLOBAL)data1handle)
GlobalFree((HGLOBAL)hdib)
GlobalFree((HGLOBAL)data1handle)
Invalidate(TRUE)//显示图像
}
3.图像的旋转
根据图像像素的位置来调节该位置的灰度可以实现许多显示的特效,例如图像的镜像、翻转等。灰度图像旋转就是根据这一个思想实现的,它是指把定义的图像绕某一点以逆时针或顺时针方向旋转一定的角度,通常是指绕图像的中心以逆时针方向旋转。首先根据旋转的角度、图像对角线的长度计算旋转后的图像的最大宽度、高度,根据旋转后图象最大的宽度、高度生成新的缓冲区,假设图像的左上角为(left, top),右下角为(right, bottom),则图像上任意点(x, y)绕其中心(xcenter, ycenter)逆时针旋转angle角度后,新的坐标位置(x1, y1)的计算公式为:
xcenter = (width+1)/2+left
ycenter = (height+1)/2+top
x1 = (x-xcenter) cosθ - (y - ycenter) sinθ+xcenter
y1 = (x-xcenter) sinθ+ (y- ycenter) cosθ+ ycenter
与图像的镜像变换相类似,下一步就是把原图中的(x,y)处象素的灰度值读入新缓冲区的(x1,y1)点处。注意在新缓冲区中与原图没有对应的象素点的值用白色或指定的灰度代替。
二、图像的分块显示和清除
1. 图像的扫描显示和清除
扫描显示图像是最基本的特效显示方法,它表现为图像一行行(或一列列)地显示出来或从屏幕上清除掉,有种大戏院种的拉幕效果。根据扫描的方向的不同,可以分为上、下、左、右、水平平分和垂直平分等六种扫描。这里以向下移动为例,分别介绍显示和清除的实现。其余的扫描效果可以依次类推。向下扫描显示的实现方法是:从图像的底部开始将图像一行一行的复制到目标区域的顶部。每复制一行后,复制的行数便要增加一行,并加上一些延迟;向下移动清除的实现方法是图像向下移动显示,并在显示区域的上部画不断增高的矩形。
1)扫描显示的代码:
CdibView::OnImageDownScan()
{
CDibDoc *pDoc=GetDocument()
HDIB hdib
CClientDC pDC(this)
hdib=pDoc->m_hDIB//获取图像数据句柄;
BITMAPINFOHEADER *lpDIBHdr//位图信息头结构指针;
BYTE *lpDIBBits//指向位图像素灰度值的指针;
HDC hDC=pDC.GetSafeHdc()//获取当前设备上下文的句柄;
lpDIBHdr=( BITMAPINFOHEADER *)GlobalLock(hdib)//得到图像的位图头信息;
lpDIBBits=(BYTE*)lpDIBHdr+sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD)//获取指向图像像素值;
SetStretchBltMode(hDC,COLORONCOLOR)
//显示图像;
for(int i=0ibiHeighti++)
{ //每次循环显示图象的0到i行数据;
SetDIBitsToDevice (hDC,0,0,lpDIBHdr->biWidth, lpDIBHdr->biHeight,
0, 0,0, i,
lpDIBBits,(LPBITMAPINFO)lpDIBHdr,
DIB_RGB_COLORS
)
DelayTime(50)//延迟;
}
GlobalUnlock(hdib)
return
}
2)清除代码:
.......................................//由于篇幅的限制,省略了与上面的相同代码
Cbrush brush(crWhite)//定义一个白色的刷子;
Cbrush *oldbrush=pDC->SelectObject(&brush)
for(int i=0i <lpDIBHdr->biHeight i++)
{//每次循环将目标区域中的0到i行刷成白色;
pDC->Rectangle(0,0,lpDIBHdr->biWidth,lpDIBHdr->biHeight)
DelayTime(50)
}
.......................................
2. 百页窗效果
所谓百页窗显示效果,就如同关闭和开启百页窗一样,图像被分为一条条或一列列地分别显示或清除掉,根据显示时以行或列为单位可以将该效果分为垂直或水平两种方式。以垂直百页窗为例来说明如何实现这种特效显示。实现垂直百页窗显示时,需要将图像垂直等分为n部分由上向下扫描显示,其中每一部分包括m个条、这个n可以根据具体应用时的需要来决定、m既为图像的高度除n。扫描显示时,依照差值进行扫描显示,即第k次显示k-1、k*m-1、...k*n -1条扫描线。同样,垂直百页窗清除的实现与垂直百页窗的显示相似,不同的是将绘制位图换成画矩形而已。在下面的例子中,我将图像的分成8份。
.......................................
int m=8
int n=lpDIBHdr->biHeight/m//图像的高度能够整除8;
for(int l=1l<=ml++)
for(int k=0k
{ //每次循环依次显示图像中的k-1、k*m-1、...k*n-1行;
StretchDIBits (hDC,0,4*k+l-1,lpDIBHdr->biWidth,1,
0, lpDIBHdr->biHeight-4*k-l+1,lpDIBHdr->biWidth,1,
lpDIBBits,(LPBITMAPINFO)lpDIBHdr,
DIB_RGB_COLORS,
SRCCOPY)//juanlianxiaoguo
DelayTime(50)
}
.......................................
3.栅条显示特效
栅条特效是移动特效的复杂组合,可以分为垂直栅条和水平栅条两类。它的基本思想是将图像分为垂直或水平的的小条,奇数条向上或向左显示/清除,偶数条向下或向右显示/清除。当然也可以规定进行相反的方向显示/清除。下面的代码是实现垂直栅条的例子:
.......................................
int m=8
for(int i=0i<=lpDIBHdr->biHeighti++)
for(int j=0j<=lpDIBHdr->biWidthj+=m)
{//向下显示偶数条;
StretchDIBits (hDC,j,0,m,i,j,lpDIBHdr->biHeight-i,
m,i,
lpDIBBits,(LPBITMAPINFO)lpDIBHdr,
DIB_RGB_COLORS,
SRCCOPY)//juanlianxiaoguo
j=j+m
//向上显示奇数条;
StretchDIBits (hDC,j,lpDIBHdr->biHeight-i,m,i,j,0,
m,i,
lpDIBBits,(LPBITMAPINFO)lpDIBHdr,
DIB_RGB_COLORS,
SRCCOPY)//
DelayTime(20)
}.......................................
4.马赛克效果
马赛克显示是指图像被分成许多的小块,它们以随机的次序显示出来,直到图像显示完毕。实现马赛克的效果主要解决的问题是如何定义显示随机序列的小方块,这个问题的解决可以在定义过小方块的基础上,用一个数组来记录各个方块的左上角的坐标的位置。显示图像过程中,产生一个随机数来挑选即将显示的小方块,显示后将该方块的位置坐标从数组中剔除。清除过程与之相仿。剔除显示过的方块的位置坐标的方法是将该数组中的最后的一个点的坐标拷贝到当前位置,然后删除数组中的最后点的坐标,经过实现发现这样处理有时显示的图像是不完整的,分析其原因是生成随机数的过程有舍入溢出误差。读者可以采用其它的办法解决这个问题,例如可以生成固定的随机数组或采用一个动态的数组来跟踪未显示的图像方块的坐标等方法。
.......................................
int m,n
int RectSize=60//方块的宽、高尺寸为60个像素;
if(lpDIBHdr->biWidth%RectSize!=0)//得到图像水平方块的个数;
m= lpDIBHdr->biWidth/RectSize+1
else
m= lpDIBHdr->biWidth/RectSize
if(lpDIBHdr->biHeight%RectSize!=0)//得到图像垂直方块的个数;
n= lpDIBHdr->biHeight/RectSize+1
else
n=lpDIBHdr->biHeight/RectSize
POINT *point=new POINT[n*m]//申请一个数组用来记录各个方块的左上角的坐标;
POINT point1
for(int a=0a
for(int b=0b
{
point1.x=a*RectSize
point1.y=b*RectSize
*(point+a*b+b)=point1
}
//开始随机的显示各个小方块;
double fMax=RAND_MAX//定义Rand()函数的最大值;
for(int k=m*n-1k>=0k )
{
int c=(int)((double)(m*n)*rand()/fMax)
int mx=point[c].x
int my=point[c].y
//显示对应的图像的小块;
StretchDIBits (hDC,mx,my,RectSize,RectSize,
mx,lpDIBHdr->biHeight-my,RectSize,RectSize,
lpDIBBits,(LPBITMAPINFO)lpDIBHdr,
DIB_RGB_COLORS,
SRCCOPY)
point[c].x=point[k].x
point[c].y=point[k].y
DelayTime(50)
}
.......................................
打开VC程序——文件——新建——工程中的MFC AppWizard(exe),在工程下面的框中输入工程名(假定工程名为111),点确定——选多重文档,点下一个——后面都点下一个直到完成确定,基本框架就完成了,下面就加代码。这时VC界面上左边框的下面有三个按钮:ClassView、ResourceView和FileView,ClassView里面是工程111的类:CAdoutDlg、CChildFrame、CMy111App、CMy111Doc、CMy111View和Globals;点ResourceView里面是资源类:Accelerator、Dialog、Icon、Menu、String Table、Toolbar和Version;点开FileView里面是文件类:Source File、Header Files、Resource Files和ReadMe.txt。
点界面的“工程”按钮——添加工程——新建——选C++ Source File,在文件下面的框里输入文件名(如DIBAPI),点“结束”,这样在FileView中的Source Files里面就多了一个DIBAPI.cpp文件,所有的代码都加在该文件中。再点界面的首念喊“工程”按高闷钮——添加工程——新建——选C/C++ Header File,在文件下面的框里输入文件名(和前面的文件名必须一致),点“结束”,这样在FileView中的Header Files里面就多了一个DIBAPI.h文件,该文件是DIBAPI.cpp的头文件。
点开DIBAPI.h文件,里面是空白的,把如下代码考入文件中:
//DIBAPI.h
#ifndef _INC_DIBAPI
#define _INC_DIBAPI
DECLARE_HANDLE(HDIB)
#define PALVERSION 0x300
#define IS_WIN30_DIB(lpbi) ((*(LPDWORD)(lpbi))==sizeof(BITMAPINFOHEADER))
#define RECTWIDTH(lpRect) ((lpRect)->right-(lpRect)->left)
#define RECTHEIGHT(lpRect) ((lpRect)->bottom-(lpRect)->top)
#define WIDTHBYTES(bits) (((bits)+31)/32*4)
#define DIB_HEADER_MARKER ((WORD)('M'<<8)|'B')
BOOL WINAPI PaintDIB(HDC,LPRECT,HDIB,LPRECT,CPalette* pPal)
BOOL WINAPI CreateDIBPalette(HDIB hDIB,CPalette* cPal)
LPSTR WINAPI FindDIBBits(LPSTR lpbi)
DWORD WINAPI DIBWidth(LPSTR lpDIB)
DWORD WINAPI DIBHeight(LPSTR lpDIB)
WORD WINAPI PaletteSize(LPSTR lpbi)
WORD WINAPI DIBNumColors(LPSTR lpbi)
HGLOBAL WINAPI CopyHandle(HGLOBAL h)
BOOL WINAPI SaveDIB(HDIB hDib,CFile&file)
HDIB WINAPI ReadDIBFile(CFile&file)
//在此处输入自己的函数声明
#endif//!_INC_DIBAPI
上面这些函数是实现图像的读取、存储等图像处理的基本功能的,你将自己需要的函数也输入者野到“//在此处输入自己的函数声明”的下面。
点开DIBAPI.cpp文件,里面是空白的,将如下代码加入其中:
//DIBAPI.cpp
#include "stdafx.h"
#include "DIBAPI.h"
WORD WINAPI DIBNumColors(LPSTR lpbi)
{
WORD wBitCount
if(IS_WIN30_DIB(lpbi))
{
DWORD dwClrUsed
dwClrUsed=((LPBITMAPINFOHEADER)lpbi)->biClrUsed
if(dwClrUsed)
return (WORD)dwClrUsed
}
if(IS_WIN30_DIB(lpbi))
wBitCount=((LPBITMAPINFOHEADER)lpbi)->biBitCount
else
wBitCount=((LPBITMAPCOREHEADER)lpbi)->bcBitCount
switch(wBitCount)
{
case 1:
return 2
case 4:
return 16
case 8:
return 256
default:
return 0
}
}
WORD WINAPI PaletteSize(LPSTR lpbi)
{
if(IS_WIN30_DIB(lpbi))
return (WORD)(DIBNumColors(lpbi)*sizeof(RGBQUAD))
else
return (WORD)(DIBNumColors(lpbi)*sizeof(RGBTRIPLE))
}
LPSTR WINAPI FindDIBBits(LPSTR lpbi)
{
return (lpbi+*(LPDWORD)lpbi+::PaletteSize(lpbi))
}
DWORD WINAPI DIBWidth(LPSTR lpDIB)
{
LPBITMAPINFOHEADER lpbmi
LPBITMAPCOREHEADER lpbmc
lpbmi=(LPBITMAPINFOHEADER)lpDIB
lpbmc=(LPBITMAPCOREHEADER)lpDIB
if(IS_WIN30_DIB(lpDIB))
return lpbmi->biWidth
else
return (DWORD)lpbmc->bcWidth
}
DWORD WINAPI DIBHeight(LPSTR lpDIB)
{
LPBITMAPINFOHEADER lpbmi
LPBITMAPCOREHEADER lpbmc
lpbmi=(LPBITMAPINFOHEADER)lpDIB
lpbmc=(LPBITMAPCOREHEADER)lpDIB
if(IS_WIN30_DIB(lpDIB))
return lpbmi->biHeight
else
return (DWORD)lpbmc->bcHeight
}
BOOL WINAPI PaintDIB(HDC hDC,LPRECT lpDCRect,HDIB hDIB,LPRECT lpDIBRect,CPalette* pPal)
{
LPSTR lpDIBHdr
LPSTR lpDIBBits
BOOL bSuccess=FALSE
HPALETTE hPal=NULL
HPALETTE hOldPal=NULL
if(hDIB==NULL)
return FALSE
lpDIBHdr=(LPSTR)::GlobalLock((HGLOBAL)hDIB)
lpDIBBits=FindDIBBits(lpDIBHdr)
if(pPal!=NULL)
{
hPal=(HPALETTE)pPal->m_hObject
hOldPal=::SelectPalette(hDC,hPal,TRUE)
}
::SetStretchBltMode(hDC,COLORONCOLOR)
if((RECTWIDTH(lpDCRect)==RECTWIDTH(lpDIBRect))&&(RECTHEIGHT(lpDCRect)==RECTHEIGHT(lpDIBRect)))
{
bSuccess=::SetDIBitsToDevice(hDC,lpDCRect->left,lpDCRect->top,RECTWIDTH(lpDCRect),RECTHEIGHT(lpDCRect),lpDIBRect->left,\
(int)DIBHeight(lpDIBHdr)-lpDIBRect->top-RECTHEIGHT(lpDIBRect),0,(WORD)DIBHeight(lpDIBHdr),\
lpDIBBits,(LPBITMAPINFO)lpDIBHdr,DIB_RGB_COLORS)
}
else
{
bSuccess=::StretchDIBits(hDC,lpDCRect->left,lpDCRect->top,RECTWIDTH(lpDCRect),RECTHEIGHT(lpDCRect),lpDIBRect->left,\
lpDIBRect->top,RECTWIDTH(lpDIBRect),RECTHEIGHT(lpDIBRect),\
lpDIBBits,(LPBITMAPINFO)lpDIBHdr,DIB_RGB_COLORS,SRCCOPY)
}
::GlobalUnlock((HGLOBAL)hDIB)
if(hOldPal)
::SelectPalette(hDC,hOldPal,TRUE)
GlobalUnlock(hDIB)
return bSuccess
}
BOOL WINAPI CreateDIBPalette(HDIB hDIB,CPalette* pPal)
{
LPLOGPALETTE lpPal
HANDLE hLogPal
HPALETTE hPal=NULL
LPSTR lpbi
LPBITMAPINFO lpbmi
LPBITMAPCOREINFO lpbmc
BOOL bWinStyleDIB
int i
WORD wNumColors
BOOL bResult=FALSE
if(hDIB==NULL)
return FALSE
lpbi=(LPSTR)::GlobalLock((HGLOBAL)hDIB)
lpbmi=(LPBITMAPINFO)lpbi
lpbmc=(LPBITMAPCOREINFO)lpbi
wNumColors=DIBNumColors(lpbi)
bWinStyleDIB=IS_WIN30_DIB(lpbi)
if(wNumColors!=0)
{
hLogPal=::GlobalAlloc(GHND,sizeof(LOGPALETTE)+sizeof(PALETTEENTRY)*wNumColors)
if(hLogPal==0)
{
::GlobalUnlock((HGLOBAL)hDIB)
return FALSE
}
lpPal=(LPLOGPALETTE)::GlobalLock(hLogPal)
lpPal->palVersion=PALVERSION
lpPal->palNumEntries=(WORD)wNumColors
bWinStyleDIB=IS_WIN30_DIB(lpbi)
for(i=0i<(int)wNumColorsi++)
{
if(bWinStyleDIB)
{
lpPal->palPalEntry[i].peRed=lpbmi->bmiColors[i].rgbRed
lpPal->palPalEntry[i].peGreen=lpbmi->bmiColors[i].rgbGreen
lpPal->palPalEntry[i].peBlue=lpbmi->bmiColors[i].rgbBlue
lpPal->palPalEntry[i].peFlags=0
}
else
{
lpPal->palPalEntry[i].peRed=lpbmc->bmciColors[i].rgbtRed
lpPal->palPalEntry[i].peGreen=lpbmc->bmciColors[i].rgbtGreen
lpPal->palPalEntry[i].peBlue=lpbmc->bmciColors[i].rgbtBlue
lpPal->palPalEntry[i].peFlags=0
}
}
bResult=pPal->CreatePalette(lpPal)
::GlobalUnlock((HGLOBAL)hLogPal)
::GlobalFree((HGLOBAL)hLogPal)
}
::GlobalUnlock((HGLOBAL)hDIB)
return bResult
}
HGLOBAL WINAPI CopyHandle(HGLOBAL h)
{
if(h==NULL)
return NULL
DWORD dwLen=::GlobalSize((HGLOBAL)h)
HGLOBAL hCopy=::GlobalAlloc(GHND,dwLen)
if(hCopy!=NULL)
{
void* lpCopy=::GlobalLock((HGLOBAL)hCopy)
void* lp=::GlobalLock((HGLOBAL)h)
memcpy(lpCopy,lp,dwLen)
::GlobalUnlock(hCopy)
::GlobalUnlock(h)
}
return hCopy
}
BOOL WINAPI SaveDIB(HDIB hDib,CFile&file)
{
BITMAPFILEHEADER bmfHdr
LPBITMAPINFOHEADER lpBI
DWORD dwDIBSize
if(!hDib)
return FALSE
lpBI=(LPBITMAPINFOHEADER)::GlobalLock((HGLOBAL)hDib)
if(lpBI==NULL)
return FALSE
if(!IS_WIN30_DIB(lpBI))
{
::GlobalUnlock((HGLOBAL)hDib)
return FALSE
}
bmfHdr.bfType=DIB_HEADER_MARKER
dwDIBSize=*(LPDWORD)lpBI+::PaletteSize((LPSTR)lpBI)
if((lpBI->biCompression==BI_RLE8)||(lpBI->biCompression==BI_RLE4))
dwDIBSize+=lpBI->biSizeImage
else
{
DWORD dwBmBitsSize
dwBmBitsSize=WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount))*lpBI->biHeight
dwDIBSize+=dwBmBitsSize
lpBI->biSizeImage=dwBmBitsSize
}
bmfHdr.bfSize=dwDIBSize+sizeof(BITMAPFILEHEADER)
bmfHdr.bfReserved1=0
bmfHdr.bfReserved2=0
bmfHdr.bfOffBits=(DWORD)sizeof(BITMAPFILEHEADER)+lpBI->biSize+::PaletteSize((LPSTR)lpBI)
TRY
{
file.Write((LPSTR)&bmfHdr,sizeof(BITMAPFILEHEADER))
file.WriteHuge(lpBI,dwDIBSize)
}
CATCH(CFileException,e)
{
::GlobalUnlock((HGLOBAL)hDib)
THROW_LAST()
}
END_CATCH
::GlobalUnlock((HGLOBAL)hDib)
return TRUE
}
HDIB WINAPI ReadDIBFile(CFile&file)
{
BITMAPFILEHEADER bmfHeader
DWORD dwBitsSize
HDIB hDIB
LPSTR pDIB
dwBitsSize=file.GetLength()
if(file.Read((LPSTR)&bmfHeader,sizeof(bmfHeader))!=sizeof(bmfHeader))
return NULL
if(bmfHeader.bfType!=DIB_HEADER_MARKER)
return NULL
hDIB=(HDIB)::GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,dwBitsSize)
if(hDIB==0)
return NULL
pDIB=(LPSTR)::GlobalLock((HGLOBAL)hDIB)
if(file.ReadHuge(pDIB,dwBitsSize-sizeof(BITMAPFILEHEADER))!=dwBitsSize-sizeof(BITMAPFILEHEADER))
{
::GlobalUnlock((HGLOBAL)hDIB)
::GlobalFree((HGLOBAL)hDIB)
return NULL
}
::GlobalUnlock((HGLOBAL)hDIB)
return hDIB
}
//在此处输入自己的函数定义
上面是DIBAPI.h头文件中声明的函数的定义,你将自己的函数定义加到“//在此处输入自己的函数定义”后面。
下面加相应的消息映射函数,点Ctrl+W键,会出现MFC ClassWizard对话框,点Message Maps,在Class name下面的框中选择CMy111Doc,在Messages里面选中OnOpenDocument,然后点击Add Function按钮就加入了相应的消息映射函数,同样的方法以此加入OnSaveDocument、DeleteContents、CanCloseFrame相应的消息函数,点“确定”即可。
点开111Doc.cpp文件,里面有相应的消息映射函数定义位置,在函数CMy111Doc::CMy111Doc()里输入以下代码:
m_refColorBKG=0x00808080
m_hDIB=NULL
m_palDIB=NULL
m_sizeDoc=CSize(1,1)
在函数CMy111Doc::~CMy111Doc()里输入以下代码:
if(m_hDIB!=NULL)
::GlobalFree((HGLOBAL)m_hDIB)
if(m_palDIB!=NULL)
delete m_palDIB
在函数BOOL CMy111Doc::OnOpenDocument(LPCTSTR lpszPathName)里/ TODO: Add your specialized creation code here下面添加如下代码:
CFile file
CFileException fe
if(!file.Open(lpszPathName,CFile::modeRead|CFile::shareDenyWrite,&fe))
{
ReportSaveLoadException(lpszPathName,&fe,FALSE,AFX_IDP_FAILED_TO_OPEN_DOC)
return FALSE
}
DeleteContents()
BeginWaitCursor()
TRY
{
m_hDIB=::ReadDIBFile(file)
}
CATCH(CFileException,eLoad)
{
file.Abort()
EndWaitCursor()
ReportSaveLoadException(lpszPathName,eLoad,FALSE,AFX_IDP_FAILED_TO_OPEN_DOC)
m_hDIB=NULL
return FALSE
}
END_CATCH
InitDIBData()
EndWaitCursor()
if(m_hDIB==NULL)
{
CString strMsg
strMsg="读取图像时出错!可能是不支持该类型的图像文件!"
MessageBox(NULL,strMsg,NULL,MB_ICONINFORMATION|MB_OK)
return FALSE
}
SetPathName(lpszPathName)
SetModifiedFlag(FALSE)
在函数BOOL CMy111Doc::OnSaveDocument(LPCTSTR lpszPathName)里// TODO: Add your specialized code here and/or call the base class后面添加如下代码:
CFile file
CFileException fe
if(!file.Open(lpszPathName,CFile::modeCreate|CFile::modeReadWrite|CFile::shareExclusive,&fe))
{
ReportSaveLoadException(lpszPathName,&fe,TRUE,AFX_IDP_INVALID_FILENAME)
return FALSE
}
BOOL bSuccess=FALSE
TRY
{
BeginWaitCursor()
bSuccess=::SaveDIB(m_hDIB,file)
file.Close()
}
CATCH(CException,eSave)
{
file.Abort()
EndWaitCursor()
ReportSaveLoadException(lpszPathName,eSave,TRUE,AFX_IDP_FAILED_TO_SAVE_DOC)
return FALSE
}
END_CATCH
EndWaitCursor()
SetModifiedFlag(FALSE)
if(!bSuccess)
{
CString strMsg
strMsg="无法保存BMP图像"
MessageBox(NULL,strMsg,NULL,MB_ICONINFORMATION|MB_OK)
}
点开ClassView,右键点击CMy111Doc类,点Add Member Variable出现添加成员变量对话框,在Variable Type下的框中输入变量类型名HDIB,在Variable Name中输入变量名m_hDIB,在Access中选中Public就在CMy111Doc中加入了公共成员变量m_hDIB;同样加入int类型的m_nColorIndex、COLORREF类型的m_refColorBKG公共成员变量,再添加保护成员变量(在Access中选中Protected)CSize类的m_sizeDoc、CPalette*类的m_palDIB变量。右键点击CMy111Doc类,点Add Member Function出现添加成员函数对话框,在Function Type下的框中输入函数类型名void,在Function Declaration中输入函数名InitDIBData(),在Access中选中Public就在CMy111Doc中加入了公共成员函数InitDIBData();同样方法加入void类型的公共成员函数ReplaceHDIB(HDIB hDIB)。在111Doc.cpp中加入函数的代码,InitDIBData()里加如下代码:
if(m_palDIB!=NULL)
{
delete m_palDIB
m_palDIB=NULL
}
if(m_hDIB==NULL)
return
LPSTR lpDIB=(LPSTR)::GlobalLock((HGLOBAL)m_hDIB)
if(::DIBWidth(lpDIB)>INT_MAX||::DIBHeight(lpDIB)>INT_MAX)
{
::GlobalUnlock((HGLOBAL)m_hDIB)
::GlobalFree((HGLOBAL)m_hDIB)
m_hDIB=NULL
CString strMsg
strMsg="BMP图像太大!"
MessageBox(NULL,strMsg,NULL,MB_ICONINFORMATION|MB_OK)
return
}
m_sizeDoc=CSize((int)::DIBWidth(lpDIB),(int)::DIBHeight(lpDIB))
::GlobalUnlock((HGLOBAL)m_hDIB)
m_palDIB=new CPalette
if(m_palDIB==NULL)
{
::GlobalFree((HGLOBAL)m_hDIB)
m_hDIB=NULL
return
}
if(::CreateDIBPalette(m_hDIB,m_palDIB)==NULL)
{
delete m_palDIB
m_palDIB=NULL
return
}
在函数ReplaceHDIB(HDIB hDIB)中加入如下代码:
if(m_hDIB!=NULL)
::GlobalFree((HGLOBAL)m_hDIB)
m_hDIB=hDIB
在CMy111doc.h的
// Attributes
public:
下面加入如下代码:
HDIB GetHDIB() const
{
return m_hDIB
}
CPalette* GetDocPalette() const
{
return m_palDIB
}
CSize GetDocSize() const
{
return m_sizeDoc
}
注意要在111Doc.h前加上#include "DIBAPI.h"语句(在class CMy111Doc:public CDocument语句前)
下面为CMy111View中的函数 void CMy111View::OnDraw(CDC* pDC)中添加如下代码:
BeginWaitCursor()
CMy111* pDoc = GetDocument()
ASSERT_VALID(pDoc)
// TODO: add draw code for native data here
HDIB hDIB=pDoc->GetHDIB()
if(hDIB!=NULL)
{
LPSTR lpDIB=(LPSTR)::GlobalLock((HGLOBAL)hDIB)
int cxDIB=(int)::DIBWidth(lpDIB)
int cyDIB=(int)::DIBHeight(lpDIB)
::GlobalUnlock((HGLOBAL)hDIB)
CRect rcDIB
rcDIB.top=rcDIB.left=0
rcDIB.right=cxDIB
rcDIB.bottom=cyDIB
CRect rcDest
if(pDC->IsPrinting())
{
int cxPage=pDC->GetDeviceCaps(HORZRES)
int cyPage=pDC->GetDeviceCaps(VERTRES)
int cxInch=pDC->GetDeviceCaps(LOGPIXELSX)
int cyInch=pDC->GetDeviceCaps(LOGPIXELSY)
rcDest.top=rcDest.left=0
rcDest.bottom=(int)(((double)cyDIB*cxPage*cyInch)/((double)cxDIB*cxInch))
rcDest.right=cxPage
int temp=cyPage-(rcDest.bottom-rcDest.top)
rcDest.bottom+=temp/2
rcDest.top+=temp/2
}
else
{
rcDest=rcDIB
}
::PaintDIB(pDC->m_hDC,&rcDest,pDoc->GetHDIB(),&rcDIB,pDoc->GetDocPalette())
}
EndWaitCursor()
以上是关于图像打开、显示、保存的有关步骤和代码。
在111.cpp文件的InitInstance()函数的ParseCommandLine(cmdInfo)语句下输入语句
cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing
则启动时不自动打开一个空文档。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)