由GdkPixmap得到透明的GdkPixbuf
GdkPixmap是GdkDrawable的子類。GdkDrawable和Win32下的DC(DeviceContext)有點類似,你可以在上面畫直線、畫圓或者在上面貼圖檔。DC有很多不同的子類,最常見的有記憶體DC,列印機DC,螢幕DC。同樣,GdkDrawable也有很多子類,非要和Win32對應起來的話,GdkPixmap的地位和記憶體DC差不多。
GdkPixbuf的功能近似于位圖(bitmap),但一般僅限于在記憶體使用中,沒有定義特定的存儲格式。可以把任意格式的圖檔檔案加裁到一個GdkPixbuf中; 可以把GdkPixbuf貼到GdkDrawable任意子類的對象上; 也可以把GdkDrawable任意子類的對象轉換成GdkPixbuf對象,然後把GdkPixbuf對象存為指定格式的圖檔檔案。
GTK+提供了幾個函數在這兩者之間轉換:
gdk_draw_pixbuf 把GdkPixbuf對象貼到GdkDrawable對象上。
gdk_pixbuf_get_from_drawable 從GdkDrawable對象中得到GdkPixbuf對象。
GdkPixbuf是GdkDrawable的子類,這兩個函數自然也适用于GdkPixmap。
最近遇到一個問題,盡管我指明要透明的GdkPixbuf,通過gdk_pixbuf_get_from_drawable得到的GdkPixbuf仍然是不透明的。
GdkPixbuf有一個has_alpha屬性,它是控制GdkPixbuf透明與否的第一關。隻能在建立時設定它(gdk_pixbuf_new),對于已經存在的GdkPixbuf對象,不能再修改它的has_alpha屬性。
對于透明的GdkPixbuf,每個像素在記憶體中占四個位元組,也即R(紅)、G(綠)、B(藍)三基色各占一個位元組,alpha占一個位元組。利用alpha的值可以實作(半)透明效果,alpha的值為0則完全透明,alpha的值為255則完全不透明,中間的值為半透明。
我發現通過gdk_pixbuf_get_from_drawable得到的GdkPixbuf是完全不透明的,從記憶體中的值可以看到每個像素的alpha值都為255,而且沒有任何參數可以控制gdk_pixbuf_get_from_drawable處理透明問題的行為。
把GTK+提供的相關函數翻了個遍,也沒有找到把GdkPixbuf轉換為透明效果GdkPixbuf的函數,最後隻好自己寫了一個,它的缺點是隻能指定一種透明色,所有為這種透明色的pixel都是作透明處理。不過,這對正常應用沒有什麼影響。
void
gdk_pixbuf_transparent (GdkPixbuf *pixbuf, guint32 pixel)
{
guchar *pixels;
guint r, g, b, a;
guchar *p;
guint w, h;
g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
if (pixbuf->width == 0 || pixbuf->height == 0)
return;
pixels = pixbuf->pixels;
r = (pixel & 0xff000000) >> 24;
g = (pixel & 0x00ff0000) >> 16;
b = (pixel & 0x0000ff00) >> 8;
a = (pixel & 0x000000ff);
h = pixbuf->height;
while (h--) {
w = pixbuf->width;
p = pixels;
switch (pixbuf->n_channels) {
case 4:
while (w--) {
if(p[0] == r && p[1] == g && p[2] == b)
{
p[3] = a;
}
p += 4;
}
break;
default:
}
pixels += pixbuf->rowstride;
}
return;
}
使用方法:
把黑色設定為透明色:gdk_pixbuf_transparent(pixbuf, 0x00000000); 把白色設定為透明色:gdk_pixbuf_transparent(pixbuf, 0xFFFFFF00); 把紅色設定為透明色:gdk_pixbuf_transparent(pixbuf, 0xFF000000); 把綠色設定為透明色:gdk_pixbuf_transparent(pixbuf, 0x00FF0000); 把藍色設定為透明色:gdk_pixbuf_transparent(pixbuf, 0x0000FF00);