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

 

 

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);//设置延时时间

        }

 

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++中,可以使用以下步骤对bmp图像文件进行操作: 1. 打开bmp文件:使用标准C++库中的文件操作函数,如fopen()或ifstream打开bmp文件。 2. 读取bmp文件头:根据bmp文件格式,读取文件头信息,包括文件类型、文件大小、图像宽度、高度和色彩位数等信息。 3. 读取像素数据:根据图像宽度、高度和色彩位数等信息,计算出像素数据的大小,然后读取像素数据。 4. 对像素数据进行操作:可以使用C++的数组或指针等数据结构来对像素数据进行操作,如图像处理、滤波、变换等操作。 5. 写入像素数据:对操作后的像素数据进行写入,覆盖原有像素数据。 6. 关闭bmp文件:使用标准C++库中的文件操作函数,如fclose()或ofstream关闭bmp文件。 以下是一个简单的C++程序示例,用于读取bmp文件并将像素数据进行灰度化处理: ```c++ #include <iostream> #include <fstream> using namespace std; #pragma pack(push, 1) typedef struct { char type[2]; unsigned int size; short reserved1; short reserved2; unsigned int offset; } BMPHeader; typedef struct { unsigned int size; int width; int height; short planes; short bitsPerPixel; unsigned int compression; unsigned int imageSize; int xPixelsPerMeter; int yPixelsPerMeter; unsigned int colorsUsed; unsigned int colorsImportant; } BMPInfoHeader; #pragma pack(pop) int main() { BMPHeader header; BMPInfoHeader infoHeader; char* data; ifstream file("test.bmp", ios::binary); if (!file.is_open()) { cout << "Error opening file" << endl; return 1; } file.read((char*)&header, sizeof(header)); file.read((char*)&infoHeader, sizeof(infoHeader)); int width = infoHeader.width; int height = infoHeader.height; int bitsPerPixel = infoHeader.bitsPerPixel; int dataSize = width * height * bitsPerPixel / 8; data = new char[dataSize]; file.seekg(header.offset, ios::beg); file.read(data, dataSize); file.close(); // 灰度化处理 for (int i = 0; i < width * height; i++) { int index = i * 3; int gray = 0.299 * (unsigned char)data[index + 2] + 0.587 * (unsigned char)data[index + 1] + 0.114 * (unsigned char)data[index]; data[index] = gray; data[index + 1] = gray; data[index + 2] = gray; } ofstream outFile("output.bmp", ios::binary); outFile.write((char*)&header, sizeof(header)); outFile.write((char*)&infoHeader, sizeof(infoHeader)); outFile.write(data, dataSize); outFile.close(); delete[] data; return 0; } ``` 注意:上述代码仅用于演示bmp文件读取和像素数据处理的基本操作,实际应用中可能需要进行更多的异常处理和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值