千里之行,始于足下

酌贪泉而觉爽,处涸辙而犹欢

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  34 随笔 :: 0 文章 :: 192 评论 :: 10 引用

在.net framework中,绘制图形一般是使用Graphics.DrawImage方法,但是这个方法在许多时候有明显的缺陷。



以上是一张图的两种显示效果。左侧为windows自身的缩略图显示效果,右侧为调用DrawImage方法所显示的效果。源图为tiff格式,幅面大小为3185*2276,300*300dpi,图形文件大小52.4KB。可以看到两种显示效果有明显的区别,这是由于DrawImage在处理图形的高比例缩小时采用了默认算法,导致了图形显示的严重失真。

更为严重的缺陷是,DrawImage函数对于更大幅面的图像绘制几乎完全不能胜任,测试中使用了一个幅面为13290*9600,400*400dpi,大小为2.5MB的一个tiff文件,DrawImage函数一运行一下子就使得我的本本虚拟内存全部耗完,整个系统陷入没有响应的状态!

基于以上原因,在绘制大型图像时,已不能再使用.net framework提供的DrawImage方法。在最近我做的一个程序中,便重新开发了一个C++的动态链接库来完成大型图像的绘制,显示的效果和速度均得到极佳的体现!

C++绘制函数原型:

1extern "C" void HighSpeedDraw(HDC hDC, int srcLeft, int srcTop, int srcRight, int srcBottom,
2    int dstLeft, int dstTop, int dstRight, int dstBottom)
3{
4    CDC* pDC = CDC::FromHandle(hDC);
5    CRect srcRect(srcLeft, srcTop, srcRight, srcBottom);
6    CRect dstRect(dstLeft, dstTop, dstRight, dstBottom);
7    pDrawEngine->Draw(pDC, dstRect, srcRect);
8}

在C#中的包装:

1[DllImport("HSDraw.dll")]
2private extern static void HighSpeedDraw(IntPtr hDC, int srcLeft, int srcTop, int srcRight, int srcBottom,
3    int dstLeft, int dstTop, int dstRight, int dstBottom)

OK,在Paint函数中就可以这样调用了:

 1try
 2{
 3  checked
 4  {
 5    IntPtr hDC = e.Graphics.GetHdc();
 6    HighSpeedDraw(hDC, sourceRect.Left, sourceRect.Top, sourceRect.Right, sourceRect.Bottom,
 7        targetRect.Left, targetRect.Top, targetRect.Right, targetRect.Bottom);
 8    e.Graphics.ReleaseHdc(hDC);
 9  }

10}

11catch (Exception ex)
12{
13  graphics.DrawString(ex.ToString(), new Font("Arial"8), Brushes.Red, new PointF(00));
14}

以下是使用C++绘制算法看到的效果:

 

可以看到,新的算法绘制的效果非常好。此外,原先使用DrawImage导致系统无法响应的tiff文件,现在绘制所耗时间在1秒以内,图像绘制所消耗的内存也降至20M以下,效果得到了明显的提高。

posted on 2006-12-27 18:11 sunwaywei 阅读(2126) 评论(10) 编辑 收藏

评论

#1楼 2006-12-27 19:44 microshot      
看看??
 回复 引用 查看   

#2楼 2006-12-27 21:42 Cat Chen      
很多非托管GDI+有的功能,在托管GDI+中都没有,特别是高效率的函数,这让人很头痛。.NET Framework的架构师们也太注重易用性了,把易于理解的函数都去掉。
 回复 引用 查看   

#3楼 2006-12-27 22:19 U2U      
好东西,二者结合,相得益彰。
 回复 引用 查看   

#4楼 2006-12-27 23:27 wqxh      
呵呵,不错。效率原来差这么大啊,看来一些底层一点的api还是不能抛弃。
 回复 引用 查看   

哈哈~~原来是你~~~嘻嘻
 回复 引用   

我最近也遇到绘大图的问题(1W*1W),我用的是分块绘图,性能 还是不错,就是内存耗的多。
你有高招没有?
 回复 引用   

#7楼 2006-12-28 12:36 航天奇侠
看来有些问题还是c++比较简单。
 回复 引用   

#8楼 2006-12-28 15:36 hesicong[未注册用户]
学习学习.看来底层api不能忘记啊~!
 回复 引用   

#9楼 2006-12-28 19:40 cutechun[未注册用户]
另外:.net 在图像处理方面,易用性是提高了,但速度却不敢恭维
 回复 引用   

#10楼 2006-12-29 11:04 A.Z[匿名]
.net很多地方都是调用原生环境已经实现的API,这样的封装在处理通常的高层对性能和响应比较宽松的场合是适用的,但是如果频繁的调用原生环境的函数就会产生过程大量的封送值的问题,虽然.net可以尽量快的处理平台的调用,但是累计的性能损耗还是很厉害,而C++的库对底层设备的支持是供.net使用的,所以如果有大量的或者无法用.net操作的底层api都需要引用C++工程予以实现,就像高负荷的DC作业,本身就对内存的分配算法要求很高,这是.net平台的未能真正触及的领域。m$引入混合工程就是为了这部分从上而下的开发的需求而设计的。
 回复 引用