原文: https://zetcode.com/gfx/cairo/shapesfills/

在 Cairo 教程的这一部分中,我们将创建一些基本的和更高级的形状。 我们将用纯色,图案和渐变填充它们。 渐变将在单独的章节中介绍。

基本形状

Cairo API 具有一些用于创建简单形状的基本函数。

  1. static void do_drawing(cairo_t *cr)
  2. {
  3. cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
  4. cairo_set_line_width(cr, 1);
  5. cairo_rectangle(cr, 20, 20, 120, 80);
  6. cairo_rectangle(cr, 180, 20, 80, 80);
  7. cairo_stroke_preserve(cr);
  8. cairo_fill(cr);
  9. cairo_arc(cr, 330, 60, 40, 0, 2*M_PI);
  10. cairo_stroke_preserve(cr);
  11. cairo_fill(cr);
  12. cairo_arc(cr, 90, 160, 40, M_PI/4, M_PI);
  13. cairo_close_path(cr);
  14. cairo_stroke_preserve(cr);
  15. cairo_fill(cr);
  16. cairo_translate(cr, 220, 180);
  17. cairo_scale(cr, 1, 0.7);
  18. cairo_arc(cr, 0, 0, 50, 0, 2*M_PI);
  19. cairo_stroke_preserve(cr);
  20. cairo_fill(cr);
  21. }

在此示例中,我们将创建一个矩形,正方形,圆形,弧形和椭圆形。

  1. cairo_rectangle(cr, 20, 20, 120, 80);
  2. cairo_rectangle(cr, 180, 20, 80, 80);

cairo_rectangle()用于创建正方形和矩形。 正方形只是矩形的一种特定类型。

  1. cairo_arc(cr, 330, 60, 40, 0, 2*M_PI);

这条线创建一个圆。

  1. cairo_scale(cr, 1, 0.7);
  2. cairo_arc(cr, 0, 0, 50, 0, 2*M_PI);

我们使用cairo_scale()函数调用来创建一个椭圆。

形状和填充 - 图1

图:基本形状

可以使用基本图元的组合来创建其他形状。

  1. #include <cairo.h>
  2. #include <gtk/gtk.h>
  3. static void do_drawing(cairo_t *);
  4. int points[11][2] = {
  5. { 0, 85 },
  6. { 75, 75 },
  7. { 100, 10 },
  8. { 125, 75 },
  9. { 200, 85 },
  10. { 150, 125 },
  11. { 160, 190 },
  12. { 100, 150 },
  13. { 40, 190 },
  14. { 50, 125 },
  15. { 0, 85 }
  16. };
  17. static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr,
  18. gpointer user_data)
  19. {
  20. do_drawing(cr);
  21. return FALSE;
  22. }
  23. static void do_drawing(cairo_t *cr)
  24. {
  25. cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
  26. cairo_set_line_width(cr, 1);
  27. gint i;
  28. for (i = 0; i < 10; i++) {
  29. cairo_line_to(cr, points[i][0], points[i][1]);
  30. }
  31. cairo_close_path(cr);
  32. cairo_stroke_preserve(cr);
  33. cairo_fill(cr);
  34. cairo_move_to(cr, 240, 40);
  35. cairo_line_to(cr, 240, 160);
  36. cairo_line_to(cr, 350, 160);
  37. cairo_close_path(cr);
  38. cairo_stroke_preserve(cr);
  39. cairo_fill(cr);
  40. cairo_move_to(cr, 380, 40);
  41. cairo_line_to(cr, 380, 160);
  42. cairo_line_to(cr, 450, 160);
  43. cairo_curve_to(cr, 440, 155, 380, 145, 380, 40);
  44. cairo_stroke_preserve(cr);
  45. cairo_fill(cr);
  46. }
  47. int main(int argc, char *argv[])
  48. {
  49. GtkWidget *window;
  50. GtkWidget *darea;
  51. gtk_init(&argc, &argv);
  52. window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  53. darea = gtk_drawing_area_new();
  54. gtk_container_add(GTK_CONTAINER(window), darea);
  55. g_signal_connect(G_OBJECT(darea), "draw",
  56. G_CALLBACK(on_draw_event), NULL);
  57. g_signal_connect(window, "destroy",
  58. G_CALLBACK(gtk_main_quit), NULL);
  59. gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  60. gtk_window_set_default_size(GTK_WINDOW(window), 460, 240);
  61. gtk_window_set_title(GTK_WINDOW(window), "Other shapes");
  62. gtk_widget_show_all(window);
  63. gtk_main();
  64. return 0;
  65. }

在此示例中,我们将星形对象创建为三角形和修改后的三角形。 这些对象是使用直线和一条曲线创建的。

  1. gint i;
  2. for (i = 0; i < 10; i++ ) {
  3. cairo_line_to(cr, points[i][0], points[i][1]);
  4. }
  5. cairo_close_path(cr);

通过连接点数组中的所有点来绘制星形。 通过调用cairo_close_path()函数将星星结束,该函数将星星的最后两个点连接在一起。

  1. cairo_move_to(cr, 380, 40);
  2. cairo_line_to(cr, 380, 160);
  3. cairo_line_to(cr, 450, 160);
  4. cairo_curve_to(cr, 440, 155, 380, 145, 380, 40);

修改后的三角形是两条直线和一条曲线的简单组合。

形状和填充 - 图2

图:其它形状

填充

填充填充形状的内部。 填充可以是纯色,图案或渐变。

纯色

颜色是代表红色,绿色和蓝色(RGB)强度值的组合的对象。 Cairo 有效 RGB 值在 0 到 1 的范围内。

  1. static void do_drawing(cairo_t *cr)
  2. {
  3. cairo_set_source_rgb(cr, 0.5, 0.5, 1);
  4. cairo_rectangle(cr, 20, 20, 100, 100);
  5. cairo_fill(cr);
  6. cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
  7. cairo_rectangle(cr, 150, 20, 100, 100);
  8. cairo_fill(cr);
  9. cairo_set_source_rgb(cr, 0, 0.3, 0);
  10. cairo_rectangle(cr, 20, 140, 100, 100);
  11. cairo_fill(cr);
  12. cairo_set_source_rgb(cr, 1, 0, 0.5);
  13. cairo_rectangle(cr, 150, 140, 100, 100);
  14. cairo_fill(cr);
  15. }

在示例中,我们绘制了四个彩色矩形。

  1. cairo_set_source_rgb(cr, 0.5, 0.5, 1);
  2. cairo_rectangle(cr, 20, 20, 100, 100);
  3. cairo_fill(cr);

cairo_set_source_rgb()函数调用将源设置为不透明的颜色。 参数是红色,绿色和蓝色强度值。 通过调用cairo_fill()函数,源可用于填充矩形的内部。

形状和填充 - 图3

图:纯色

图案

图案是可以填充形状的复杂图形对象。

  1. #include <cairo.h>
  2. #include <gtk/gtk.h>
  3. static void do_drawing(cairo_t *);
  4. cairo_surface_t *surface1;
  5. cairo_surface_t *surface2;
  6. cairo_surface_t *surface3;
  7. cairo_surface_t *surface4;
  8. static void create_surfaces() {
  9. surface1 = cairo_image_surface_create_from_png("blueweb.png");
  10. surface2 = cairo_image_surface_create_from_png("maple.png");
  11. surface3 = cairo_image_surface_create_from_png("crack.png");
  12. surface4 = cairo_image_surface_create_from_png("chocolate.png");
  13. }
  14. static void destroy_surfaces() {
  15. cairo_surface_destroy(surface1);
  16. cairo_surface_destroy(surface2);
  17. cairo_surface_destroy(surface3);
  18. cairo_surface_destroy(surface4);
  19. }
  20. static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr,
  21. gpointer user_data)
  22. {
  23. do_drawing(cr);
  24. return FALSE;
  25. }
  26. static void do_drawing(cairo_t *cr)
  27. {
  28. cairo_pattern_t *pattern1;
  29. cairo_pattern_t *pattern2;
  30. cairo_pattern_t *pattern3;
  31. cairo_pattern_t *pattern4;
  32. pattern1 = cairo_pattern_create_for_surface(surface1);
  33. pattern2 = cairo_pattern_create_for_surface(surface2);
  34. pattern3 = cairo_pattern_create_for_surface(surface3);
  35. pattern4 = cairo_pattern_create_for_surface(surface4);
  36. cairo_set_source(cr, pattern1);
  37. cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
  38. cairo_rectangle(cr, 20, 20, 100, 100);
  39. cairo_fill(cr);
  40. cairo_set_source(cr, pattern2);
  41. cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
  42. cairo_rectangle(cr, 150, 20, 100, 100);
  43. cairo_fill(cr);
  44. cairo_set_source(cr, pattern3);
  45. cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
  46. cairo_rectangle(cr, 20, 140, 100, 100);
  47. cairo_fill(cr);
  48. cairo_set_source(cr, pattern4);
  49. cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
  50. cairo_rectangle(cr, 150, 140, 100, 100);
  51. cairo_fill(cr);
  52. cairo_pattern_destroy(pattern1);
  53. cairo_pattern_destroy(pattern2);
  54. cairo_pattern_destroy(pattern3);
  55. cairo_pattern_destroy(pattern4);
  56. }
  57. int main(int argc, char *argv[])
  58. {
  59. GtkWidget *window;
  60. GtkWidget *darea;
  61. gtk_init(&argc, &argv);
  62. window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  63. darea = gtk_drawing_area_new();
  64. gtk_container_add(GTK_CONTAINER(window), darea);
  65. g_signal_connect(G_OBJECT(darea), "draw",
  66. G_CALLBACK(on_draw_event), NULL);
  67. g_signal_connect(G_OBJECT(window), "destroy",
  68. G_CALLBACK(gtk_main_quit), NULL);
  69. create_surfaces();
  70. gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  71. gtk_window_set_default_size(GTK_WINDOW(window), 270, 260);
  72. gtk_window_set_title(GTK_WINDOW(window), "Patterns");
  73. gtk_widget_show_all(window);
  74. gtk_main();
  75. destroy_surfaces();
  76. return 0;
  77. }

在此示例中,我们再次绘制了四个矩形。 这次,我们用一些模式填充它们。 我们使用来自 Gimp 图像处理器的四个图案图像。 我们必须保留这些模式的原始大小,因为我们将对它们进行平铺。

我们在on_draw_event()函数之外创建图像表面。 每次需要重新绘制窗口时,每次从硬盘读取数据都不是很有效。

  1. pattern1 = cairo_pattern_create_for_surface(surface1);

我们通过调用cairo_pattern_create_for_surface()函数从表面创建图案。

  1. cairo_set_source(cr, pattern1);
  2. cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
  3. cairo_rectangle(cr, 20, 20, 100, 100);
  4. cairo_fill(cr);

在这里,我们绘制第一个矩形。 cairo_set_source()告诉 Cairo 上下文使用图案作为绘图源。 图像图案可能不完全适合形状。 我们将模式设置为CAIRO_EXTEND_REPEAT,这将导致图案通过重复平铺。 cairo_rectangle()创建一个矩形路径。 最后,cairo_fill()用源填充路径。

本章介绍了 Cairo 的形状和填充。