学习VC++编制的BMP图像文件的特效显示程序.。
一、 主要内容:
1. 面向对象的 DIB 的读写及访问,ImgCenterDib类;
2. 特效显示类,SpecialEffectShow类;
3. 图像的扫描显示;
4. 图像的滑动显示;
5. 图像的渐进显示;
6. 图像的马赛克显示;
7. 垂直对接;VerticalButt
8. 压缩反转;CompressInvert
9. 中心闭幕;CenterFallCurtain
10. 中心放大;CenterEnlarge
11. 交叉竖条;CrossBars
12. 水平拉幕;PullCurtain
13. 随机拉丝;RandomDraw
14. 对角闭幕;DiagonalClose
15. 垂直百叶;VerticalBlinds
16. 三色对接;ColorDocking
二、 设计实现:
1. 面向对象的 DIB 的读写及访问,ImgCenterDib类;
面向对象的方式实现图像的可视化编程,声明的类叫 ImgCenterDib;里面封装了 DIB 位图处理所需要的基本的成员变量和成员函数。
1).ImgCenterDib 类的定义
ImgCenterDib 类的定义在头文件“ImageCenterDib.h”中。
class ImgCenterDib
{
public:
//图像数据指针
unsigned char * m_pImgData
//图像颜色表指针
LPRGBQUAD m_lpColorTable;
//每像素占的位数
int m_nBitCount;
private:
//指向 DIB 的指针(包含 BITMAPFILEHEADER、BITMAPINFOHEADER 和颜色表)
LPBYTE m_lpDib;
//图像信息头指针
LPBITMAPINFOHEADER m_lpBmpInfoHead;
//调色板句柄
HPALETTE m_hPalette;
//颜色表长度
int m_nColorTableLength;
public:
//不带参数的构造函数
ImgCenterDib();
//带参数的构造函数
ImgCenterDib(CSize size, intnBitCount, LPRGBQUAD lpColorTable,
unsigned char *pImgData);
//析构函数
~ImgCenterDib();
//DIB 读函数
BOOL Read(LPCTSTRlpszPathName);
//DIB 写函数
BOOL Write(LPCTSTRlpszPathName);
//DIB 显示函数
BOOL Draw(CDC* pDC, CPointorigin, CSize size);
//逻辑调色板生成函数
void MakePalette();
//获取 DIB 的尺寸(宽、高)
CSize GetDimensions();
//清理空间
void Empty();
//用新的数据替换当前DIB
void ReplaceDib(CSize size,int nBitCount, LPRGBQUAD lpColorTable, unsigned char *pImgData);
//计算颜色表的长度
intComputeColorTabalLength(int nBitCount);
protected:
//图像的宽,像素为单位
int m_imgWidth;
//图像的高,像素为单位
int m_imgHeight;
};
2. 特效显示类,SpecialEffectShow类;
图像的特效显示就是利用人眼的视觉特性,通过先对图像分块,然后以不同的次序显示出来。其中的要点是:如何划分图像块;确定图像块的操作次序,以及两个图像块的操作之间的延时。
SpecialEffectShow 类继承了 ImgCenterDib 类。
3. 图像的扫描显示;
扫描是最基本的特效显示方式,它没有划分图像块,只是顺序地一行一行或一列一列地显示图像。
单重循环,最基本的。
4. 图像的滑动显示;
滑动是将图像看做一个整体,显示时不能像扫描那样,扫描方式有些像打开一幅画,例如显示上部分的时候,下部分可以不显示。而移动则可以看成一块木板画,显示时候必须按照物理顺序进行,例如从上向下平移时,必须先显示下面的图像,后显示上面的图像。因此平移的算法比扫描要难一些,平移是以复制的方法显示图像的,每次显示一次,复制的行数就增加一行,直至显示完成。
双重循环,最基本的。
5. 图像的渐进显示;
图像渐进显示的思路是先记录下图像的每个像素点的灰度值,显示的时候先将屏幕置黑,将循环显示图像n 次,这里设 n 为 0,1,2,…,256。每一次显示像素灰度值的 n/256 倍,图像的像素点计算一遍后,显示一次,重复执行上述过程,直至每一个屏幕上的像素点的灰度值恢复到原始图像灰度值的水平。渐进显示特效虽然不需要对图像进行分块,但是需要开辟两块内存空间,一块用来存储图像的原始灰度值,另一块用来存储每次计算后的像素灰度值。
逐渐增强亮度,从0到256。
6. 图像的马赛克显示;
马赛克显示是图像被分成许多小区域,显示时候小区域以杂乱无章的顺序显示在屏幕上。马赛克显示是比较难的特效,它的图像分块和显示都比较复杂。其编程思想是:先将图像分成大小相同的小区域,计算出每一块区域的首地址,并记录下来。设置一个随机数,用来产生随机显示区域的次序,每获得一个随机区域,就根据首地址显示这块区域的图像,直至所有的区域都至少显示一次。
把每个小方块都显示出来,即使每个小方块的标记都为真。
7. 图像的垂直对接显示;VerticalButt
垂直对接显示是将图像分为上下部分,然后同时向中心移动;
需要注意的是,BMP文件是倒着存放的,即屏幕显示位置(0,j)对应数据块的(0,bitmapHeight – j);屏幕显示位置(0, bitmapHeight – j)对应数据块的(0,j)。
8. 图像的压缩反转显示;CompressInvert
计算图像位置和高度,以高度的一半为轴进行对换上下半边的图像。目标矩形区域在循环的前半段为垂直反向。
//压缩反转特效显示的具体算法
int blockSize =4; // 每次显示的高度增量,应能被高度整除
for(int j=-bitmapHeight/blockSize;j<=bitmapHeight/blockSize;j++)
{
//目标矩形区域在循环的前半段为垂直反向
::StretchDIBits(pDC->GetSafeHdc(),
0, bitmapHeight/2-j*blockSize/2, bitmapWidth,j*blockSize,
0, 0, bitmapWidth, bitmapHeight,
m_pImgData, pBitmapInfo,
DIB_RGB_COLORS, SRCCOPY);
Sleep(3);//设置延时时间
}
9. 中心闭幕;CenterFallCurtain
由大到小生成图像中心区域,然后用总区域减去该中心区域,并用材质画刷填充。
//中心闭幕特效显示的具体算法
for(intj=0;j<=bitmapWidth/2;j+=stepCount)
{
CRgn rgn1,rgn2;
rgn1.CreateRectRgn(0,0,bitmapWidth, bitmapHeight);
//以源图象的尺寸创建一个矩形
rgn2.CreateRectRgn(j, j*bitmapHeight/bitmapWidth,bitmapWidth-2*j,bitmapHeight-j*2*bitmapHeight/bitmapWidth);
//不在rgn1中的部分
rgn1.CombineRgn( &rgn1, &rgn2, RGN_DIFF);
::StretchDIBits(pDC->GetSafeHdc(),j,j*bitmapHeight/bitmapWidth,
bitmapWidth-2*j,bitmapHeight-j*2*bitmapHeight/bitmapWidth,
0, 0, bitmapWidth,bitmapHeight,
m_pImgData, pBitmapInfo,
DIB_RGB_COLORS, SRCCOPY);
pDC->FillRgn(&rgn1,&brush1);
rgn1.DeleteObject();
rgn2.DeleteObject();
Sleep(3);//设置延时时间
}
10. 中心放大;CenterEnlarge
由中心向边缘按高度和宽度的比例循环输出所有像素,直到高度和宽度为原始大小。
//中心放大特效显示的具体算法
int stepCount =2; // 每次收缩的步长像素
for(int j=0;j<=bitmapWidth/2;j+=stepCount)
{
::StretchDIBits(pDC->GetSafeHdc(),bitmapWidth/2-j,
bitmapHeight/2-j*bitmapHeight/bitmapWidth, 2*j,2*j*bitmapHeight/bitmapWidth,
0, 0, bitmapWidth, bitmapHeight,
m_pImgData, pBitmapInfo,
DIB_RGB_COLORS, SRCCOPY);
Sleep(30);//设置延时时间
}
11. 交叉竖条;CrossBars
将图像分成宽度相等的列,然后计算从上下两个方向交叉前进的区域,并使用材质画刷填充。
//交叉竖条特效显示的具体算法
int lineWidth = 8; // 竖条宽度
int lineStep = 6; // 竖条每次前进的步长
for(int j=0;j<=bitmapHeight/lineStep;j++) {
for(inti=0;i<=bitmapWidth/lineWidth;i++)
{ if(i%2==0) // 从上到下
{
::StretchDIBits(pDC->GetSafeHdc(),
i*lineWidth,j*lineStep,lineWidth, lineStep,
i*lineWidth, bitmapHeight-(j+1)*lineStep,lineWidth, lineStep,
m_pImgData, pBitmapInfo,
DIB_RGB_COLORS, SRCCOPY);
}
else// 从下到上
{
::StretchDIBits(pDC->GetSafeHdc(),
bitmapWidth-(i+0)*lineWidth, bitmapHeight-(j+1)*lineStep,
lineWidth,lineStep,
bitmapWidth-(i+0)*lineWidth,j*lineStep,lineWidth,lineStep,
m_pImgData, pBitmapInfo,
DIB_RGB_COLORS, SRCCOPY);
}
}
Sleep(30);//设置延时时间
}
12. 水平拉幕;PullCurtain
由中心向开始逐渐输出中心两侧的像素,直到宽度为原始大小。
//水平拉幕特效显示的具体算法
for(inti=0;i<=bitmapWidth/2;i+=lineStep)
{
::StretchDIBits(pDC->GetSafeHdc(),
bitmapWidth/2-i,0, 2*i,bitmapHeight,
bitmapWidth/2-i, 0, 2*i,bitmapHeight,
m_pImgData, pBitmapInfo,
DIB_RGB_COLORS, SRCCOPY);
Sleep(30);//设置延时时间
}
13. 随机拉丝;RandomDraw
每次随机显示图像的一个像素行。
//13. 随机拉丝特效显示的具体算法
int*rowIndex =new int[bitmapHeight];
for (int i=0 ;i
rowIndex[i]=0;
int index = 1; // 数组索引
long RandNum;//随机变量
srand( (unsigned)time( NULL ) );//生成随机种子
do
{
RandNum=(long)( ( (double)bitmapHeight)*rand()/RAND_MAX );
//随机变量在0到bitmapHeight-1之间取值
if (rowIndex[RandNum] == 0)
{
rowIndex[RandNum] = index++;
}
}while(index
// 按照上面随机生成的次序逐一显示每个像素行
for(int i=0;i
{
::StretchDIBits(pDC->GetSafeHdc(),
0,rowIndex[i]-1, bitmapWidth, 1,
0, bitmapHeight-rowIndex[i] , bitmapWidth, 1,
m_pImgData, pBitmapInfo,
DIB_RGB_COLORS, SRCCOPY);
Sleep(3);//设置延时时间
}
14. 对角闭幕;DiagonalClose
用背景色填充左上、右下角。
//对角闭幕特效显示的具体算法
int stepCount =4; // 每次收缩的步长像素
CBrush brush1(RGB(0,128,128)); //设置画刷为lan色
CPoint ptVertex[3];
for(intj=0;j<=bitmapHeight;j+=stepCount)
{
CRgnrgn1,rgn2;
//左上角区域
ptVertex[0].x = 0;
ptVertex[0].y = 0;
ptVertex[1].x = 0;
ptVertex[1].y = j;
ptVertex[2].x =j*bitmapWidth/bitmapHeight;
ptVertex[2].y = 0;
rgn1.CreatePolygonRgn( ptVertex, 3,ALTERNATE);
//右下角区域
ptVertex[0].x = bitmapWidth ;
ptVertex[0].y = bitmapHeight ;
ptVertex[1].x = bitmapWidth ;
ptVertex[1].y = bitmapHeight -j;
ptVertex[2].x = bitmapWidth-j*bitmapWidth/bitmapHeight;
ptVertex[2].y = bitmapHeight;
rgn2.CreatePolygonRgn(ptVertex, 3, ALTERNATE);
pDC->FillRgn(&rgn1,&brush1);
pDC->FillRgn(&rgn2,&brush1);
rgn1.DeleteObject();
rgn2.DeleteObject();
Sleep(30);//设置延时时间
}
15. 垂直百叶;VerticalBlinds
//百叶特效显示的具体算法
for(int i=0;i
{
for(intj=0;j<=bitmapHeight/lineHeight;j++)
{
CRgnrgn1;
inty=lineHeight * j + i;
if(y>=(bitmapHeight-1) ) y=bitmapHeight-1;
rgn1.CreateRectRgn(0, y, bitmapWidth, y+1);
pDC->FillRgn(&rgn1,&brush1);
rgn1.DeleteObject();
Sleep(10);//设置延时时间
}
}
16. 水平拉入;PullScroll
由于内存位图与设备无关,故不能使用在水平方向逐渐改变图像分辨率(每英寸点数)的办法而改为使用在水平方向拉伸显示,并逐步缩小。
CBrush brush1(RGB(255,255,255)); //设置画刷为白色
for(int i=1;i<=96;i++)
{
CRgn rgn1;
rgn1.CreateRectRgn(bitmapWidth, 0, bitmapWidth*96/i,bitmapHeight);
::StretchDIBits(pDC->GetSafeHdc(),
0,0, bitmapWidth*96/i,bitmapHeight,
0, 0, bitmapWidth,bitmapHeight,
m_pImgData, pBitmapInfo,
DIB_RGB_COLORS, SRCCOPY);
pDC->FillRgn(&rgn1,&brush1);
rgn1.DeleteObject();
Sleep(30);//设置延时时间
}