Cairo 图形指南 (11) —— 图像

在这一篇里,要讲述图像的处理。先是演示如何在 GTK+ 窗口中显示一幅图像,然后再制造一些特效。

在第一个例子里,显示了一幅图像。

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

这个示例显示了一幅图片,其尺寸为 300x225,可从这里 下载。这是斯洛伐克西部一个什么地方(Plavecke Podhradie)的中世纪城堡的废墟的一幅照片。 

1. image = cairo_image_surface_create_from_png( "plaveckycastle.png" );

用一幅 png 图片来创建一份图像外观。出于效率的考虑,应在主函数中调用这个函数。

1. cairo_set_source_surface(cr, image, 10, 10);

基于前面构造的图像外观来创建源与外观,用于图像的绘制。

1. cairo_paint(cr);

绘制图片。

 

垂帘效果(Blind Down)

在下面的代码示例中,要垂帘显示图片,就像拉下窗帘的那种效果。

01. #include <cairo.h>
02. #include <gtk/gtk.h>
03.  
04.  
05. gboolean timer = TRUE;
06. cairo_surface_t *image;
07.  
08.  
09. static gboolean
10. on_expose_event(GtkWidget *widget,
11.      GdkEventExpose *event,
12.      gpointer data)
13. {
14.    cairo_t *cr;
15.    cairo_t *ic;
16.  
17.    cairo_surface_t *surface;
18.  
19.    static gdouble angle = 0;
20.    static gint image_width = 0;
21.    static gint image_height = 0;
22.  
23.    static gint w = 0;
24.    static gint h = 0;
25.  
26.    cr = gdk_cairo_create(widget->window);
27.  
28.    gint width, height;
29.    gtk_window_get_size(GTK_WINDOW(widget), &width, &height);
30.  
31.    image_width = cairo_image_surface_get_width(image);
32.    image_height = cairo_image_surface_get_height(image);
33.    w = image_width;
34.  
35.    surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, image_width, image_height);
36.    ic = cairo_create(surface);
37.  
38.    cairo_rectangle(ic, 0, 0, w, h);
39.    cairo_fill(ic);
40.  
41.    h += 1;
42.    if ( h == image_height) timer = FALSE;
43.  
44.    cairo_set_source_surface(cr, image, 10, 10);
45.    cairo_mask_surface(cr, surface, 10, 10);
46.  
47.    cairo_surface_destroy(surface);
48.  
49.    cairo_destroy(cr);
50.    cairo_destroy(ic);
51.    return FALSE;
52. }
53.  
54. static gboolean
55. time_handler(GtkWidget *widget)
56. {
57.    if (widget->window == NULL) return FALSE;
58.  
59.    if (!timer) return FALSE;
60.  
61.    gtk_widget_queue_draw(widget);
62.    return TRUE;
63. }
64.  
65. int main( int argc, char *argv[])
66. {
67.    GtkWidget *window;
68.  
69.    image = cairo_image_surface_create_from_png( "plaveckycastle.png" );
70.  
71.    gtk_init(&argc, &argv);
72.  
73.    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
74.  
75.    g_signal_connect(G_OBJECT(window), "expose-event" ,
76.        G_CALLBACK(on_expose_event), NULL);
77.    g_signal_connect(G_OBJECT(window), "destroy" ,
78.        G_CALLBACK(gtk_main_quit), NULL);
79.  
80.    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
81.    gtk_window_set_default_size(GTK_WINDOW(window), 325, 250);
82.    gtk_window_set_title(GTK_WINDOW(window), "blind down" );
83.  
84.    gtk_widget_set_app_paintable(window, TRUE);
85.    g_timeout_add(15, (GSourceFunc) time_handler, (gpointer) window);
86.  
87.    gtk_widget_show_all(window);
88.  
89.    gtk_main();
90.  
91.    cairo_surface_destroy(image);
92.  
93.    return 0;
94. }

这个垂帘效果幕后的思想相当简单。图片的高度是 h 个像素,则可对其逐行进行绘制,直至图片完全显示。

1. cairo_t *cr;
2. cairo_t *ic;

声明两个 cairo 环境,一个与 GtkWindow 相关联,另一个与图片相关联。

1. surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, image_width, image_height);
2. ic = cairo_create(surface);

创建一个图像外观,并通过它构造那个与图像相关联的 cairo 环境。

1. cairo_rectangle(ic, 0, 0, w, h);
2. cairo_fill(ic);

在初始的空图像中绘制一个矩形,它在循环显示中会增加 1 个像素的高度。采用这种方式创建的图像在后面要作为蒙板来用。

1. h += 1;
2. if ( h == image_height) timer = FALSE;

整幅图像绘制完毕后,停止计时器。

1. cairo_set_source_surface(cr, image, 10, 10);
2. cairo_mask_surface(cr, surface, 10, 10);

城堡图像被设置为要被绘制的源,并采用 surface 的 alpha 通道作为蒙板来绘制这个源。

 

光谱效果

将这种效果称为光谱效果,因为作者不知道怎么称呼才好(我感觉叫百叶窗效果更好)。可能你还记得从前的 ZX 光谱计算机,在这种计算机上载入图像时,它就逐渐的被显示出来,下面的示例大致是模仿这种方式。

001. #include <cairo.h>
002. #include <gtk/gtk.h>
003.  
004.  
005. gboolean timer = TRUE;
006. cairo_surface_t *image;
007.  
008. static gboolean
009. on_expose_event(GtkWidget *widget,
010.      GdkEventExpose *event,
011.      gpointer data)
012. {
013.    cairo_t *cr;
014.    cairo_t *ic;
015.  
016.    cairo_surface_t *surface;
017.  
018.    static gdouble angle = 0;
019.    static gint w = 0;
020.    static gint h = 0;
021.  
022.    static gint image_width = 0;
023.    static gint image_height = 0;
024.  
025.    static gint count = 0;
026.  
027.    cr = gdk_cairo_create(widget->window);
028.  
029.    gint width, height;
030.    gtk_window_get_size(GTK_WINDOW(widget), &width, &height);
031.  
032.    surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, image_width, image_height); 
033.  
034.    image_width = cairo_image_surface_get_width(image);
035.    image_height = cairo_image_surface_get_height(image);
036.    w = image_width; 
037.  
038.    ic = cairo_create(surface);
039.  
040.    gint i, j;
041.    for (i = 0; i <= image_height; i+=7) {
042.        for (j=0 ; j < count; j++) {
043.            cairo_move_to(ic, 0, i+j);
044.            cairo_line_to(ic, w, i+j);
045.        }
046.    }
047.  
048.    count++;
049.    if ( count == 8) timer = FALSE;
050.  
051.    cairo_stroke(ic);
052.  
053.    cairo_set_source_surface(cr, image, 10, 10);
054.    cairo_mask_surface(cr, surface, 10, 10);
055.  
056.    cairo_surface_destroy(surface);
057.  
058.    cairo_destroy(cr);
059.    cairo_destroy(ic);
060.    return FALSE;
061. }
062.  
063. static gboolean
064. time_handler (GtkWidget *widget)
065. {
066.    if (widget->window == NULL) return FALSE;
067.  
068.    if (!timer) return FALSE;
069.  
070.    gtk_widget_queue_draw(widget);
071.    return TRUE;
072. }
073.  
074. int main( int argc, char *argv[])
075. {
076.    GtkWidget *window;
077.  
078.    image = cairo_image_surface_create_from_png( "plaveckycastle.png" );
079.  
080.    gtk_init(&argc, &argv);
081.  
082.    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
083.  
084.    g_signal_connect(G_OBJECT(window), "expose-event" ,
085.        G_CALLBACK(on_expose_event), NULL);
086.    g_signal_connect(G_OBJECT(window), "destroy" ,
087.        G_CALLBACK(gtk_main_quit), NULL);
088.  
089.    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
090.    gtk_window_set_default_size(GTK_WINDOW(window), 325, 250);
091.  
092.    gtk_widget_set_app_paintable(window, TRUE);
093.    g_timeout_add(400, (GSourceFunc) time_handler, (gpointer) window);
094.  
095.    gtk_widget_show_all(window);
096.  
097.    gtk_main();
098.  
099.    cairo_surface_destroy(image);
100.  
101.    return 0;
102. }

这个示例的许多细节与上一个示例相似。这次,是将图像分为每 8 行为一个区域。在每次循环中,8 个部分中每个区域增加一个像素高度。通过这种方式创建的图像将再一次作为模板来显示城堡图像。

1. gint i, j;
2. for (i = 0; i <= image_height; i+=7) {
3.      for (j=0 ; j < count; j++) {
4.          cairo_move_to(ic, 0, i+j);
5.          cairo_line_to(ic, w, i+j);
6.      }
7. }

这是该示例的主要逻辑,我们逐渐的将线绘制到各区域。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值