Cairo 图形指南5形状与填充.docx
《Cairo 图形指南5形状与填充.docx》由会员分享,可在线阅读,更多相关《Cairo 图形指南5形状与填充.docx(16页珍藏版)》请在冰点文库上搜索。
![Cairo 图形指南5形状与填充.docx](https://file1.bingdoc.com/fileroot1/2023-5/9/dbf4a9a0-1d22-4d58-9df2-fb922893d22e/dbf4a9a0-1d22-4d58-9df2-fb922893d22e1.gif)
Cairo图形指南5形状与填充
Cairo图形指南(5)——形状与填充
这一部分,讲述一些基本的以及较为高级的形状绘制及其纯色(solidcolor)、图案(pattern)与渐变(gradient)填充方法。
基本形状
Cairo提供了几个用于绘制基本形状的函数。
#include
#include
#include
staticgboolean
on_expose_event(GtkWidget*widget,
GdkEventExpose*event,gpointerdata)
{
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);
returnFALSE;
}
int
main(intargc,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();
return0;
}
这个示例,绘制了矩形、正方形、圆、圆弧和椭圆。
下面对关键代码简单分析:
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
staticvoid
draw_round_rectangle(cairo_t*cr,
doublex,doubley,
doublewidth,doubleheight,doubler)
{
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);
}
staticgboolean
on_expose_event(GtkWidget*widget,
GdkEventExpose*event,gpointerdata)
{
cairo_t*cr;
intwidth,height;
doublew,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");
returnFALSE;
}
staticgboolean
on_configure_event(GtkWidget*widget,
GdkEventConfigure*event,gpointerdata)
{
gdk_window_invalidate_rect(widget->window,
&widget->allocation,
FALSE);
returnFALSE;
}
int
main(intargc,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();
return0;
}
注:
因为"Thecairographicstutorial"在这一部分所提供的示例程序不具代表性,因此写了这个程序。
该示例程序绘制了一个可跟随窗口尺寸进行缩放变化的圆角矩形。
自定义的draw_round_rectangle()函数利用Cairo提供的基本图元函数,利用直线段与圆弧拼凑出圆角矩形。
on_configure_event()函数用于响应窗口尺寸变化事件,在其中调用gdk_window_invalidate_rect()函数让窗口绘图区域失效,并产生窗口重绘制事件(即expose事件)。
填充(Fill)
虽然上一篇已经讲述了一些有关填充的知识,但这里所讲述的内容是与形状相关的。
填充可分为三种类型:
纯色、图案、渐变。
纯色(Solidcolor)
对象的颜色是采用红(R)、绿(G)、蓝(B)三原色描述的,Cairo的RGB取值是从0到1的双精浮点数。
#include
#include
staticgboolean
on_expose_event(GtkWidget*widget,
GdkEventExpose*event,gpointerdata)
{
cairo_t*cr;
cr=gdk_cairo_create(widget->window);
intwidth,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);
returnFALSE;
}
int
main(intargc,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();
return0;
}
该示例绘制了4个正方形,分别采用四种不同颜色进行填充。
这个例子,由于很简单,就不再像原作者那样自作多情的分析了。
图案(Pattern)
所谓图案填充,就是将图片填充到形状内部。
#include
#include
#include
cairo_surface_t*surface1;
cairo_surface_t*surface2;
cairo_surface_t*surface3;
cairo_surface_t*surface4;
staticvoid
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");
}
staticvoid
destroy_surfaces()
{
g_print("destroyingsurfaces");
cairo_surface_destroy(surface1);
cairo_surface_destroy(surface2);
cairo_surface_destroy(surface3);
cairo_surface_destroy(surface4);
}
staticgboolean
on_expose_event(GtkWidget*widget,
GdkEventExpose*event,gpointerdata)
{
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);
intwidth,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