網誌存檔

2010年11月16日 星期二

「轉貼」Cairo 圖形指南 (7) —— 形狀與填充

圖案 (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 又是黑色。


沒有留言:

張貼留言