最近要在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仿射变换
仿射平面(或空间)到自身的一类变换,最重要的性质是保持点的共线性(或共面性)以及保持直线的平行性。通常在图像处理中的旋转、缩放、切变、反射以及正投影。