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

来源:互联网 发布:我的知乎首页没有提问 编辑:程序博客网 时间:2024/06/07 07:37

在这一篇里,要讲述图像的处理。先是演示如何在 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)的中世纪城堡的废墟的一幅照片。 

view source
print?
1.image = cairo_image_surface_create_from_png("plaveckycastle.png");

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

view source
print?
1.cairo_set_source_surface(cr, image, 10, 10);

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

view source
print?
1.cairo_paint(cr);

绘制图片。

 

垂帘效果(Blind Down)

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

view source
print?
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 个像素,则可对其逐行进行绘制,直至图片完全显示。

view source
print?
1.cairo_t *cr;
2.cairo_t *ic;

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

view source
print?
1.surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, image_width, image_height);
2.ic = cairo_create(surface);

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

view source
print?
1.cairo_rectangle(ic, 0, 0, w, h);
2.cairo_fill(ic);

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

view source
print?
1.h += 1;
2.if ( h == image_height) timer = FALSE;

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

view source
print?
1.cairo_set_source_surface(cr, image, 10, 10);
2.cairo_mask_surface(cr, surface, 10, 10);

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

 

光谱效果

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

view source
print?
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 个部分中每个区域增加一个像素高度。通过这种方式创建的图像将再一次作为模板来显示城堡图像。

view source
print?
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.}

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

原创粉丝点击