Cairo 图形指南 (8) —— 裁剪与遮蔽

在这一篇中讲述裁剪(Clipping)与遮蔽(Masking)。

在下面的示例中,对一幅图像进行裁剪。

01. #include <cairo.h>
02. #include <gtk/gtk.h>
03. #include <math.h>
04.  
05. cairo_surface_t *image;
06.  
07. static gboolean
08. on_expose_event(GtkWidget *widget,
09.      GdkEventExpose *event,
10.      gpointer data)
11. {
12.    cairo_t *cr;
13.  
14.    static gint pos_x = 128;
15.    static gint pos_y = 128;
16.    gint radius = 40; 
17.  
18.    static gint delta[] = { 3, 3 };
19.  
20.    cr = gdk_cairo_create(widget->window);
21.  
22.    gint width, height;
23.    gtk_window_get_size(GTK_WINDOW(widget), &width, &height);
24.  
25.    if (pos_x < 0 + radius) {
26.        delta[0] = rand () % 4 + 5;
27.    } else if (pos_x > width - radius) {
28.        delta[0] = -( rand () % 4 + 5);
29.    }
30.  
31.    if (pos_y < 0 + radius) {
32.        delta[1] = rand () % 4 + 5;
33.    } else if (pos_y > height - radius) {
34.        delta[1] = -( rand () % 4 + 5);
35.    }
36.  
37.    pos_x += delta[0];
38.    pos_y += delta[1];
39.  
40.    cairo_set_source_surface(cr, image, 1, 1);
41.    cairo_arc(cr, pos_x, pos_y, radius, 0, 2*M_PI);
42.    cairo_clip(cr);
43.    cairo_paint(cr);
44.  
45.    cairo_destroy(cr);
46.  
47.    return FALSE;
48. }
49.  
50. static gboolean
51. time_handler (GtkWidget *widget)
52. {
53.    if (widget->window == NULL) return FALSE;
54.    gtk_widget_queue_draw(widget);
55.    return TRUE;
56. }
57.  
58. int main( int argc, char *argv[])
59. {
60.    GtkWidget *window;
61.    gint width, height; 
62.  
63.    image = cairo_image_surface_create_from_png( "turnacastle.png" );
64.    width = cairo_image_surface_get_width(image);
65.    height = cairo_image_surface_get_height(image);
66.  
67.  
68.    gtk_init(&argc, &argv);
69.  
70.    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
71.  
72.    g_signal_connect(G_OBJECT(window), "expose-event" ,
73.        G_CALLBACK(on_expose_event), NULL);
74.    g_signal_connect(G_OBJECT(window), "destroy" ,
75.        G_CALLBACK(gtk_main_quit), NULL);
76.  
77.    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
78.    gtk_window_set_default_size(GTK_WINDOW(window), width+2, height+2);
79.  
80.    gtk_widget_set_app_paintable(window, TRUE);
81.    gtk_widget_show_all(window);
82.    g_timeout_add(100, (GSourceFunc) time_handler, (gpointer) window);
83.  
84.    gtk_main();
85.  
86.    cairo_surface_destroy(image);
87.  
88.    return 0;
89. }

在这一示例中,在窗口中会有一个圆形区域不断移动,并且在该区域显示位于其下的图像,仿佛是通过一个孔洞观看图像。

1. if (pos_x < 0 + radius) {
2.      delta[0] = rand () % 4 + 5;
3. } else if (pos_x > width - radius) {
4.      delta[0] = -( rand () % 4 + 5);
5. }

当这个圆形区域碰到窗口边界,它的移动方向就会随机改变。

1. cairo_set_source_surface(cr, image, 1, 1);
2. cairo_arc(cr, pos_x, pos_y, radius, 0, 2*M_PI);

这里是绘制一幅图像和一个圆。注意:这时,图形尚未绘制到窗口中,它们还在内存里。

1. cairo_clip(cr);

cairo_clip() 函数设定裁剪域——当前所用的路径,即 cairo_arc() 函数所创建的路径。

1. cairo_paint(cr);

cairo_paint() 函数绘制当前落入裁剪域中的源。

裁剪矩形

下面这个示例是对一个 Java 2D 示例的模拟。

001. #include <cairo.h>
002. #include <gtk/gtk.h>
003. #include <math.h>
004.  
005.  
006. static gboolean
007. on_expose_event(GtkWidget *widget,
008.      GdkEventExpose *event,
009.      gpointer data)
010. {
011.    cairo_t *cr;
012.    cr = gdk_cairo_create(widget->window);
013.  
014.    static gboolean xdirection = TRUE;
015.    static gint counter = 0;
016.  
017.    int width, height;
018.    gtk_window_get_size(GTK_WINDOW(widget), &width, &height);
019.  
020.    static gdouble rotate = 0;
021.  
022.    static gint bigx = 20;
023.    static gint bigy = 200;
024.    static gint delta = 1;
025.  
026.    counter += 1; 
027.  
028.  
029.    if (bigx > width) {
030.        xdirection = FALSE;
031.        delta = -delta;
032.        bigx = width;
033.    }
034.  
035.    if (bigx < 1) {
036.        bigx = 1;
037.        delta = -delta;
038.    }
039.  
040.    if (bigy > height) {
041.        xdirection = TRUE;
042.        delta = -delta;
043.        bigy = height;
044.    }
045.  
046.    if (bigy < 1) {
047.        delta = -delta;
048.        bigy = 1;
049.    }
050.  
051.    if (xdirection) {
052.        bigx += delta;
053.    } else {
054.        bigy += delta;
055.    }
056.  
057.    cairo_translate(cr, width / 2, height /2);
058.  
059.    cairo_rectangle(cr, -bigx/2, -bigy/2, bigx-2, bigy-2);
060.    cairo_set_source_rgb(cr, 0, 0, 0);
061.    cairo_set_line_width(cr, 1); 
062.    cairo_stroke(cr);
063.  
064.    cairo_rotate(cr, rotate);
065.    rotate += 0.01;
066.  
067.    cairo_rectangle(cr, -50, -25, 100, 50);
068.    cairo_stroke(cr);
069.  
070.    GdkRectangle bigrect;
071.    GdkRectangle rect;
072.    GdkRectangle intersect;
073.  
074.    bigrect.x = -bigx/2;
075.    bigrect.y = -bigy/2;
076.    bigrect.width = bigx -2;
077.    bigrect.height = bigy -2;
078.  
079.    rect.x = -50;
080.    rect.y = -25;
081.    rect.width = 100;
082.    rect.height = 50;
083.  
084.    gdk_rectangle_intersect(&bigrect, &rect, &intersect);
085.    cairo_rectangle(cr, intersect.x, intersect.y, intersect.width, intersect.height);
086.    cairo_fill(cr);
087.  
088.    cairo_destroy(cr);
089.  
090.    return FALSE;
091. }
092.  
093. static gboolean
094. time_handler (GtkWidget *widget)
095. {
096.    if (widget->window == NULL) return FALSE;
097.    gtk_widget_queue_draw(widget);
098.    return TRUE;
099. }
100.  
101. int
102. main ( int argc, char *argv[])
103. {
104.  
105.    GtkWidget *window;
106.  
107.    gtk_init(&argc, &argv);
108.  
109.    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
110.  
111.    g_signal_connect(G_OBJECT(window), "expose-event" ,
112.        G_CALLBACK(on_expose_event), NULL);
113.    g_signal_connect(G_OBJECT(window), "destroy" ,
114.        G_CALLBACK(gtk_main_quit), NULL);
115.  
116.    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
117.    gtk_window_set_default_size(GTK_WINDOW(window), 250, 200);
118.  
119.    gtk_widget_set_app_paintable(window, TRUE);
120.    gtk_widget_show_all(window);
121.    g_timeout_add(5, (GSourceFunc) time_handler, (gpointer) window);
122.  
123.    gtk_main();
124.  
125.    return 0;
126. }

在这个示例中,绘制了两个矩形,一个是形状大一些的,一个是在旋转的。大点的那个矩形,持续的在进行形状的缩放,小一点的一直在旋转。在两个矩形的 运动过程中进行了交集操作,它们的相交区域用黑色区域来绘制。注意:那个相交区域并非恰好是矩形,只是为了简化,将那个区域用矩形近似替代。

1. static gboolean xdirection = TRUE;

这个变量决定了那个大一些的矩形的运动方向。

1. if (bigx > width) {
2.      xdirection = FALSE;
3.      delta = -delta;
4.      bigx = width;
5. }

如果那个大的矩形,其宽度增长到与窗口的宽度相等时,就开始收缩,同时矩形开始沿 y 方向收缩。

1. cairo_rotate(cr, rotate);

cairo_rotate() 函数用来旋转那个小一点的矩形。

1. GdkRectangle bigrect;
2. GdkRectangle rect;
3. GdkRectangle intersect;

这里定义了三个矩形区域。insersect 是那两个矩形的相交区域。

1. gdk_rectangle_intersect(&bigrect, &rect, &intersect);

这个函数可完成矩形相交运算。

1. cairo_rectangle(cr, intersect.x, intersect.y, intersect.width, intersect.height);
2. cairo_fill(cr);

绘制相交区域的矩形。

 

遮蔽

因为在源被用于外观之前,首先要被过滤。遮蔽可作为一种过滤器。遮蔽用于决定源的哪部分要被显示,哪部分不可被显示。遮蔽的不透明部分允许将源复制到外观,透明部分则不允许将源复制给外观。

 

01. #include <cairo.h>
02. #include <gtk/gtk.h>
03.  
04.  
05. static gboolean
06. on_expose_event(GtkWidget *widget,
07.      GdkEventExpose *event,
08.      gpointer data)
09. {
10.    cairo_t *cr;
11.    cairo_surface_t *surface;
12.  
13.    cr = gdk_cairo_create(widget->window);
14.  
15.    cairo_set_source_rgb(cr, 0, 0, 0);
16.  
17.    surface = cairo_image_surface_create_from_png( "omen.png" );
18.    cairo_mask_surface(cr, surface, 0, 0);
19.    cairo_fill(cr);
20.  
21.    cairo_surface_destroy(surface);
22.    cairo_destroy(cr);
23.  
24.    return FALSE;
25. }
26.  
27.  
28. int main( int argc, char *argv[])
29. {
30.    GtkWidget *window;
31.  
32.    gtk_init(&argc, &argv);
33.  
34.    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
35.  
36.    g_signal_connect(G_OBJECT(window), "expose-event" ,
37.        G_CALLBACK(on_expose_event), NULL);
38.    g_signal_connect(G_OBJECT(window), "destroy" ,
39.        G_CALLBACK(gtk_main_quit), NULL);
40.  
41.    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
42.    gtk_window_set_default_size(GTK_WINDOW(window), 305, 100);
43.  
44.    gtk_window_set_title(GTK_WINDOW(window), "mask" );
45.    gtk_widget_set_app_paintable(window, TRUE);
46.    gtk_widget_show_all(window);
47.  
48.    gtk_main();
49.  
50.    return 0;
51. }

这个小例子清楚的展示了遮蔽的基本思想。

1. surface = cairo_image_surface_create_from_png( "omen.png" );
2. cairo_mask_surface(cr, surface, 0, 0);
3. cairo_fill(cr);

这里,是用了一幅图像作为遮蔽,然后在窗口中显示它。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要下载Cairo图形指南,首先需要找到可靠的来源。Cairo是一个跨平台的开源图形库,用于绘制2D向量图形。在进行下载前,可以先到Cairo官方网站(https://cairographics.org/)浏览相关信息。 在官方网站上找到"Downloads"或者"获取"的选项,点击进入下载页面。通常,下载页面会列出各种版本的Cairo图形指南可供选择。选择适合自己操作系统的版本,例如Windows、Linux或者macOS。 根据自己的操作系统,点击相应的下载链接,等待下载完成。一般来说,Cairo图形指南的下载文件以压缩包的形式提供,可以是zip文件、tar.gz文件等。如果下载的是压缩文件,需要先解压缩,可以使用系统自带的解压软件或者第三方解压工具。 解压缩完成后,就可以开始阅读Cairo图形指南了。Cairo图形指南通常以PDF、HTML或者文本格式提供,可以根据个人的喜好选择合适的格式进行阅读。可以使用电脑自带的PDF阅读器、文本编辑器等工具进行查看。 在阅读Cairo图形指南时,可以了解Cairo的基本概念、使用方法和相关的示例代码。图形指南会提供详细的说明和实例,以帮助读者更好地理解和应用Cairo图形库。 总之,要下载Cairo图形指南,需要先访问Cairo官方网站,找到适合自己操作系统的版本,下载并解压缩文件,最后选择合适的格式进行阅读。通过学习Cairo图形指南,可以更好地利用Cairo开发出高质量的2D图形应用程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值