在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
以下是代码实例,例子中用到的两张图片在这里:
![](http://p.blog.csdn.net/images/p_blog_csdn_net/aishen944/EntryImages/20090923/bk.png)
![](http://p.blog.csdn.net/images/p_blog_csdn_net/aishen944/EntryImages/20090923/football.png)
转贴请注明出处,谢谢!!
其实透明贴图的原理就是进行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
以下是代码实例,例子中用到的两张图片在这里:
![](http://p.blog.csdn.net/images/p_blog_csdn_net/aishen944/EntryImages/20090923/bk.png)
![](http://p.blog.csdn.net/images/p_blog_csdn_net/aishen944/EntryImages/20090923/football.png)
#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; }
相关文章推荐
- 使用Samba实现Windows与Linux主机之间文件共享
- 使用cwRsync实现Windows/Linux间文件同步
- 在Linux中实现类似windows中获取配置文 件的函数GetProfileString
- 安装、设置和使用SSH Secure shell 实现windows 登录linux
- virtualbox中linux系统使用samba服务实现和windows系统共享
- 23 使用 cygwin X server实现Linux远程桌面 (for windows)
- 使用samba实现VMWARE 中 LINUX 与宿主机 WINDOWS的文件共享
- 使用VNC实现LINUX与windows的相互远程控制
- C++学习:使用libssh2实现交互式shell的ssh2,linux和windows通用
- 使用java实现windows与linux之间的文件传输
- 在ThreeJS中使用PNG实现透明贴图效果
- Windows使用SSH Secure Shell实现免密码登录Linux的方法以及使用scp2命令免密码下载文件
- Linux管理工作,实例讲解工作中使用ssh证书登录的实际流程,讲解ssh证书登录的配置原理,基于配置原理,解决实际工作中,windows下使用SecureCRT证书登录的各种问题,以及实现hadoo
- 学习在linux和windows安装GSL和使用,编译 链接 和makefile的撰写和实现
- 使用samba实现linux,windows间文件共享
- Windows 8 DirectX 开发学习笔记(十五)使用Billboard实现树木贴图
- 电脑(Linux/Windows)使用SSH远程登录安卓(Android)手机实现无线传输和管理文件(图文详解)
- 树莓派-使用xrdp实现windows 远程桌面linux
- 使用putty从windows下访问Linux 使用pscp实现windows与linux间传递文件
- linux中rz, sz命令的安装与使用------实现Windows与linux文件的快捷互传