在linux下使用gtk的gdk-pixbuf实现类似windows下的透明贴图

aishen944-163.com

转贴请注明出处,谢谢!!

 

 

其实透明贴图的原理就是进行xor运算,

 

基本公式:A  xor A = 0    A xor 0 = A   A xor A xor B  = B

 

假如现在有两张图片,一张是我们要对其进行贴图的图片A, 另外一张是要被贴图的图片B

 

1, 复制图片B的一份拷贝为C

2, 将C中指定的背景色变为全白(0xffffff),其他颜色变为全黑(0x00)

3,     依次执行如下运算:

        A  xor B

        A  and C

        A  xor B

 

        对于C中的白色执行运算后的结果如下:

        ((A xor B) and 0xfffffff) xor B =  A xor B xor B =  A

 

        对于C中的黑色执行运算后的结果如下:

        ((A xor B) and 0x0000) xor B =  0 xor B = B

 

 

以下是代码实例,例子中用到的两张图片在这里:

在linux下使用gtk的gdk-pixbuf实现类似windows下的透明贴图_第1张图片

 

在linux下使用gtk的gdk-pixbuf实现类似windows下的透明贴图_第2张图片

 

 

#include #include #include static GdkPixbuf *bkpixbuf; static GdkPixbuf *footballpixbuf; static gboolean on_expose_event (GtkWidget * widget, GdkEventExpose * event, gpointer data) { cairo_t *cr; cr = gdk_cairo_create (widget->window); gdk_cairo_set_source_pixbuf(cr, bkpixbuf, 0, 0); cairo_paint(cr); cairo_destroy (cr); return FALSE; } gboolean blttransparent(GdkPixbuf *dest, const GdkPixbuf *src, gint destx, gint desty, guint transcolor) { GdkPixbuf *maskpixbuf = NULL; /* 蒙板 */ guchar *p = NULL, *dp = NULL, *sp = NULL; gint x = 0, y = 0, i = 0; /* 检查目的区域 */ if(destx + gdk_pixbuf_get_width(src) >= gdk_pixbuf_get_width(dest) || desty + gdk_pixbuf_get_height(src) >= gdk_pixbuf_get_height(dest)) { /* 超出目的大小, 什么也不做 */ return TRUE; } /* 检查颜色采样数 */ if(gdk_pixbuf_get_bits_per_sample(dest) != 8 || gdk_pixbuf_get_bits_per_sample(src) != 8) { // 只支持8位采样 return FALSE; } /* 检查通道数 */ if(gdk_pixbuf_get_n_channels(dest) != gdk_pixbuf_get_n_channels(src)) { /* 源和目的通道数必须相同 */ return FALSE; } if((i = gdk_pixbuf_get_n_channels(dest)) != 3 && i != 4) { // 只支持RGB和RGBA模式 return FALSE; } /* 分解要透明转换的颜色值 */ guchar clrr = (guchar)(transcolor >> 24); guchar clrg = (guchar)((transcolor >> 16) & 0x000000ff); guchar clrb = (guchar)(transcolor & 0x000000ff); /* 生成黑白蒙板 */ maskpixbuf = gdk_pixbuf_copy(src); for(y = 0; y < gdk_pixbuf_get_height(src); ++y) { for(x = 0; x < gdk_pixbuf_get_width(src); ++x) { p = gdk_pixbuf_get_pixels(maskpixbuf) + y * gdk_pixbuf_get_rowstride(maskpixbuf) + x * gdk_pixbuf_get_n_channels(maskpixbuf); if(p[0] == clrr && p[1] == clrg && p[2] == clrb) { p[0] = 0xff; p[1] = 0xff; p[2] = 0xff; } else { p[0] = 0x00; p[1] = 0x00; p[2] = 0x00; } } } /* 应用蒙板 */ const GdkPixbuf *tmp = NULL; const GdkPixbuf *compositePixbufs[] = {src, maskpixbuf, src}; for(i = 0; i < sizeof(compositePixbufs) / sizeof(GdkPixbuf*); ++i) { /* for begin 1 */ tmp = compositePixbufs[i]; for(y = 0; y < gdk_pixbuf_get_height(tmp); ++y) { /* for begin 2 */ for(x = 0; x < gdk_pixbuf_get_width(tmp); ++x) { dp = gdk_pixbuf_get_pixels(dest) + (y + desty) * gdk_pixbuf_get_rowstride(dest) + (x + destx) * gdk_pixbuf_get_n_channels(dest); sp = gdk_pixbuf_get_pixels(tmp) + y * gdk_pixbuf_get_rowstride(tmp) + x * gdk_pixbuf_get_n_channels(tmp); switch(i) { case 0: case 2: dp[0] ^= sp[0]; dp[1] ^= sp[1]; dp[2] ^= sp[2]; break; case 1: dp[0] &= sp[0]; dp[1] &= sp[1]; dp[2] &= sp[2]; default: break; } if(gdk_pixbuf_get_n_channels(dest) == 4) { dp[3] = sp[3]; } } } /* for begin 2 */ } /* for begin 1 */ g_object_unref(G_OBJECT(maskpixbuf)); return TRUE; } int main (int argc, char *argv[]) { GtkWidget *window; gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); g_signal_connect (window, "expose-event", G_CALLBACK (on_expose_event), NULL); g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL); bkpixbuf = gdk_pixbuf_new_from_file("./bk.png", NULL); footballpixbuf = gdk_pixbuf_new_from_file("./football.png", NULL); blttransparent(bkpixbuf, footballpixbuf, 0, 30, 0x0000ff); gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER); gtk_window_set_default_size (GTK_WINDOW (window), 510, 120); gtk_widget_set_app_paintable (window, TRUE); gtk_widget_show_all (window); gtk_main (); return 0; }

 

 

你可能感兴趣的:(gtk+,编程)