GDI实现图像的简单显示特效



GDI实现图像的简单显示特效

1. 原理                                                                                                                                                 
    核心是将图像分成不同的块,然后以不同的顺序显示
2. 特效                                                                                                                   
    要实现图片的特效,首先加载一副位图
  1. //////////////////////////////////////////////////////////////////////
  2. //加载位图
  3. CDC memDC;
  4. memDC.CreateCompatibleDC(pDC);  //创建兼容DC
  5. HBITMAP hBmp;                   //加载位图
  6. hBmp = (HBITMAP)LoadImageW(NULL,L”1.bmp”,IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION);
  7. BITMAP bm;                      //获取位图信息
  8. GetObject(hBmp,sizeof(bm),&bm);
  9. SelectObject(memDC,hBmp);       //位图选入内存DC
	//////////////////////////////////////////////////////////////////////
	//加载位图

	CDC memDC;
	memDC.CreateCompatibleDC(pDC);	//创建兼容DC

	HBITMAP	hBmp;					//加载位图
	hBmp = (HBITMAP)LoadImageW(NULL,L"1.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION);

	BITMAP bm;						//获取位图信息
	GetObject(hBmp,sizeof(bm),&bm);

	SelectObject(memDC,hBmp);		//位图选入内存DC
    要显示特效,还需获得显示屏幕的DC
    可以在MFC 单文档程序的OnDraw 中实现特效的绘制,其屏幕DC 为 pDC
2.1  逐行显示特效
    方法:循环,每次显示一行
  1. //逐行显示特效
  2. int offset_x = 10;
  3. int offset_y = 10;
  4. for(int i=0;i<bm.bmHeight;++i)
  5. {
  6.     //pDC->BitBlt(x,y,width,height,pSrcDC,xSrc,ySrc,dwRop);
  7.     //(x,y)         : 屏幕左上角的坐标
  8.     //(width,height): 要绘制的宽度和高度
  9.     //pSrcDC        : 源图像(的DC)
  10.     //(xSrc,ySrc)   : 图像上的左上角
  11.     //dwRop         : 操作方式
  12.     pDC->BitBlt(offset_x,offset_y+i,bm.bmWidth,1,&memDC,0,i,SRCCOPY);//一行一行显示
  13.     Sleep(10);
  14. }
	//逐行显示特效
	int offset_x = 10;
	int offset_y = 10;
	for(int i=0;i<bm.bmHeight;++i)
	{
		//pDC->BitBlt(x,y,width,height,pSrcDC,xSrc,ySrc,dwRop);
		//(x,y)			: 屏幕左上角的坐标
		//(width,height): 要绘制的宽度和高度
		//pSrcDC		: 源图像(的DC)
		//(xSrc,ySrc)   : 图像上的左上角
		//dwRop			: 操作方式
		pDC->BitBlt(offset_x,offset_y+i,bm.bmWidth,1,&memDC,0,i,SRCCOPY);//一行一行显示
		Sleep(10);
	}
说明:上面程序实现了自上而下的逐行显示,自下而上、自左向右等特效实现方法类似。
2.2  向右移动进入特效
     方法:从右向左显示图像,每次显示的图像宽度增加
  1. //向右移动进入特效
  2. offset_x = 10;
  3. offset_y = bm.bmHeight+20;
  4. for(int w=1;w<=bm.bmWidth;++w)   //w是显示的宽度
  5. {
  6.     pDC->BitBlt(offset_x,offset_y,w,bm.bmHeight,&memDC,bm.bmWidth-w,0,SRCCOPY);
  7.     Sleep(10);
  8. }
	//向右移动进入特效
	offset_x = 10;
	offset_y = bm.bmHeight+20;
	for(int w=1;w<=bm.bmWidth;++w)	//w是显示的宽度
	{

		pDC->BitBlt(offset_x,offset_y,w,bm.bmHeight,&memDC,bm.bmWidth-w,0,SRCCOPY);
		Sleep(10);
	}

                 

2.3 马赛克特效
    方法:将图像划分成小块,然后按照随机的顺序显示出每一小块
  1. //将0到count-1 随机顺序形成一个数组
  2. void rand_seq(int count,int seq_array[])
  3. {
  4.     for(int i=0;i<count;++i)
  5.     {
  6.         seq_array[i] = i;
  7.     }
  8.     //打乱 做1000次随机交换
  9.     int swap_count=0;
  10.     while(swap_count<1000)
  11.     {
  12.         //生成一个随机数
  13.         LARGE_INTEGER seed;
  14.         QueryPerformanceCounter(&seed);
  15.         srand((int)seed.QuadPart);
  16.         int seq = rand()%count-1; //0到count-1
  17.         //交换seq_array[seq] 和 seq_array[count-seq-1]
  18.         int tmp = seq_array[seq];
  19.         seq_array[seq] = seq_array[count-seq-1];
  20.         seq_array[count-seq-1] = tmp;
  21.         swap_count ++;
  22.     }
  23. }
//将0到count-1 随机顺序形成一个数组
void rand_seq(int count,int seq_array[])
{
	for(int i=0;i<count;++i)
	{
		seq_array[i] = i;
	}

	//打乱 做1000次随机交换
	int swap_count=0;
	while(swap_count<1000)
	{	
		//生成一个随机数
		LARGE_INTEGER seed;
		QueryPerformanceCounter(&seed);
		srand((int)seed.QuadPart);
		int seq = rand()%count-1; //0到count-1

		//交换seq_array[seq] 和 seq_array[count-seq-1]
		int tmp = seq_array[seq];
		seq_array[seq] = seq_array[count-seq-1];
		seq_array[count-seq-1] = tmp;

		swap_count ++;
	}
}
  1. //马赛克效果:分成不同的块,随机显示
  2. offset_x = bm.bmWidth+20;
  3. offset_y = 10;
  4. int block_size = 10;                //10*10的小块,按行编号 0,1,2,3,4,5…block_count-1
  5. int bpr = bm.bmWidth/block_size;    //一行的方块数目,block_per_row
  6. int bpc = bm.bmHeight/block_size;
  7. int block_count = bpr*bpc;          //总共的方块数目
  8. int seq=-1;
  9. int* seq_array = new int[block_count];
  10. rand_seq(block_count,seq_array);    //获得随机顺序
  11. for(int i=0;i<block_count;++i)
  12. {
  13.     seq = seq_array[i];         //要显示的块号
  14.     int row = seq/bpr;          //所在行
  15.     int col = seq%bpr;          //所在列
  16.     pDC->BitBlt(offset_x+col*block_size,
  17.                 offset_y+row*block_size,
  18.                 block_size,
  19.                 block_size,
  20.                 &memDC,
  21.                 col*block_size,
  22.                 row*block_size,
  23.                 SRCCOPY);
  24.     Sleep(1);
  25. }
  26. delete[] seq_array;


	//马赛克效果:分成不同的块,随机显示
	offset_x = bm.bmWidth+20;
	offset_y = 10;
	int block_size = 10;				//10*10的小块,按行编号 0,1,2,3,4,5...block_count-1
	int bpr = bm.bmWidth/block_size;	//一行的方块数目,block_per_row
	int bpc = bm.bmHeight/block_size;
	int block_count = bpr*bpc;			//总共的方块数目

	int seq=-1;
	int* seq_array = new int[block_count]; 
	rand_seq(block_count,seq_array);	//获得随机顺序
	for(int i=0;i<block_count;++i)
	{
		seq = seq_array[i];			//要显示的块号
		int row = seq/bpr;			//所在行
		int col = seq%bpr;			//所在列
		pDC->BitBlt(offset_x+col*block_size,
					offset_y+row*block_size,
					block_size,
					block_size,
					&memDC,
					col*block_size,
					row*block_size,
					SRCCOPY);
		Sleep(1);
	}
	delete[] seq_array;

说明:由于写的随机顺序算法rand_seq不是很好,所以马赛克效果也不是很好。读者如果能否实现更好的随机排列算法,势必会得到更好的马赛克效果
2.4 雨滴特效
    方法:从图像的最后一行开始,每次显示一行,并将该行上面的每一行都与该行显示相同
  1. //雨滴特效
  2. offset_x = bm.bmWidth+20;
  3. offset_y = bm.bmHeight+20;
  4. for(int i=0;i<bm.bmHeight;++i)//外循环控制每次显示的图像行,循环一次,表示显示了一行
  5. {
  6.     for(int j=0;j<bm.bmHeight-i;++j)//内循环控制绘制出雨滴轨迹
  7.     {
  8.         pDC->BitBlt(offset_x,offset_y+j,bm.bmWidth,1,&memDC,0,bm.bmHeight-i,SRCCOPY);
  9.     }
  10.     Sleep(10);
  11. }
	//雨滴特效
	offset_x = bm.bmWidth+20;
	offset_y = bm.bmHeight+20;
	for(int i=0;i<bm.bmHeight;++i)//外循环控制每次显示的图像行,循环一次,表示显示了一行
	{
		for(int j=0;j<bm.bmHeight-i;++j)//内循环控制绘制出雨滴轨迹
		{
			pDC->BitBlt(offset_x,offset_y+j,bm.bmWidth,1,&memDC,0,bm.bmHeight-i,SRCCOPY);

		}
		Sleep(10);
	}

 

注:本文为学习《数字图像处理原理与实践》(左飞等)过程中的笔记