这一部分,讲述一些基本的以及较为高级的形状绘制及其纯色 (solid color)、图案 (pattern) 与渐变 (gradient) 填充方法。

基本形状

Cairo 提供了几个用于绘制基本形状的函数。

#include

#include

#include

static gboolean

on_expose_event (GtkWidget * widget,

GdkEventExpose * event, gpointer data)

{

cairo_t *cr;

cr = gdk_cairo_create (widget->window);

cairo_set_source_rgb (cr, 0, 0, 0);

cairo_set_line_width (cr, 1);

cairo_rectangle (cr, 20, 20, 120, 80);

cairo_rectangle (cr, 180, 20, 80, 80);

cairo_stroke_preserve (cr);

cairo_set_source_rgb (cr, 1, 1, 1);

cairo_fill (cr);

cairo_set_source_rgb (cr, 0, 0, 0);

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

cairo_stroke_preserve (cr);

cairo_set_source_rgb (cr, 1, 1, 1);

cairo_fill (cr);

cairo_set_source_rgb (cr, 0, 0, 0);

cairo_arc (cr, 90, 160, 40, M_PI / 4, M_PI);

cairo_close_path (cr);

cairo_stroke_preserve (cr);

cairo_set_source_rgb (cr, 1, 1, 1);

cairo_fill (cr);

cairo_set_source_rgb (cr, 0, 0, 0);

cairo_translate (cr, 220, 180);

cairo_scale (cr, 1, 0.7);

cairo_arc (cr, 0, 0, 50, 0, 2 * M_PI);

cairo_stroke_preserve (cr);

cairo_set_source_rgb (cr, 1, 1, 1);

cairo_fill (cr);

cairo_destroy (cr);

return FALSE;

}

int

main (int argc, char *argv[])

{

GtkWidget *window;

GtkWidget *darea;

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), 390, 240);

gtk_widget_show_all (window);

gtk_main ();

return 0;

}

这个示例,绘制了矩形、正方形、圆、圆弧和椭圆。

下面对关键代码简单分析:

cairo_rectangle (cr, 20, 20, 120, 80);

cairo_rectangle (cr, 180, 20, 80, 80);

绘制矩形与正方形。正方形在 cairo 中是矩形的一种特例。

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

画了一个圆,圆心为 (330, 60)px,半径为 40px。Cairo 所谓的圆,其实是起始角为 0 度,终止角为 360 度的弧线。

cairo_scale (cr, 1, 0.7);

cairo_arc (cr, 0, 0, 50, 0, 2 * M_PI);

画椭圆的方法也与画圆类似,只是需要先设定长轴与短轴的比例,在本例中为 1:0.7。

复杂的图形

复杂的图形是由简单的图形拼凑出来的,譬如下面这个绘制圆角矩形的程序。

#include

#include

#include

static void

draw_round_rectangle (cairo_t * cr,

double x, double y,

double width, double height, double r)

{

cairo_move_to (cr, x + r, y);

cairo_line_to (cr, x + width - r, y);

cairo_move_to (cr, x + width, y + r);

cairo_line_to (cr, x + width, y + height - r);

cairo_move_to (cr, x + width - r, y + height);

cairo_line_to (cr, x + r, y + height);

cairo_move_to (cr, x, y + height - r);

cairo_line_to (cr, x, y + r);

cairo_arc (cr, x + r, y + r, r, M_PI, 3 * M_PI / 2.0);

cairo_arc (cr, x + width - r, y + r, r, 3 * M_PI / 2, 2 * M_PI);

cairo_arc (cr, x + width - r, y + height - r, r, 0, M_PI / 2);

cairo_arc (cr, x + r, y + height - r, r, M_PI / 2, M_PI);

}

static gboolean

on_expose_event (GtkWidget * widget,

GdkEventExpose * event, gpointer data)

{

cairo_t *cr;

int width, height;

double w, h, x, y, r;

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

x = width / 5.0;

y = height / 5.0;

w = 3 * width / 5.0;

h = 3 * height / 5.0;

r = h / 4.0;

cr = gdk_cairo_create (widget->window);

cairo_set_source_rgb (cr, 0.8, 0.4, 0);

cairo_set_line_width (cr, 6);

draw_round_rectangle (cr, x, y, w, h, r);

cairo_stroke_preserve (cr);

cairo_set_source_rgb (cr, 0.8, 0.8, 0.2);

cairo_fill (cr);

cairo_destroy (cr);

g_print ("test\n");

return FALSE;

}

static gboolean

on_configure_event (GtkWidget * widget,

GdkEventConfigure * event, gpointer data)

{

gdk_window_invalidate_rect (widget->window,

&widget->allocation,

FALSE);

return FALSE;

}

int

main (int argc, char *argv[])

{

GtkWidget *window;

GtkWidget *darea;

gtk_init (&argc, &argv);

window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

g_signal_connect (window, "expose-event",

G_CALLBACK (on_expose_event), NULL);

g_signal_connect (window, "destroy",

G_CALLBACK (gtk_main_quit), NULL);

g_signal_connect(G_OBJECT(window), "configure-event",

G_CALLBACK(on_configure_event), NULL);

gtk_window_set_position (GTK_WINDOW (window),

GTK_WIN_POS_CENTER);

gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);

gtk_widget_set_app_paintable (window, TRUE);

gtk_widget_show_all (window);

gtk_main ();

return 0;

}

注:因为 "The cairo graphics tutorial" 在这一部分所提供的示例程序不具代表性,因此写了这个程序。

该示例程序绘制了一个可跟随窗口尺寸进行缩放变化的圆角矩形。

自定义的 draw_round_rectangle () 函数利用 Cairo 提供的基本图元函数,利用直线段与圆弧拼凑出圆角矩形。on_configure_event () 函数用于响应窗口尺寸变化事件,在其中调用 gdk_window_invalidate_rect () 函数让窗口绘图区域失效,并产生窗口重绘制事件(即 expose 事件)。

填充 (Fill)

虽然上一篇已经讲述了一些有关填充的知识,但这里所讲述的内容是与形状相关的。填充可分为三种类型:纯色、图案、渐变。

纯色 (Solid color)

对象的颜色是采用红 (R)、绿 (G)、蓝 (B) 三原色描述的,Cairo 的 RGB 取值是从 0 到 1 的双精浮点数。

#include

#include

static gboolean

on_expose_event (GtkWidget * widget,

GdkEventExpose * event, gpointer data)

{

cairo_t *cr;

cr = gdk_cairo_create (widget->window);

int width, height;

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

cairo_set_source_rgb (cr, 0.5, 0.5, 1);

cairo_rectangle (cr, 20, 20, 100, 100);

cairo_fill (cr);

cairo_set_source_rgb (cr, 0.6, 0.6, 0.6);

cairo_rectangle (cr, 150, 20, 100, 100);

cairo_fill (cr);

cairo_set_source_rgb (cr, 0, 0.3, 0);

cairo_rectangle (cr, 20, 140, 100, 100);

cairo_fill (cr);

cairo_set_source_rgb (cr, 1, 0, 0.5);

cairo_rectangle (cr, 150, 140, 100, 100);

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), 270, 260);

gtk_window_set_title (GTK_WINDOW (window), "colors");

gtk_widget_set_app_paintable (window, TRUE);

gtk_widget_show_all (window);

gtk_main ();

return 0;

}

该示例绘制了 4 个正方形,分别采用四种不同颜色进行填充。这个例子,由于很简单,就不再像原作者那样自作多情的分析了。

图案 (Pattern)

所谓图案填充,就是将图片填充到形状内部。

#include

#include

#include

cairo_surface_t *surface1;

cairo_surface_t *surface2;

cairo_surface_t *surface3;

cairo_surface_t *surface4;

static void

create_surfaces ()

{

surface1 = cairo_image_surface_create_from_png ("blueweb.png");

surface2 = cairo_image_surface_create_from_png ("maple.png");

surface3 = cairo_image_surface_create_from_png ("crack.png");

surface4 =

cairo_image_surface_create_from_png ("chocolate.png");

}

static void

destroy_surfaces ()

{

g_print ("destroying surfaces");

cairo_surface_destroy (surface1);

cairo_surface_destroy (surface2);

cairo_surface_destroy (surface3);

cairo_surface_destroy (surface4);

}

static gboolean

on_expose_event (GtkWidget * widget,

GdkEventExpose * event, gpointer data)

{

cairo_t *cr;

cairo_pattern_t *pattern1;

cairo_pattern_t *pattern2;

cairo_pattern_t *pattern3;

cairo_pattern_t *pattern4;

cr = gdk_cairo_create (widget->window);

int width, height;

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

pattern1 = cairo_pattern_create_for_surface (surface1);

pattern2 = cairo_pattern_create_for_surface (surface2);

pattern3 = cairo_pattern_create_for_surface (surface3);

pattern4 = cairo_pattern_create_for_surface (surface4);

cairo_set_source (cr, pattern1);

cairo_pattern_set_extend (cairo_get_source (cr),

CAIRO_EXTEND_REPEAT);

cairo_rectangle (cr, 20, 20, 100, 100);

cairo_fill (cr);

cairo_set_source (cr, pattern2);

cairo_pattern_set_extend (cairo_get_source (cr),

CAIRO_EXTEND_REPEAT);

cairo_arc (cr, 200, 70, 50, 0, 2 * M_PI);

cairo_fill (cr);

cairo_set_source (cr, pattern3);

cairo_pattern_set_extend (cairo_get_source (cr),

CAIRO_EXTEND_REPEAT);

cairo_rectangle (cr, 20, 140, 100, 100);

cairo_fill (cr);

cairo_set_source (cr, pattern4);

cairo_pattern_set_extend (cairo_get_source (cr),

CAIRO_EXTEND_REPEAT);

cairo_rectangle (cr, 150, 140, 100, 100);

cairo_fill (cr);

cairo_pattern_destroy (pattern1);

cairo_pattern_destroy (pattern2);

cairo_pattern_destroy (pattern3);

cairo_pattern_destroy (pattern4);

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);

create_surfaces ();

gtk_window_set_position (GTK_WINDOW (window),

GTK_WIN_POS_CENTER);

gtk_window_set_default_size (GTK_WINDOW (window), 270, 260);

gtk_window_set_title (GTK_WINDOW (window), "patterns");

gtk_widget_set_app_paintable (window, TRUE);

gtk_widget_show_all (window);

gtk_main ();

destroy_surfaces ();

return 0;

}

该示例,载入 4 张图片,分别填充至三个矩形与一个圆形内部区域。所使用的 4 幅图,均采用 GIMP 制作。程序中,图片的外观 (surface) 实在 on_expose_event () 函数中创建的,这并不是很妥当,因为窗口每次被重绘时,都需要从硬盘中读取图片。

pattern1 = cairo_pattern_create_for_surface (surface1);

由图片外观创建一个图案。

cairo_set_source (cr, pattern1);

cairo_pattern_set_extend (cairo_get_source (cr),

CAIRO_EXTEND_REPEAT);

cairo_rectangle (cr, 20, 20, 100, 100);

cairo_fill (cr);

这里,绘制第一个矩形。cairo_set_source () 函数通知 Cairo 环境,让它使用一份图案作为源 (source)。图片所形成的图案或许并不适合于形状,当使用 cairo_pattern_set_extend () 函数讲图案填充模式设为 CAIRO_EXTEND_REPEAT 时,可以让图案像瓦片那样填充于形状内部。cairo_rectangle () 函数创建一个矩形路径,cairo_fill () 函数将已经准备好的图案填充到矩形路径所构成的封闭区域中。

渐变 (Gradient)

在计算机图形学中,渐变是形状由明到暗或者从一种颜色向另一种颜色的平滑过度。在 2D 绘图与渲染程序中,渐变通常被用于创造多彩的背景与一些特效,比如光影的仿真。

#include

#include

static gboolean

on_expose_event (GtkWidget * widget,

GdkEventExpose * event, gpointer data)

{

cairo_t *cr;

cairo_pattern_t *pat1;

cairo_pattern_t *pat2;

cairo_pattern_t *pat3;

cr = gdk_cairo_create (widget->window);

pat1 = cairo_pattern_create_linear (0.0, 0.0, 350.0, 350.0);

gdouble j;

gint count = 1;

for (j = 0.1; j < 1; j += 0.1) {

if ((count % 2)) {

cairo_pattern_add_color_stop_rgb (pat1, j, 0, 0,

0);

} else {

cairo_pattern_add_color_stop_rgb (pat1, j, 1, 0,

0);

}

count++;

}

cairo_rectangle (cr, 20, 20, 300, 100);

cairo_set_source (cr, pat1);

cairo_fill (cr);

pat2 = cairo_pattern_create_linear (0.0, 0.0, 350.0, 0.0);

gdouble i;

count = 1;

for (i = 0.05; i < 0.95; i += 0.025) {

if ((count % 2)) {

cairo_pattern_add_color_stop_rgb (pat2, i, 0, 0,

0);

} else {

cairo_pattern_add_color_stop_rgb (pat2, i, 0, 0,

1);

}

count++;

}

cairo_rectangle (cr, 20, 140, 300, 100);

cairo_set_source (cr, pat2);

cairo_fill (cr);

pat3 = cairo_pattern_create_linear (20.0, 260.0, 20.0, 360.0);

cairo_pattern_add_color_stop_rgb (pat3, 0.1, 0, 0, 0);

cairo_pattern_add_color_stop_rgb (pat3, 0.5, 1, 1, 0);

cairo_pattern_add_color_stop_rgb (pat3, 0.9, 0, 0, 0);

cairo_rectangle (cr, 20, 260, 300, 100);

cairo_set_source (cr, pat3);

cairo_fill (cr);

cairo_pattern_destroy (pat1);

cairo_pattern_destroy (pat2);

cairo_pattern_destroy (pat3);

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), 340, 390);

gtk_window_set_title (GTK_WINDOW (window), "gradients");

gtk_widget_set_app_paintable (window, TRUE);

gtk_widget_show_all (window);

gtk_main ();

return 0;

}

在这一示例程序中,我们绘制了三个具有不同渐变风格的矩形。

pat3 = cairo_pattern_create_linear (20.0, 260.0, 20.0, 360.0);

这里,创建了一个线性渐变图案。参数设定了绘制渐变方向的直线,在示例中,它是一条竖线。

cairo_pattern_add_color_stop_rgb (pat3, 0.1, 0, 0, 0);

cairo_pattern_add_color_stop_rgb (pat3, 0.5, 1, 1, 0);

cairo_pattern_add_color_stop_rgb (pat3, 0.9, 0, 0, 0);

定义了渐变图案的断点。在示例中,渐变图案表现为黑色与黄色的过渡。通过添加两个黑色断点和一个黄色断点,就可以构成一个水平方向的渐变图案,颜色 的变化方向则是沿竖直方向。渐变图案从矩形的上端至下端,开始是黑色,到 1/10 宽度时,黑色便停止了,然后就是由黑色向黄色的渐变渲染;到达矩形中部时,黄色达到饱和状态。黄色断点会在 9/10 宽度处终止,最后的 1/10 又是黑色。

cairo填充_Cairo 图形指南 (5) —— 形状与填充相关推荐

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

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

  2. cairo填充_Cairo图形指南

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

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

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

  4. cairo填充_用 cairo 实现跨平台图形

    用 cairo 实现跨平台图形 用于产生一致输出的矢量绘图库 Eli Dow 2007 年 9 月 24 日发布 cairo 的优点和用途 cairo 是一个免费的矢量绘图软件库,它可以绘制多种输出格 ...

  5. PyCairo 中的形状和填充

    PyCairo 教程的这个部分,我们创建一些基本的和更高级的形状.我们使用纯色,模式和渐变填充这些形状.渐变将在另一章中讨论. 基本形状 PyCairo 有一些基本的方法可以用来绘制简单的形状. de ...

  6. 用 cairo 实现跨平台图形

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

  7. cario java_(转)用 cairo 实现跨平台图形

    用于产生一致输出的矢量绘图库 Eli Dow (emdow@us.ibm.com), 软件工程师, IBM Linux Test and Integration Center 简介: cairo 的目 ...

  8. CAD图形设置:层高与填充设置教程

    当我们在使用国产CAD软件绘制建筑CAD图纸的过程中,有些时候会需要进行CAD图形设置.那么你知道浩辰CAD建筑软件的CAD图形设置中层高和填充怎么设置吗?不知道也没关系,接下来的CAD教程就让小编来 ...

  9. html渐变颜色填充,在画布形状中填充渐变色

    您也可以在画布形状内填充渐变色.渐变只是从一种颜色到另一种颜色的平滑视觉过渡.有两种类型的渐变可用:线性渐变和径向渐变. 创建线性渐变的基本语法可以通过以下方式给出: var grd = contex ...

最新文章

  1. Redis初学:14(Redis中的事务)
  2. 巨杉数据库完成数千万美元C轮融资,嘉实投资领投
  3. 【深度学习】深度学习之对抗样本问题和知识蒸馏技术
  4. linux导出路径path,Linux kernel 绝对路径之d_path篇【转】
  5. JAVA输出希腊union,希腊文化认为,最为抽象的艺术形式是()。
  6. 最新SSM完整模板(Spring+SpringMVC+MybatisPlus)
  7. 【Python】Pygame入门
  8. PyCharm中Scrapy的安装
  9. Android Studio导入project和module的方法
  10. java 俄语月份,适当的俄语月字符串翻译Java
  11. 小C语言程序----词法分析程序输出单词
  12. RocketMQ之消息中间件需要解决的问题
  13. GigE Vision网络相机
  14. “十三五”输电通道规模倍增 重点建设配电网
  15. Java——JButton按钮
  16. c语言中fprintf的作用,c语言中fprintf的用法
  17. java combo_JAVA中的下拉框(Combo Box)概述(1) | 学步园
  18. 服务器上开虚拟机,可以在云服务器上开虚拟机
  19. 数据分析怎么学?我画了一个导图,又找到22本书
  20. 华为Mate40 Pro 66w充电器冒火花怎么回事?

热门文章

  1. linux用ping命令测试网速,linux下面使用命令测试网速
  2. mysql5批处理_转关于mysql5.5 的批处理讨论(转载)
  3. cmd执行sql文件路径 oracle_oracle 基础 执行sql文件
  4. python风控工具_python-风控模型分析01
  5. Java Scanner nextLine()方法与示例
  6. tohexstring方法_Java Float类toHexString()方法的示例
  7. 再见 Feign!推荐一款微服务间调用神器,跟 SpringCloud 绝配!
  8. 消息队列的其他实现方式
  9. 第 2-3 课:抽象类和接口 + 面试题
  10. 想快速拥有个人网站?来试试这个...