GDI实现图像的简单显示特效
1. 原理
核心是将图像分成不同的块,然后以不同的顺序显示
2. 特效
要实现图片的特效,首先加载一副位图
- //////////////////////////////////////////////////////////////////////
- //加载位图
- 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
////////////////////////////////////////////////////////////////////// //加载位图 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 逐行显示特效
方法:循环,每次显示一行
- //逐行显示特效
- 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);
- }
//逐行显示特效 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 向右移动进入特效
方法:从右向左显示图像,每次显示的图像宽度增加
- //向右移动进入特效
- 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);
- }
//向右移动进入特效 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 马赛克特效
方法:将图像划分成小块,然后按照随机的顺序显示出每一小块
- //将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 ++;
- }
- }
//将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 ++; } }
- //马赛克效果:分成不同的块,随机显示
- 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;
//马赛克效果:分成不同的块,随机显示 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 雨滴特效
方法:从图像的最后一行开始,每次显示一行,并将该行上面的每一行都与该行显示相同
- //雨滴特效
- 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);
- }
//雨滴特效 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); }
注:本文为学习《数字图像处理原理与实践》(左飞等)过程中的笔记