最近要在Linux手持設備上優化一個圖形的程序,被迫去學習Gnome Canvas。
1、有了GTK,爲什麼還要GnomeCanvas?
GnomeCanvas 是一個強大的、高級API的、高圖形渲染性能的圖形渲染引擎,提供豐富的圖像功能。GnomeCanvas使用兩種可選圖形渲染後端(rendering back-ends)。第一種是XLIB,實現快速圖像顯示,另一種基於Libart類庫,優秀成熟、反抖動,並支持alpha-compositing。GnomeCanvas由於血緣關係,能夠和GTK程序幾乎是無縫的融合。由於我們的程序需要使用圖像的運動過程中的縮放功能,爲了更快的顯示速度,我決定考慮一下使用GnomeCanvas進行優化,並測試。
2、有GnomeCanvas類似的類庫?
有,gEvas,http://www.linuxjournal.com/article/8213中說“Evas library provides a canvas for quickly rendering raster graphics with alpha blending support.” “gEvas is a wrapper and glue library built to allow Evas to be used from GTK+2.x applications easily.” 並有gEvas和gnomecanvas的一些對比測試。 我想等我搞清楚了GnomeCanvas,有餘力再看看gEvas,也對比測試一把,學無止境呀,青春苦短,時間太瘦,指縫太寬。
3、基礎概念
當初沒有系統學習,拿着個例子就勇往直前,以爲能夠輕鬆搞定。只是我在圖像處理的開發經驗不夠,看着一堆的affine、alpha、world coordinates、 canvas coordinates、item coordinates終於暈了。詩人里爾克說:誰此時孤獨,就永遠孤獨。我想到的是:誰此時不懂,就永遠不懂.......
3.1 圖像的alpha通道
Alpha其實是一個決定混合透明度的數值,抄一段網上的說明:假設一幅圖象是A,另一幅透明的圖象是B,那麼透過B去看A,看上去的圖象C就是B和A的混合圖象。
Gnome/GTK程序一般使用GdkPixbuf把圖像數據保存在內存,當圖像格式在GdkPixbuf表示成RGBA/RGB兩種格式的時候,A值就是透明度。GdkPixbuf中數據不一定含有alpha,例如:如果GdkPixbuf數據從jpg文件讀入,是不含alpha通道的,但是從png文件讀入,則包含alpha值。使用下面的代碼行判斷GdkPixbuf是否包含alpha通道。
g_assert (gdk_pixbuf_get_colorspace (pixbuf) == GDK_COLORSPACE_RGB);
g_assert (gdk_pixbuf_get_bits_per_sample (pixbuf) == 8);
g_assert (gdk_pixbuf_get_has_alpha (pixbuf));
g_assert (gdk_pixbuf_get_n_channels (pixbuf) == 4);
直接操作GdkPixbuf的指針可以修改圖像上任何一點的alpha值
例如:
guchar *pixels;
pixels = gdk_pixbuf_get_pixels (pixbuf);
for (xindex=0;xindex<width;xindex++){
for(yindex=0;yindex<height;yindex++){
p = pixels + yindex * rowstride + xindex * n_channels;
p[3] =0x2F ;
}
}
alpha的取值範圍:(0-255, 0=completely transparent, 255=opaque)
3.2GnomeCanvas、GnomeCanvasItem、與GTK的控件的關係 。
首先,GnomeCanvas類庫也是GObject的血統,與GTK可以說是同源。
GnomeCanvas是一個“畫布”對象(GObject的對象,與CPP對象不同),同時,GnomeCanvas 是一種GtkWidget *,可以放到GTK的容器中。畫布上面的繪畫對象是GnomeCanvasItem,例如GnomeCanvasPixbuf 是圖像的對象,GnomeCanvasText 則是文本對象,
GnomeCanvasPolygon是多邊形的對象。GnomeCanvasItem只包含操作對象的方法,各種GnomeCanvasItem子類基本上只定義額外負擔了的屬性。例如GnomeCanvasPixbuf,並未定義額外的操作方法,只定義了下面這些屬性:
"anchor" GtkAnchorType : Read / Write
"height" gdouble : Read / Write
"height-in-pixels" gboolean : Read / Write
"height-set" gboolean : Read / Write
"pixbuf" GdkPixbuf* : Read / Write
"width" gdouble : Read / Write
"width-in-pixels" gboolean : Read / Write
"width-set" gboolean : Read / Write
"x" gdouble : Read / Write
"x-in-pixels" gboolean : Read / Write
"y" gdouble : Read / Write
"y-in-pixels" gboolean : Read / Write
有趣的是GnomeCanvas定義了命名爲GnomeCanvasWidget的GnomeCanvasItem,用以在畫布上嵌入GTK的對象。當然,還有一種用途,就是畫布對象中嵌入“子畫布”。
3.3 座標變換
world coordinates相當於Window OS下圖形編程的世界座標,是一種無限的、抽象的、邏輯的座標。世界座標使用雙精度浮點數表示。畫屏的時候使用畫布像素座標,該座標叫做canvas coordinates,使用整數來指定像素位置。畫布上每一個元素都有自身的系統座標,該座標叫做item coordinates。item coordinates是一種相對的world coordinates,相對於與本元素左上腳的點的座標值,左上腳的點爲(0.0,0.0)。
下面描述的方法來自GnomeCanvas的定義。gnome_canvas_w2c()完成從world coordinates到canvas coordinates的轉換,gnome_canvas_c2w()則完成反向轉換。gnome_canvas_w2c_affine(GnomeCanvas *canvas,double affine[6])獲取從world coordinates到canvas coordinates的轉換的仿射變換矩陣。gnome_canvas_w2c_d()和gnome_canvas_w2c()類似,但是以dbouble的類型返回canvas coordinates(避免返回整形時導致的精度丟失)。gnome_canvas_set_pixels_per_unit()能夠設置畫布的縮放比例(每個世界座標單元的畫布像素個數),當設置成1.0的時候兩者是一一對應的,例如[5, 6] 像素單元 在世界座標中則是 [5.0, 6.0]。
3.4仿射變換
仿射平面(或空間)到自身的一類變換,最重要的性質是保持點的共線性(或共面性)以及保持直線的平行性。通常在圖像處理中的旋轉、縮放、切變、反射以及正投影。