前天在博客上说希望开发一个尽量独立于GDI的图形库。这个图形库将不使用其他图形库例如GDI+、OpenGL以及DirectX等。图形库使用GDI的原因如下:
1:字体的边框比较难获得。直接读TTF文件暂时还不想做,因此想借助GDI的API获取文字的Bezier轮廓。
2:不使用GDI无法把图片刷上窗口。
因此这个图形库使用的GDI的功能也仅限于此。当然,开发出来的结果必然是GDI所不能达到的。GDI+的结构也稍微有一点点不理想。
为什么GDI和GDI+的速度都不太理想呢?下面的分析将会给出一个可能的解释。
今天早上考了软件配置管理,也就是让我们了解一下为什么需要Subversion这样的软件来帮助我们开发软件。考完试回来的路上就构思了这个图形库的结构。让我们考虑一下图形库所需的功能,也就是需求分析了。我们用惯的图形库都有绘制图形、文字以及图像的功能。图形有画刷和边框,其中边框是具有形状的。
首先考虑一下文字。我们知道现在绝大多数的文字都是由Bezier边框构成的,虽然这种图形是镶嵌图形(也就是有孔),不过孔不是什么大问题。我们拿到了文字的Bezier边框之后,就可以将文字转换为几何图形了。于是实际上只需要绘制图形和图像就够了,外加一个
获取边框的程序。
其次,绘制图像实际上也是使用一个跟边框有关系的画刷去绘制一个矩形而已。所以,绘制图像的时候,我们需要
创建一个几何图形以及相匹配的设置的画刷。
再者,让我们考虑以下图形。我们知道,图形由边框和内部构成,这两个部分都是可选的。边框有填充物、有线条类型(实线虚线等)、有线条的边界形状以及宽度等设置。那么,图形的边框通过这些设置就可以转化为一个或多个几何形状和填充物。于是,我们只需要一个
将边框转换为几何图形的程序就可以将边框也去掉了,剩下的就是使用画刷填充几何图形。
那么,几何图形就是由直线、弧线、Bezier曲线以及其他线条方程组成了。这个就跟架构无关了,只需要解决相应的数学问题就行了。剩下的就是画刷的问题。我们知道画刷有若干类型,譬如单调颜色、渐变以及图像等。渐变分两种,一种是跟绘制的几何图形有关的,另一种是跟绘制的几何图形无关的。于是我们在使用跟绘制的几何图形有关的画刷的时候,我们可以
创建一个根据某种几何图形渐变的画刷,并且让这个几何图形跟被绘制的几何图形相同,从而可以去掉『跟绘制的几何图形有关的画刷』了。
于是画刷就只有一种属性了,也就是通过坐标来获取颜色。因为这个时候画刷已经跟被绘制的几何图形无关了。于是到了这里,我们很容易联想到多态。使用一个接口包含『坐标返回颜色』的函数,就可以填充几何图形了。但是这样做是不好的,因为一个几何图形有成千上万个点,调用这么多次虚函数是会严重影响效率的。所以填充几何图形这种工作应该完全由画刷负责。那么我们如何多态呢?实际上可以这样。
我们定义一个接口,给出几何图形然后绘制。然后继承一个类出来,这个类是模板类。模板类传入一个参数用于决定如何通过坐标返回颜色。因为画刷跟被绘制的几何图形无关,所以可以这么做。这个时候,我们就可以把填充跟获取颜色分开了,但是编译的时候仍然会让他们结合在一起。所以无论几何图形有多大,调用的虚函数也就是一次。
好了,到了这里,一个图形库实际上就是由
通过一定模式填充几何图形的函数,加上构造几何图形以及画刷的各种各样功能强大的周边函数组成。
那么考虑到这里,我们如何根据一个点获取颜色呢?单调颜色非常好处理,无论如何都返回这个颜色。渐变的话,根据复杂的几何图形渐变仍需考虑一下好用的算法,根据直线、方框以及椭圆等
凸多边形渐变实际上是相当简单的。剩下的就是根据图像来获取颜色了。根据图像获取颜色有几个需要考虑的问题。第一个是超出图像的部分如何处理,这个比较好办,要么就返回一个颜色,要么就不填充,要么就让图像堆砌起来。第二个问题就是根据被绘制的点经过变换到图像上的点的时候,这个点可能不是整数。这个时候我们可以寻找临近的点的颜色,或者根据缩放尺度来计算若干点的颜色的加权平均值。当然第二种是比较逼真同时也比较慢的。
剩下的一个问题就是反锯齿效果了。这个不用过多解释,实际上也有非常多的办法来解决,在框架没有定下来之前讨论这个是没有意义的。因为图形库实际上是支持Alpha通道的,所以并没有什么技术上过于困难的地方。
图形我们就完全解决了,现在开始图像的问题。我们仍然可以通过修改
通过点获取颜色的程序来实现调整一个图像的对比度啊、亮度啊、甚至执行一些模糊锐化边缘化等处理。我们甚至可以借用OpenGL的Color Matrix这种概念来执行一些比较简单的线性颜色变换。这些效果实际上只需要慢慢添加进去就可以了,不过如何将多态的损耗减至最小仍然需要考虑。
如果以上的讨论所涉及到的问题全部解决的话,我们可以得到一个跟GDI+一样,甚至是更加强大的图形库。好了,现在讨论一下为什么GDI和GDI+的速度都比较慢。我们可能经常会重复绘制一些没有任何变化的、具有复杂画笔的几何图形。通过画笔构造边框的轮廓是一件复杂的工作,我们使用GDI和GDI+就会在每一次绘制的时候重复计算这些东西了。不过由于GDI和GDI+的接口过于友好,我们无法干预这件事情。所以效率下降就是必然的了。而且绘制文字等价于填充几何图形,因此也是如此。GDI+唯一一个比较快的就是图像处理了,因为它的图像处理并不是通过本文讲述的转嫁到画刷的办法来实现的。当然,如何打开和保存各种格式的图片文件的事情就暂缓处理了,这根图形库本身是无关的。至于到时候这个图形库所展现出来的接口是如何的?我想仍然会有画笔啊画刷啊这种概念的,只不过会复杂一点,为了解决上面所说的问题也会繁琐一点。
图形库,仅仅是数学问题而已。
posted on 2008-06-10 19:13
陈梓瀚(vczh) 阅读(4370)
评论(13) 编辑 收藏 引用 所属分类:
其他