前天在博客上說希望開發一個盡量獨立于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) 閱讀(4392)
評論(13) 編輯 收藏 引用 所屬分類:
其他