透明

这一篇讲述有关透明的一些基本知识,并提供两个有趣的透明效果。

透明是透过某种材质的可见度。理解透明最简单的方式就是想像一下玻璃或者水。从技术上讲,光线可以穿过玻璃,因此我们可以看到玻璃之后的物体。

在计算机图形学中,可以使用alpha 混合 方式来实现透明效果。Alpha 混合,是通过将图像与背景组合实现部分透明的视觉效果。混合过程中使用了一种叫做 alpha 通道 的东西。Alpha 通道在图形文件格式中是一个 8 位的层,用于表示图片的透明性。每个像素所包含的这个各额外的 8 位数字提供了一个蒙板,可以表达 256 个层次的透明度。

透明的矩形

第一个例子,绘制了 10 个不同透明程度的矩形。


#include <cairo.h>
#include <gtk/gtk.h>

static gboolean
on_expose_event ( GtkWidget * widget,
                 GdkEventExpose * event, gpointer data)
{
        cairo_t *cr;

cr = gdk_cairo_create ( widget->window) ;

gint i;
        for ( i = 1 ; i <= 10 ; i++) {
                cairo_set_source_rgba ( cr, 0 , 0 , 1 , i * 0.1 ) ;
                cairo_rectangle ( cr, 50 * i, 20 , 40 , 40 ) ;
                cairo_fill ( cr) ;
        }

cairo_destroy ( cr) ;

return FALSE ;
}

int
main ( int argc, char *argv[ ] )
{
        GtkWidget *window;

gtk_init ( &argc, &argv) ;

window = gtk_window_new ( GTK_WINDOW_TOPLEVEL) ;

g_signal_connect ( G_OBJECT ( window) , "expose-event" ,
                          G_CALLBACK ( on_expose_event) , NULL ) ;
        g_signal_connect ( G_OBJECT ( window) , "destroy" ,
                          G_CALLBACK ( gtk_main_quit) , NULL ) ;

gtk_window_set_position ( GTK_WINDOW ( window) ,
                                 GTK_WIN_POS_CENTER) ;
        gtk_window_set_default_size ( GTK_WINDOW ( window) , 590 , 90 ) ;
        gtk_window_set_title ( GTK_WINDOW ( window) , "transparency" ) ;

gtk_widget_set_app_paintable ( window, TRUE ) ;
        gtk_widget_show_all ( window) ;

gtk_main ( ) ;

return 0 ;
}

cairo_set_source_rgba () 函数有一个可选的 alpha 参数,用于提供透明色支持。


gint i;
        for ( i = 1 ; i <= 10 ; i++) {
                cairo_set_source_rgba ( cr, 0 , 0 , 1 , i * 0.1 ) ;
                cairo_rectangle ( cr, 50 * i, 20 , 40 , 40 ) ;
                cairo_fill ( cr) ;
        }

这段代码创建 10 个矩形,其 alpha 值从 0.1 递增到 1。



淡出的效果

在下一个示例中,实现对一幅图片的淡出处理。这幅图片会逐渐变得越来越透明直至看不见。


#include <cairo.h>
#include <gtk/gtk.h>

cairo_surface_t *image;

static gboolean
on_expose_event ( GtkWidget * widget,
                 GdkEventExpose * event, gpointer data)
{
        cairo_t *cr;

cr = gdk_cairo_create ( widget->window) ;

static double alpha = 1 ;
        double const delta = 0.01 ;

cairo_set_source_surface ( cr, image, 10 , 10 ) ;
        cairo_paint_with_alpha ( cr, alpha) ;

alpha -= delta;

if ( alpha <= 0 )
                timer = FALSE ;

cairo_destroy ( cr) ;

return FALSE ;
}

static gboolean
time_handler ( GtkWidget * widget)
{
        if ( widget->window == NULL )
                return FALSE ;

gtk_widget_queue_draw ( widget) ;
        return TRUE ;
}

int
main ( int argc, char *argv[ ] )
{
        GtkWidget *window;
        GtkWidget *darea;

gint width, height;

image = cairo_image_surface_create_from_png ( "tuz.png" ) ;
        width = cairo_image_surface_get_width ( image) ;
        height = cairo_image_surface_get_height ( image) ;

gtk_init ( &argc, &argv) ;

window = gtk_window_new ( GTK_WINDOW_TOPLEVEL) ;

darea = gtk_drawing_area_new ( ) ;
        gtk_container_add ( GTK_CONTAINER ( window) , darea) ;

g_signal_connect ( darea, "expose-event" ,
                          G_CALLBACK ( on_expose_event) , NULL ) ;
        g_signal_connect ( window, "destroy" ,
                          G_CALLBACK ( gtk_main_quit) , NULL ) ;

gtk_window_set_position ( GTK_WINDOW ( window) ,
                                 GTK_WIN_POS_CENTER) ;
        gtk_window_set_default_size ( GTK_WINDOW ( window) , width + 20 ,
                                     height + 20 ) ;

gtk_window_set_title ( GTK_WINDOW ( window) , "fade out" ) ;
        g_timeout_add ( 50 , ( GSourceFunc) time_handler,
                       ( gpointer) window) ;
        gtk_widget_show_all ( window) ;

gtk_main ( ) ;

cairo_surface_destroy ( image) ;

return 0 ;
}

在这一示例中,显示了一幅渐渐淡出的图片。所使用的图片是 Linux kernel 的新 Logo,详见 LinuxToy 网站的介绍 。


image = cairo_image_surface_create_from_png ( "tuz.png" ) ;

出于对程序运行效率的考虑,图像外观的创建在主函数中进行。


cairo_set_source_surface ( cr, image, 10 , 10 ) ;

将载入的图片设置为源 (source)。


cairo_paint_with_alpha ( cr, alpha) ;

调用函数 cairo_paint_with_alpha () 来实现图片淡出效果,该函数使用透明度作为蒙板。


alpha -= delta;

在每次响应 expose 事件的处理过程中,进行透明度的值递减。


if ( alpha <= 0 )
                alpha = 1 ;

当透明度为 0 时,意味着图片是完全透明的。这时,再将透明度置为 1,即将图片复原为不透明状态。这样做的目的是让图片周而复始、痛不欲生的淡出着。


g_timeout_add ( 50 , ( GSourceFunc) time_handler, ( gpointer) window) ;

创建一个计时器,其回调函数为 time_handler (),每隔 50ms 便会被调用一次。


static gboolean
time_handler ( GtkWidget * widget)
{
        if ( widget->window == NULL )
                return FALSE ;

gtk_widget_queue_draw ( widget) ;
        return TRUE ;
}

time_handler () 函数的实现,它的主要作用是调用 gtk_widget_queue_draw () 函数,实现窗口的重绘 (发出 expose 事件)。当该函数返回值为 FALSE 时,计时器便停止工作。


if ( widget->window == NULL )
                return FALSE ;

这两行代码看上去有点多余。但是考虑在计时器的时间间隔很小的情况下 (譬如 5ms),如果关闭窗口,这时进程尚未完全销毁,不过窗口已经被 destroy 了。这时,这两行代码可以防止计时器回调函数继续工作而引起的程序崩溃。



“等待”的演示

下面的示例,使用透明效果制作了一个“等待”状态的演示,是通过绘制 8 条依次消隐淡出的线,模拟一条线的运动过程。像这样的效果通常被用于通知用户耐心地等待一个隐藏在屏幕之后漫长的任务的完成。在网上看视频时,经常可以看到类似的“等待”。

#include <cairo.h>
#include <gtk/gtk.h>
#include <math.h>

static gushort count = 0 ;

static gboolean
on_expose_event ( GtkWidget * widget,
                 GdkEventExpose * event, gpointer data)
{
        cairo_t *cr;

cr = gdk_cairo_create ( widget->window) ;

static gdouble const trs[ 8 ] [ 8 ] = {
                { 0.0 , 0.15 , 0.30 , 0.5 , 0.65 , 0.80 , 0.9 , 1.0 } ,
                { 1.0 , 0.0 , 0.15 , 0.30 , 0.5 , 0.65 , 0.8 , 0.9 } ,
                { 0.9 , 1.0 , 0.0 , 0.15 , 0.3 , 0.5 , 0.65 , 0.8 } ,
                { 0.8 , 0.9 , 1.0 , 0.0 , 0.15 , 0.3 , 0.5 , 0.65 } ,
                { 0.65 , 0.8 , 0.9 , 1.0 , 0.0 , 0.15 , 0.3 , 0.5 } ,
                { 0.5 , 0.65 , 0.8 , 0.9 , 1.0 , 0.0 , 0.15 , 0.3 } ,
                { 0.3 , 0.5 , 0.65 , 0.8 , 0.9 , 1.0 , 0.0 , 0.15 } ,
                { 0.15 , 0.3 , 0.5 , 0.65 , 0.8 , 0.9 , 1.0 , 0.0 ,}
        } ;

gint width, height;
        gtk_window_get_size ( GTK_WINDOW ( widget) , &width, &height) ;

cairo_translate ( cr, width / 2 , height / 2 ) ;

gint i = 0 ;
        for ( i = 0 ; i < 8 ; i++) {
                cairo_set_line_width ( cr, 3 ) ;
                cairo_set_line_cap ( cr, CAIRO_LINE_CAP_ROUND) ;
                cairo_set_source_rgba ( cr, 0 , 0 , 0 , trs[ count % 8 ] [ i] ) ;

cairo_move_to ( cr, 0.0 , -10.0 ) ;
                cairo_line_to ( cr, 0.0 , -40.0 ) ;
                cairo_rotate ( cr, M_PI / 4 ) ;

cairo_stroke ( cr) ;
        }

cairo_destroy ( cr) ;

return FALSE ;
}

static gboolean
time_handler ( GtkWidget * widget)
{
        count += 1 ;
        gtk_widget_queue_draw ( widget) ;
        return TRUE ;
}

int
main ( int argc, char *argv[ ] )
{
        GtkWidget *window;
        GtkWidget *darea;

gtk_init ( &argc, &argv) ;

window = gtk_window_new ( GTK_WINDOW_TOPLEVEL) ;

g_signal_connect ( G_OBJECT ( window) , "expose-event" ,
                          G_CALLBACK ( on_expose_event) , NULL ) ;
        g_signal_connect ( G_OBJECT ( window) , "destroy" ,
                          G_CALLBACK ( gtk_main_quit) , NULL ) ;

gtk_window_set_position ( GTK_WINDOW ( window) ,
                                 GTK_WIN_POS_CENTER) ;
        gtk_window_set_default_size ( GTK_WINDOW ( window) , 250 , 150 ) ;

gtk_window_set_title ( GTK_WINDOW ( window) , "waiting demo" ) ;

gtk_widget_set_app_paintable ( window, TRUE ) ;
        gtk_widget_show_all ( window) ;
        g_timeout_add ( 100 , ( GSourceFunc) time_handler,
                       ( gpointer) window) ;

gtk_main ( ) ;

return 0 ;
}

方法比较笨,就是绘制 8 条不同透明度的线。


static gdouble const trs[ 8 ] [ 8 ] = {
                { 0.0 , 0.15 , 0.30 , 0.5 , 0.65 , 0.80 , 0.9 , 1.0 } ,
                { 1.0 , 0.0 , 0.15 , 0.30 , 0.5 , 0.65 , 0.8 , 0.9 } ,
                { 0.9 , 1.0 , 0.0 , 0.15 , 0.3 , 0.5 , 0.65 , 0.8 } ,
                { 0.8 , 0.9 , 1.0 , 0.0 , 0.15 , 0.3 , 0.5 , 0.65 } ,
                { 0.65 , 0.8 , 0.9 , 1.0 , 0.0 , 0.15 , 0.3 , 0.5 } ,
                { 0.5 , 0.65 , 0.8 , 0.9 , 1.0 , 0.0 , 0.15 , 0.3 } ,
                { 0.3 , 0.5 , 0.65 , 0.8 , 0.9 , 1.0 , 0.0 , 0.15 } ,
                { 0.15 , 0.3 , 0.5 , 0.65 , 0.8 , 0.9 , 1.0 , 0.0 ,}
        } ;

这 8 条线的透明度就是这样被活生生地定义出来的,每一行表示一条线的透明度候选集。


cairo_set_line_width ( cr, 3 ) ;
                cairo_set_line_cap ( cr, CAIRO_LINE_CAP_ROUND) ;

设置线宽与线帽。


cairo_set_source_rgba ( cr, 0 , 0 , 0 , trs[ count % 8 ] [ i] ) ;

每条线的透明度就是这样活生生地变化出来的。


cairo_move_to ( cr, 0.0 , -10.0 ) ;
                cairo_line_to ( cr, 0.0 , -40.0 ) ;
                cairo_rotate ( cr, M_PI / 4 ) ;

这里有个从未讲过的技巧,就是 cairo 的旋转变换。每次都在前一次旋转的基础上继续逆时针旋转 角度。这样,8 次循环之后,恰好绕了一圈。


g_timeout_add ( 100 , ( GSourceFunc) time_handler, ( gpointer) window) ;

又是计时器。


Cairo图形指南(6)相关推荐

  1. Cairo 图形指南 (5) —— 形状与填充

    这一部分,讲述一些基本的以及较为高级的形状绘制及其纯色 (solid color).图案 (pattern) 与渐变 (gradient) 填充方法. 基本形状 Cairo 提供了几个用于绘制基本形状 ...

  2. [转载]Cairo 图形指南[转载]

    Cairo 图形指南 (1) -- 简介 欢迎阅读 Cairo 绘图指南,这份指南会向你讲述 Cairo 二维矢量绘图库的基本知识以及一些高级问题.指南中的示例采用 C 语言实现,其中大部分使用了 G ...

  3. cairo填充_Cairo图形指南

    Cairo 图形指南 (1) -- 简介 欢迎阅读 Cairo 绘图指南, 这份指南会向你讲述 Cairo 二维矢量绘图库的基本 知识以及一些高级问题.指南中的示例采用 C 语言实现,其中大部分使用了 ...

  4. cairo填充_Cairo 图形指南 (5) —— 形状与填充

    这一部分,讲述一些基本的以及较为高级的形状绘制及其纯色 (solid color).图案 (pattern) 与渐变 (gradient) 填充方法. 基本形状 Cairo 提供了几个用于绘制基本形状 ...

  5. 随机森林算法的随机性_理解随机森林算法的图形指南

    随机森林算法的随机性 本文是关于什么的 (What this article is about) In this article , we will see how the Random Forest ...

  6. 使用cairo和freetype进行字体布局和渲染

    使用cairo和freetype进行字体布局和渲染 | https://qa.1r1g.com/sf/ask/2568859961/# 以下示例将输入字符串转换为字形,检索其范围并进行渲染: cons ...

  7. 深度学习中的遥感影像数据集~持续更新

    收集网络上公开的遥感数据集,欢迎补充 以下数据集均为网上开源数据集,若有遗误或不慎涉及侵权,烦请评论或留言联系 目前本项目共整理 场景分类数据集27个(整理完结): 目标检测数据集31+个(整理完结) ...

  8. 00002__C++矢量图形库

    00002__C++矢量图形库 一.图形库简介 图形库 所用的语言 支持平台 特点 网址 agg c++ 跨平台 免费 http://www.antigrain.com/ cairo c 跨平台 免费 ...

  9. 用 cairo 实现跨平台图形

    Table of Contents cairo 的优点和用途 为什么要学习一种新的绘图模型? cairo 呈现目标 cairo 的实际应用情况 用 cairo 进行概念性绘图 正确的 cairo 术语 ...

最新文章

  1. 以太坊数据结构MPT
  2. 虚拟化正是云计算所依托的基石
  3. swagger2中UI界面接口点击无法展开问题解决
  4. 【JUC并发编程06】多线程锁 (公平锁和非公平锁,死锁,可重锁)
  5. Python基础案例(一)
  6. Python1 安装和配置
  7. 三维旋转矩阵_第三讲:三维空间的刚体运动
  8. 【DataMagic】如何在万亿级别规模的数据量上使用Spark
  9. mysql数据库工程师考证题_100道MySQL常见面试题总结
  10. 基于SSM的疫情数据统计分析系统
  11. 通过对i8042 键盘控制器编程控制鼠标
  12. CNNVD与CVE对齐
  13. B站 - 黑客攻防 入门到入狱 [网络安全] -笔记
  14. RoboWare 下载地址
  15. js 计算当前时间到下个整点时间,差多少分钟,多少秒
  16. python之windrose风向玫瑰图的用法
  17. 【GCC】warning: pointer targets in passing argument 1 of 'strlen' differ in signedness
  18. ODC20:更开放的行业解决方案,进击的OPPO IoT生态与云能力
  19. Linux进程间通信信号量
  20. OpenStack网络指南(17)IPAM配置

热门文章

  1. streamx平台部署
  2. python加密狗的制作_如何使用U盘制作Windows系统开机加密狗图文教程
  3. PDF编辑器技巧之PDF删除其中一页
  4. 百度地图花屏解决方案
  5. osgEarth示例分析——osgearth_elevation
  6. Anaconda => PyCharm => CUDA => cudnn => PyTorch 环境配置
  7. 美妆护肤做短视频,利用选题策划来涨粉?
  8. 4.2.1 Duration and Convexity
  9. 已成功与服务器建立连接,但是在登录前的握手期间发生错误
  10. ffmpeg安装教程(windows版)