[转]怎样提高GDI+的绘图效率(补充讨论)

偶贴的上一个帖子名字是“GDI+的绘图效率问题,大家讨论一下吧!”。在其中解决的效率问题远远不够。现在工作中的模块做的差不多了,总结了一下最近得到的经验结论,贴出来大家进一步讨论下。。。也算是在CSDN上得到了诸多帮助的一个小小的回报:) 在交流中共同进步吧!

  不知道为什么MS把GDI+中的   DrawImage   这个函数效率做的这么低,(当然了,它的优点是使用方便、支持透明PNG格式等等,还有什么优点有经验的朋友不妨贴出来共享下:) 那么到底有多低呢?我也不知道,所以刚才做了个试验。让DrawImage和::BitBlt速度做了个比较!

  先说下我的机器配置:2*3.0G   Intel   CPU,1G的内存,Intel945的显卡。在一个窗口中用DrawImage画一个590X480大小的PNG图片,画了100次,用了.......长时间;用BitBlt画同样大小的bmp图片,画了1000次,用了...长时间,多少时间我不管了,帧速我是计算出来了大约是   DrawImage   16.5帧/秒,BitBlt   2169.2帧/秒   。没错!确实是这个数字。我数学学的不好,就用计算器算了一下BitBlt的绘图速度是DrawImage的131.5倍。。。

  代码也贴出来吧,写的比较粗糙:

void   CCmpBitBltToDrawImageDlg::OnBnClickedButton1()
{

Bitmap*   ppng   =   NULL;
CDC*   pDC   =   GetDC   ();
Graphics*   pGrp   =   Graphics::FromHDC   (pDC-> GetSafeHdc   ());
ppng   =   Bitmap::FromFile   (L"res\\tray.png");

clock_t   start   =   clock   ();
for   (int   i   =   0;   i   <   100;   i++)
{
pGrp-> DrawImage   (ppng,   0,   0);
}
delete   pGrp;
ReleaseDC   (pDC);
delete   ppng;

clock_t   time   =   clock   ()   -   start;
float   ftime   =   time   /   1000.0f;
CString   str;
str.Format   ("%.1f   frame   per   second\n",   100   /   ftime);
AfxMessageBox   (str);
}

void   CCmpBitBltToDrawImageDlg::OnBnClickedButton2()
{
CDC   memDC;
CBitmap   bmp;

if   (0   ==   bmp.LoadBitmap   (IDB_BITMAP1))
{
AfxMessageBox   ("载入图片失败");
return;
}

CDC*   pDC   =   GetDC   ();
memDC.CreateCompatibleDC   (pDC);
memDC.SelectObject   (&bmp);

clock_t   start   =   clock   ();
for   (int   i   =   0;   i   <   2000;   i++)
{
::BitBlt   (pDC-> GetSafeHdc   (),   0,   0,   590,   480,   memDC.GetSafeHdc   (),  
0,   0,   SRCCOPY);
}

ReleaseDC   (pDC);
clock_t   time   =   clock   ()   -   start;
float   ftime   =   time   /   1000.0f;
CString   str;
str.Format   ("%.1f   frame   per   second\n",   2000   /   ftime);
AfxMessageBox   (str);
}


  对了,我没有在OnPaint用CPaintDC,是因为用CPaintDC   DrawImage不出东西。不知道为什么?哪位高手知道烦请告诉我。


  前面罗嗦了半天,下面进入正题。
  我做的界面模块之前用DrawImage方法来绘图,以我的机器配置有70多个帧吧,人眼是察觉不出来了。觉得速度可以了,但这个模块是跑在虚拟机是的,内存的使用是受限制的,限制到128M,另外可能也有模拟硬件的原因,速度由70多帧降到了9帧。大家都知道只有屏幕的刷新速度达到24帧/秒以上,人眼才会感觉画面流畅。

  所以,我得想办法解决问题呵呵。
  因为利用了双缓冲,我在内存中建立了一个Graphics绘图平面m_pMemGraphics,先把零碎元素画到这个内存平面上,再一次性将它绘制到屏幕上。这个Graphics对象对象是利用FromImage方法创建的(也就是说,在这个绘图平面上绘图是把所有的东西都画到了这个Graphics对象所依赖的图片上,然后需要绘制到屏幕上的时候,只能用DrawImage的办法将这个图片画到屏幕上。偶也想到了用BitBlt的方法以提高效率,但用FromImage方法创建的Graphcis对象的DC是一片漆黑!找了半天利用它的DC的方法也不得要领,在codeproject上找到一个例子是VB.NET的,分析了半天还是没有办法。。。这又是一个疑问,希望知道的高手告诉俺怎么做,在这里先谢了),我就只好用DrawImage了。也想了其它的几个办法,包括GDI和GDI+混合使用,GDI+使用了GDI创建的DC。但反过来,就像上面我描述的"一片漆黑",行不通,我还是先说一下暂时没有使用BitBlt怎样改进的绘图效果吧:

  1.   使用SetClip限定你的绘制区域。

  2.   仅仅是限定的绘制区域也是不行的,还要把你所要绘制的图片剪切的尽量小,和SetClip配合使用。

  3.   多浪费点儿内存使用   CachedBitmap   吧,绘图速度会好很多,DrawCachedBitmap   要比   DrawImage   快一些。


  使用了以上几种方法我的程序绘制速度由70多帧提高到了200多帧。。。还可以哦,仍然是DrawImage和DrawCachedBitmap而没有使用BitBlt。嘿嘿好了,今天想到的就这么多,先写这些吧。我的结论是:绘图尽量使用BitBlt 来替代 DrawImage。

  贴段示例代码吧,也因为功能性的东西写的比较分散了,就贴一个函数好了,道理是相同的。。。

void   CDesktopDlg::DrawRing   ()
{
//   设置剪切区域
m_pGraphics-> SetClip   (m_pClipRgn);

//   内存中绘制背景
m_pMemTrayGrp-> DrawCachedBitmap   (m_pCachedTrayBmp,   0,   0);     //   <------注意m_pCachedTrayBmp和         //   m_pTrayBmp是相同的图片,只是一份复         //   制,用来提高绘图速度。

if   (m_lstShowBtnRing.size   ()   >   0)
{
//   内存中绘制按钮
for   (list <CEbankButtonAttr*> ::iterator   itor   =   m_lstShowBtnRing.begin   ();
itor   !=   m_lstShowBtnRing.end   ();   itor   ++)
{
m_pMemTrayGrp-> DrawCachedBitmap   ((*itor)-> m_pCachedBmp,   (*itor)-> x,  
(*itor)-> y));
}
}

//   绘制到屏幕
m_pGraphics-> DrawImage   (m_pTrayBmp,   *m_pTrayRect);
}


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/kaka_iseeyou/archive/2008/01/10/2033690.aspx

posted @ 2010-10-20 15:37  逆时针  阅读(1045)  评论(0编辑  收藏  举报