VS2010 C++学习(3):BMP图像文件的特效显示

来源:互联网 发布:时间序列算法arima 编辑:程序博客网 时间:2024/04/27 20:43

 

 

VS2010 C++学习(3):BMP图像文件的特效显示

 

学习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的指针(包含 BITMAPFILEHEADERBITMAPINFOHEADER和颜色表)

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 012,…,256。每一次显示像素灰度值的 n/256 倍,图像的像素点计算一遍后,显示一次,重复执行上述过程,直至每一个屏幕上的像素点的灰度值恢复到原始图像灰度值的水平。渐进显示特效虽然不需要对图像进行分块,但是需要开辟两块内存空间,一块用来存储图像的原始灰度值,另一块用来存储每次计算后的像素灰度值。

逐渐增强亮度,从0256

 

6.       图像的马赛克显示;

马赛克显示是图像被分成许多小区域,显示时候小区域以杂乱无章的顺序显示在屏幕上。马赛克显示是比较难的特效,它的图像分块和显示都比较复杂。其编程思想是:先将图像分成大小相同的小区域,计算出每一块区域的首地址,并记录下来。设置一个随机数,用来产生随机显示区域的次序,每获得一个随机区域,就根据首地址显示这块区域的图像,直至所有的区域都至少显示一次。

把每个小方块都显示出来,即使每个小方块的标记都为真。

 

7.       图像的垂直对接显示;VerticalButt

垂直对接显示是将图像分为上下部分,然后同时向中心移动;

需要注意的是,BMP文件是倒着存放的,即屏幕显示位置(0j)对应数据块的(0,bitmapHeight – j);屏幕显示位置(0, bitmapHeight – j)对应数据块的(0j)。

 

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<bitmapHeight;i++)

           rowIndex[i]=0;

    int index = 1; // 数组索引      

long RandNum;//随机变量

srand( (unsigned)time( NULL ) );//生成随机种子

        do

        {

RandNum=(long)( ( (double)bitmapHeight)*rand()/RAND_MAX );

//随机变量在0bitmapHeight-1之间取值

               if (rowIndex[RandNum] == 0)

                       { 

               rowIndex[RandNum] = index++; 

           } 

        }while(index<bitmapHeight);

  // 按照上面随机生成的次序逐一显示每个像素行 

for(int i=0;i<bitmapHeight;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<lineHeight;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);//设置延时时间

        }