提高setpixel()效率,即颜色值直接赋给位图显示的问题解决

来源:互联网 发布:知乎 东邪西毒讲的什么 编辑:程序博客网 时间:2024/06/05 20:47

最近在做的项目是在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);
参数:
hdc:指向设备环境中的句柄。
hbmp:指向位图的句柄。函数要使用指定DIB中的颜色数据对该位图进行更改。
uStartScan:为参数lpvBits指向的数组中的、与设备无关的颜色数据指定起始扫描线。
cScanLines:为包含与设备无关的颜色数据的数组指定扫描线数目。
lpvBits:指向DIB颜色数据的指针,这些数据存储在字节类型的数组中,位图值的格式取决于参数lpbmi指向的BITMAPINFO结构中的成员biBitCount。
lpbmi:指向BITMAPINFO数据结构的指针,该结构包含有关DIB的信息。

fuColorUse:指定是否提供了BITMAPINFO结构中的bmiColors成员,如果提供了,那么bmiColors是否包含了明确的RGB值或调色板索引。参数fuColorUse必须取下列值。

DIB_PAL_COLORS:颜色表由16bit的索引值数组组成。这些值可以对由hdc参数标识的设备环境中的逻辑调色板进行索引。
DIB_RGB_COLORS:提供了颜色表,并且表中包含了原义的RGB值。
返回值:
如果函数成功,那么返回值就是复制的扫描线数;如果函数失败,那么返回值是0。


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 bitsfor(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 hereCDC 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。当然这些都是用来绘制很复杂的场景使用的,如游戏场景。还有大幅图像也可以考虑多线程建立后台临时文件,滚动显示的时候可以直接调用,不需要再计算绘制或赋值的过程了~~~~~~




1 0
原创粉丝点击