GDI+的雷区

原创 2005年04月22日 22:14:00

GDI+的雷区

 2005-4-22

 

 

千呼万唤之中,微软终于推出了早该有的精心设计的下一代图形程序接口GDI+,并成为dotNet的图形绘制核心,这些也可以算是陈年旧事了。当几批给微软趟雷的勇士倒下后,大家开始发现GDI+实为鸡肋,食之无味,弃之可惜。

 

雷区:贼慢的速度

 

诸位应该也有很多人都已经注意到了,不是一般的慢。找微软和MVP给的优化方法都没用,根本原因有两个,一个是GDI+目前不使用硬件加速,准确的说它基于GDI的部分是通过GDI加速的,其他的部分是纯CPU计算;二是算法实现有问题,如典型的画位图的问题,绘制的速度和源位图大小有关,注意不是和实际绘制的部分的大小有关,而是和源位图的总大小有关。就是说绘制128x128的位图和绘制1024x1024的位图的一个128x128的部分,这两种方法都只画128x128,但速度有天壤之别,这个问题在好多论坛都讨论过,大家都不能理解不能接受,只好去用GDI。不要以为这是没有使用MSDN和那些MVP的优化建议,不相信的可以自己试试。

 

雷区:失败的封装

 

dotNet最好的地方是提供了一套设计优秀、风格统一的API,但GDI+的封装部分,就是System.Drawing名字空间里的东西,却做得很失败。dotNet的核心优势是垃圾收集,对纯内存数据对象,是不需要操心其生存期管理的,不但简化了内存管理,而且使必须为函数的返回值分配内存的糟糕的API接口成为过去,可以既提供直观易用又没有性能损失的函数。按着垃圾收集模式的精神,是应该鼓励不需要Dispose的对象的。但Sytem.Drawing名字空间里的类几乎全部需要Dispose,连MatrixStringFormat这种东西都要Dispose。纠其原因,就是这些类没有提供dotNet的实现,而是包装的GDI+对象的指针,这种方式节省了他们开发的时间,却给了我们无尽的麻烦,而且处于兼容性考虑,以后的版本也很难将那个IDisposable接口从那些类上去掉。

 

而更糟的是微软的样例代码里都不掉用Dispose,这样代码看起来很清晰简洁,却要一群MVP四处劝说一定要Dispose。知道了它的内部实现,每个程序员都会认为它确实应该被尽快Dispose,而不能等垃圾收集去做,因为垃圾收集器是不知道这些非托管资源占了多少内存、占了多少系统资源的。写dotNet控件的程序员经常遇到IDE变慢甚至报告资源不足的情况,就是有太多的GDI+对象没释放的关系。而MSDN可没有教人Dispose啊,连Bitmap对象都没!

 

知道了应该Dispose,那么就Dispose呗。

Pen blackPen = new Pen(Color.Black, 3);

e.Graphics.DrawLine(blackPen, x1, y1, x2, y2);

blackPen.Dispose();

这行了吧,不行!DrawLine可能抛异常啊,那样blackPen还是没有释放,所以要

Pen blackPen = null;

Try {

       blackPen = new Pen(Color.Black, 3);

e.Graphics.DrawLine(blackPen, x1, y1, x2, y2);

}

finally {

blackPen.Dispose();

}

幸亏C#里提供了uisng,可以简化为

using (blackPen = new Pen(Color.Black, 3)) {

e.Graphics.DrawLine(blackPen, x1, y1, x2, y2);

}

可是一个GDI+对象还好,10个怎么办,在绘图程序里可不止这几个啊,难道using (…) using (…) using (…) using (…) …??这代码还能读吗?

 

于是大家也只能破罐破摔,小东西就不管了。

 

雷区3:和交互效率不高

 

由于速度问题,大家只能求救于GDI,想那GDI+提供了不少和GDI交互的函数,就像早就知道大家有这么一天似的。可一用就不对了,因为大部分情况下它是拷贝一份生成GDI对象,GDI操作完再拷贝回来。真是让人预哭无泪。

 

雷区4:又提供新的基于加速的图形,还要做什么?

 

正如Joel所说,微软现在不停的出各种各样的新的API,又在不久之后做出新的替代品而放弃旧的,对程序员来说就是恶梦。旧问题不解决,而用新的替代,然后新的又带来一堆新问题,然后再出更新的来替代。如果不是必要,不要在GDI+上下太大的赌注。

 

结论

 

当然,天下没有完美的东西,虽然有很多缺陷,GDI+的功能还是非常有吸引力,要求不高的话还是很有用的。这里给大家提供了GDI+的几大雷区,希望大家不要都在趟雷中牺牲了。

 

 

 

 

 

 

 

vb.net GDI+入门——使用Graphics对象填充图形

上一章我们了解如何使用Graphics对象来绘制由点和线构成的线图《vb.net GDI+入门——使用Graphics对象绘制线图》,在实际绘图中,我们还需要使用色块等来填充图形,这一章, 就来看如...

vc6.0使用gdi+在内存中绘图并将其保存为bmp,jpg,gif,png等格式的图片

刚开始使用的是gdi保存cview中的绘图内容,但是发现由于保存的是位图所以保存下来的图片的大小很大,每个大概有2M左右,所以在网上找解决方法,选择使用GDI+来保存绘图为图片,大小为20K左右,主要...
  • zhha86
  • zhha86
  • 2011年11月28日 11:00
  • 4193

GDI+概述及双缓冲绘图技术

1.GDI概述及实例分析 1.1 GDI概述 GDI在全称是Graphics Device Interface,即图形设备接口。是图形显示与实际物理设备之间的桥梁。GDI使得用户无需关心具...

VC++6.0使用GDI++出现'ULONG_PTR'未定义和'token' 未定义的解决办法

VC++6.0使用GDI++出现'ULONG_PTR'未定义和'token' 未定义的解决办法 http://hi.baidu.com/programpad/blog/item/5e479f4d...

GDI+学习之路1--准备知识

    从今天开始,根据MSDN中GDI+文档正式学习GDI+图形界面编程技术。GDI+概述:Microsoft Windows GDI+ 是Windows XP和Windows Server 200...

C# GDI+双缓冲技术

GDI+的双缓冲问题     我想有很多搞图形方面的朋友都会用到双缓冲技术的时候,而且有的时候她的确是个头疼的问题。最近我也要用双缓冲技术,程序怎么调试都不合适,当要对图形进行移动时,总是会出现闪烁...
  • gws1229
  • gws1229
  • 2015年07月30日 09:55
  • 341

c# GDI+ Image.Save()或者Bitmap.Save()方法保存高质量图片

GDI+保存质量比较高的图片的方法,使用Image或者Bitmap的Save方法调节图像保存的质量。 Image.Save方法共有五种重载  其中Save(String, ImageCod...

GDI+学习及代码总结之------区域

在GDI+中,对于区域的部分基本上使用了GDI的区域构造函数与合并方法,所以我们先看看GDI中的区域是如何构造与操作的。 GDI中区域构建与操作 一、基本函数 创建矩形区域: HRGN Crea...

GDI+学习之------ 绘制角度可变的颜色渐变效果

GDI+ 是GDI(Windows 早期版本提供的图形设备接口)的后续版本,是Microsoft Windows XP作系统即后续版本的图形显示技术。它已经集成到了.Net开发环境中,所以不管你的OS...

十四:GDI+ 绘制窗口 感受不一样的神奇

第一:在stdafx.h中加上下列GDI的头文件#include "c:/GDIPlus/includes/gdiplus.h"   ////请修改为你的头文件路径using namespace Gd...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:GDI+的雷区
举报原因:
原因补充:

(最多只允许输入30个字)