您的位置:首页 > 运维架构 > Linux

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

2009-09-23 11:33 781 查看
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

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





#include <cairo.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gtk/gtk.h>
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐