最近在做的项目是在MFC的框架下的,我主要负责图像的绘制显示部分。是在对方框架下做插件功能,对方给出的绘图DEMO是用fillsolidrect()与SetPixel(),显示效率很低。项目的主要内容是把大量数据通过计算转换,然后赋予颜色值,通过图像来表现巨幅的井文件。呃,闲话不多说了~~~~~~~
我只说绘制部分,当然也是分块显示,即只绘当前屏幕内容,通过双缓冲实现,先绘制到内存DC,然后再贴到屏幕上。
我这两天做的修改是把效率极低的setpixel()用直接给点赋值的方法代替。就是相当于把表示颜色值BYTE的数组直接赋值给位图显示,而不是再经过先绘制到位图再显示。
考虑到效率,直接调用了API函数。经过查询有两个函数可以实现的比较好,这两个函数都能将位图数据填到位图中去,SetDIBits和SetBitmapBits,前者是对于设备无关位图的,后者是对相关位图的。
int SetDIBits(HDC hdc, HBITMAP hbmp, UINT uStartScan, UINT cScanLines, CONST VOID *lpvBits,CONST BITMAPINFO *lpbmi, UINT fuColorUse);fuColorUse:指定是否提供了BITMAPINFO结构中的bmiColors成员,如果提供了,那么bmiColors是否包含了明确的RGB值或调色板索引。参数fuColorUse必须取下列值。
DIB_PAL_COLORS:颜色表由16bit的索引值数组组成。这些值可以对由hdc参数标识的设备环境中的逻辑调色板进行索引。
LONG SetBitmapBits(HBITMAP hmbp, DWORDcBytes, CONST VOID (lpBits));
参数:
hbmp:指向要设置的位图的句柄。
cBytes:指定参数lpBits指向的数组的字节数。
lpBits:指向字节类型数组的指针。该数组中包含了指定位图的颜色数据。
返回值:
如果函数成功,则返回值就是在设置位图位时使用的字节数;如果失败,则返回值为0。
上面是两个函数的百度定义。下面贴我参考过的两段程序,也许以后还有一定的用处~~~
CX, CY;// 这个值你必须知道,事先给定int sz= CX* CY; BYTE*pData=new BYTE[sz*4];// show in 32 bits for(int i=0; i< sz; i++) { pData[i*4+0]=*ColorB++ ; pData[i*4+1]=*ColorG++; pData[i*4+2]=*ColorR++; pData[i*4+3]=0; } CDC*pdc= GetDC(); CDC memdc; CBitmap bmp; CRect rt; memdc.CreateCompatibleDC(pdc); bmp.CreateBitmap(CX, CY ,1,32,pData); CBitmap* pOldBitmap= memdc.SelectObject(&bmp); pdc->BitBlt(0,0, CX, CY,&memdc,0,0, SRCCOPY); memdc.SelectObject(pOldBitmap); memdc.DeleteDC(); ReleaseDC(pdc);
void CTest:OnDraw(CDC* pDC) { // TODO: Add extra validation here CDC memDC; memDC.CreateCompatibleDC(pDC); CBitmap bmp; bmp.CreateCompatibleBitmap(pDC,500,500); memDC.SelectObject(&bmp); BITMAPINFO bmpInfo; bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmpInfo.bmiHeader.biWidth = 487; bmpInfo.bmiHeader.biHeight = -500; bmpInfo.bmiHeader.biPlanes = 1; bmpInfo.bmiHeader.biBitCount = 24; bmpInfo.bmiHeader.biCompression = BI_RGB; bmpInfo.bmiHeader.biSizeImage = 0; bmpInfo.bmiHeader.biXPelsPerMeter = 3000; bmpInfo.bmiHeader.biYPelsPerMeter = 3000; bmpInfo.bmiHeader.biClrUsed = 0; bmpInfo.bmiHeader.biClrImportant = 0; //每行字节数,4字节对齐 long nLnBytes = (487*3+3)/4*4; BYTE *pData = new BYTE[nLnBytes*500]; memset(pData,0,nLnBytes*500); for(int i=10; i<90; i++) { pData[50*nLnBytes+i*3]=255; pData[i*nLnBytes+50*3+2]=255; } SetDIBits(pDC->m_hDC,bmp,0,500,pData,&bmpInfo,DIB_RGB_COLORS); delete []pData; pDC ->BitBlt(0,0,500,500,&memDC,0,0,SRCCOPY); }
当然也有好多其他方法,如先定义BITMAPINFO变量,然后对这个变量进行初始化,定义好图片的文件头,接着使用CreateDIBSection,根据BITMAPINFO创建一个空的位图,然后用memcpy把BYTE中的像素数据拷贝到这个空位图中,最后用CBitmap::FromHandle把得到的HBITMAP类型变量转换为CBitmap类型。
提高绘制的效率,也有很多人提到了OPENGL与DIRECRX。当然这些都是用来绘制很复杂的场景使用的,如游戏场景。还有大幅图像也可以考虑多线程建立后台临时文件,滚动显示的时候可以直接调用,不需要再计算绘制或赋值的过程了~~~~~~