2010年11月16日 星期二

「轉貼」Cairo 圖形指南 (5) —— 基本繪圖

虛線 (Dash)

每條線都可以用不同的虛線筆 (dash pen) 來畫。虛線模式是通過 cairo_set_dash () 函數來設定。模式類型通過一個數組來定義,數組中的值均為正數,它們用於設置虛線的虛部分與實部分。數組的長度與偏移量可以在程序中設定。如果數組的長度 為 0,虛線模式就是被禁止了,那所繪製的線是實線。如果數組長度為 1,則對應著虛實均勻分佈的虛線模式。偏移量是用來設置在虛線的始端在一個虛線週期(包含一個實部單元和一個虛部單元)內的起始位置。

#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_rgba (cr, 0, 0, 0, 1);

static const double dashed1[] = { 4.0, 1.0 };
static int len1 = sizeof (dashed1) / sizeof (dashed1[0]);

static const double dashed2[] = { 4.0, 10.0, 4.0 };
static int len2 = sizeof (dashed2) / sizeof (dashed2[0]);

static const double dashed3[] = { 1.0 };

cairo_set_line_width (cr, 1.5);

cairo_set_dash (cr, dashed1, len1, 0);

cairo_move_to (cr, 40, 60);
cairo_line_to (cr, 360, 60);
cairo_stroke (cr);

cairo_set_dash (cr, dashed2, len2, 10);

cairo_move_to (cr, 40, 120);
cairo_line_to (cr, 360, 120);
cairo_stroke (cr);

cairo_set_dash (cr, dashed3, 1, 0);

cairo_move_to (cr, 40, 180);
cairo_line_to (cr, 360, 180);
cairo_stroke (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), 400, 300);

gtk_widget_show_all (window);

gtk_main ();

return 0;
}

該示例演示了三種虛線模式的設置及繪製。

下面分析一下關鍵代碼。


static const double dashed1[] = { 4.0, 1.0 };

設定第一條虛線的模式,它的實部是 4 個像素,虛部是 1 個像素。


static int len1 = sizeof (dashed1) / sizeof (dashed1[0]);

計算數組 dashed1 的長度。


cairo_set_dash (cr, dashed1, len1, 0);

設置虛線模式。


darea = gtk_drawing_area_new ();
gtk_container_add (GTK_CONTAINER (window), darea);

這次,我們是在 drawing_area 部件上繪圖,不再是窗口區域了。



線帽 (Line caps)

線帽是針對直線段的端點形狀而言的,分為三種:

  • CAIRO_LINE_CAP_SQUARE
  • CAIRO_LINE_CAP_ROUND
  • CAIRO_LINE_CAP_BUTT

對應形狀如下圖所示:

同一條直線段,CAIRO_LINE_CAP_SQUARE 線帽與 CAIRO_LINE_CAP_BUTT 線帽會導致直線段長度有所差別,前者會比後者長一個線寬尺寸。

#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_rgba (cr, 0, 0, 0, 1);
cairo_set_line_width (cr, 10);

cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
cairo_move_to (cr, 40, 60);
cairo_line_to (cr, 360, 60);
cairo_stroke (cr);

cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
cairo_move_to (cr, 40, 150);
cairo_line_to (cr, 360, 150);
cairo_stroke (cr);

cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
cairo_move_to (cr, 40, 240);
cairo_line_to (cr, 360, 240);
cairo_stroke (cr);

cairo_set_line_width (cr, 1.5);

cairo_move_to (cr, 40, 40);
cairo_line_to (cr, 40, 260);
cairo_stroke (cr);

cairo_move_to (cr, 360, 40);
cairo_line_to (cr, 360, 260);
cairo_stroke (cr);

cairo_move_to (cr, 365, 40);
cairo_line_to (cr, 365, 260);
cairo_stroke (cr);

cairo_destroy (cr);

return FALSE;
}

該示例繪製三條具有不同線帽的直線段,同時也展示了不同線帽對線的長度的影響。

下面對關鍵代碼進行簡單分析:


cairo_set_line_width (cr, 10);

設置線的寬度為 10px。


cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
cairo_move_to (cr, 40, 150);
cairo_line_to (cr, 360, 150);
cairo_stroke (cr);

畫了一條線帽為 CAIRO_LINE_CAP_ROUND 的直線段。


cairo_move_to (cr, 40, 40);
cairo_line_to (cr, 40, 260);
cairo_stroke (cr);

這是三條豎線之一,用於表現線帽對線的長度的影響。



線的交合 (Line joins)

線的交合存在以下三種風格:

  • CAIRO_LINE_JOIN_MITER
  • CAIRO_LINE_JOIN_BEVEL
  • CAIRO_LINE_JOIN_ROUND

對應形狀如下圖所示。

#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.1, 0, 0);

cairo_rectangle (cr, 30, 30, 100, 100);
cairo_set_line_width (cr, 14);
cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER);
cairo_stroke (cr);

cairo_rectangle (cr, 160, 30, 100, 100);
cairo_set_line_width (cr, 14);
cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL);
cairo_stroke (cr);

cairo_rectangle (cr, 100, 160, 100, 100);
cairo_set_line_width (cr, 14);
cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
cairo_stroke (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), 300, 280);

gtk_widget_show_all (window);

gtk_main ();

return 0;
}

該示例採用不同的交合類型繪製了三個矩形。

下面對關鍵代碼進行簡單分析:


cairo_rectangle (cr, 30, 30, 100, 100);
cairo_set_line_width (cr, 14);
cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER);
cairo_stroke (cr);

繪製了一個線寬為 14px,交合類型為 CAIRO_LINE_JOIN_MITER 的矩形。


「轉貼」Cairo 圖形指南 (4) —— 基本繪圖

這一部分講述如何繪製一些簡單的圖元,包括直線、填充與筆畫操作、虛線、線端(Cap)與線的交合等圖形的繪製方法。

直線段

直線段是非常基礎的矢量圖形對象。畫一條直線段,需要調用兩個函數:cairo_move_to() 函數,用於設置線段起點;cairo_line_to() 用於設定線段終點。

#include
#include

double coordx[100];
double coordy[100];

int count = 0;

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

int i, j;
for ( i = 0; i <= count - 1; i++ ) {
for ( j = 0; j <= count -1; j++ ) {
cairo_move_to(cr, coordx[i], coordy[i]);
cairo_line_to(cr, coordx[j], coordy[j]);
}
}

count = 0;
cairo_stroke(cr);
cairo_destroy(cr);

return FALSE;
}

gboolean clicked(GtkWidget *widget, GdkEventButton *event,
gpointer user_data)
{
if (event->button == 1) {
coordx[count] = event->x;
coordy[count++] = event->y;
}

if (event->button == 3) {
gtk_widget_queue_draw(widget);
}

return TRUE;
}


int
main (int argc, char *argv[])
{

GtkWidget *window;

gtk_init(&argc, &argv);

window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

gtk_widget_add_events (window, GDK_BUTTON_PRESS_MASK);

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(window, "button-press-event",
G_CALLBACK(clicked), NULL);

gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_title(GTK_WINDOW(window), "lines");
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;
}

該示例會創建一個支持鼠標交互繪製直線段的 GTK+ 窗口。在窗口中使用鼠標左鍵隨便點幾下,每一次點擊時,光標位置的坐標都會被記入長度為 100 的數組;然後點擊鼠標右鍵,所有由鼠標左鍵點擊所得到的點會被彼此連接形成直線段;在窗口中再次點擊鼠標右鍵時,會對窗口繪圖區域進行清除。

下面對該示例程序代碼進行分析:


cairo_set_source_rgb(cr, 0, 0, 0);
cairo_set_line_width (cr, 0.5);

設置顏色為黑色,線寬為 0.5pt 為參數,繪製直線段。


int i, j;
for ( i = 0; i <= count - 1; i++ ) {
for ( j = 0; j <= count -1; j++ ) {
cairo_move_to(cr, coordx[i], coordy[i]);
cairo_line_to(cr, coordx[j], coordy[j]);
}
}

用 cairo_move_to() 和 cairo_line_to() 函數在 cr 中定義繪圖路徑 (path),連接 coordx[] 和 coordy[] 所記錄的每個點。


cairo_stroke(cr);

cairo_stroke() 函數會將 cr 中的路徑繪製出來。


g_signal_connect(window, "button-press-event",
G_CALLBACK(clicked), NULL);

設定 button-press-event 事件的回調函數為 clicked ()


if (event->button == 1) {
coordx[count] = event->x;
coordy[count++] = event->y;
}

clicked () 函數中,當鼠標左鍵點擊事件發生時,講光標所在位置的 x 和 y 坐標分別記入數組 coordx 和 coordy


if (event->button == 3) {
gtk_widget_queue_draw(widget);
}

clicked () 函數中,當鼠標右鍵單擊時,調用 gtk_widget_queue_draw () 函數重繪窗口區域。



描繪 (Stroke) 與填充 (Fill)

描繪 (Stroke) 可以繪製形狀的輪廓,填充 (Fill) 則用於向形狀內部灌注顏色。

#include
#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_line_width (cr, 9);

cairo_set_source_rgb (cr, 0.69, 0.19, 0);
cairo_arc (cr, width / 2, height / 2,
(width < style="color: rgb(102, 204, 102);">) / 2 - 10, 0,
2 * M_PI);
cairo_stroke_preserve (cr);

cairo_set_source_rgb (cr, 0.3, 0.4, 0.6);
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), 200, 150);

gtk_widget_set_app_paintable (window, TRUE);
gtk_widget_show_all (window);

gtk_main ();

return 0;
}

這個示例繪製一個內部填充灰色的圓。

下面對代碼進行解析:


#include

之所以引入這個頭文件,是因為程序中使用了圓周率常量 M_PI。


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

獲取窗口的寬度與高度尺寸。程序中將使用這些值作為繪製圓形的參考尺寸,以實現窗口尺寸變化時,所繪製的圓的尺寸也會相應變化。


cairo_set_source_rgb (cr, 0.69, 0.19, 0);
cairo_arc (cr, width / 2, height / 2,
(width < style="color: rgb(102, 204, 102);">) / 2 - 10, 0,
2 * M_PI);
cairo_stroke_preserve (cr);

描繪圓的輪廓。這裡要注意一下 cairo_stroke_preserve () 函數與 cairo_stroke () 函數的區別(最好的辦法是用後者替換一下前者,看看程序執行效果)。cairo_stroke_preserve () 函數會將它繪製的路徑依然保存在 cairo 環境中,而 cairo_stroke () 所繪製的路徑,在繪製完成後,就從 cairo的環境中清除了。


cairo_set_source_rgb (cr, 0.3, 0.4, 0.6);
cairo_fill (cr);

對使用 cairo_stroke_preserve () 函數繪製的路徑進行藍色填充。


「轉貼」Cairo 圖形指南 (3) —— Cairo 後端

Cairo 支持多種後端,本文基於幾個示例講述如何使用 Cairo 各種後端創建 PNG 圖像、PDF 文件與 SVG 文件以及如何使用 Cairo 在 GTK 窗口中繪圖。

1. PNG 圖像

第一個示例 (example-1.c) 用於生成 PNG 圖像。

#include

int
main (int argc, char *argv[])
{
cairo_surface_t *surface;
cairo_t *cr;

surface =
cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 320, 48);
cr = cairo_create (surface);

cairo_set_source_rgb (cr, 0.627, 0, 0);
cairo_select_font_face (cr, "Adobe Heiti Std",
CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size (cr, 24.0);

cairo_move_to (cr, 10.0, 34.0);
cairo_show_text (cr, "我是中國人,我愛我的祖國。");

cairo_surface_write_to_png (surface, "image.png");

cairo_destroy (cr);
cairo_surface_destroy (surface);

return 0;
}

這個示例是一個很小的控制台程序,運行後可生成一份 PNG 圖像文件。

#include

上述頭文件聲明了上面示例中調用的函數以及一些常量的定義。

cairo_surface_t *surface;
cairo_t *cr;

這兩行代碼聲明了一個 Cairo 外觀與一個 Cairo 環境。

surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 320, 48);
cr = cairo_create(surface);

現在我們生成了 Cairo 外觀與 Cairo 環境,所生成的外觀是一份 320x48 px 的圖像。

cairo_set_source_rgb (cr, 0.627, 0, 0);

設置源的顏色為 darkred,就好比是選擇了暗紅色的顏料。

cairo_select_font_face(cr, "Adobe Heiti Std", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(cr, 24.0);

選擇字體類型並設置其尺寸。(註:可使用 "fc-list" 命令查看系統所安裝字體)

cairo_move_to(cr, 10.0, 34.0);
cairo_show_text(cr, "我是中國人,我愛我的祖國。");

將「畫筆」移動到圖像區域的 (10.0, 34.0) 位置開始繪製文本。

cairo_surface_write_to_png(surface, "image.png");

這個函數創建 PNG 圖像。

cairo_destroy(cr);
cairo_surface_destroy(surface);

最後,回收所有 Cairo 環境與外觀所佔用的內存資源。

編譯這個示例:

$ gcc -o example-1 `pkg-config --cflags --libs gtk+-2.0` example-1.c

生成的 PNG 圖像如下圖所示:

2. PDF 文件

在第二個示例 (example-2.c) 中,將使用 Cairo 生成一份 PDF 文件,其內容與第一個示例所生成的圖像是相同的。

#include
#include

int
main (int argc, char *argv[])
{
cairo_surface_t *surface;
cairo_t *cr;

surface = cairo_pdf_surface_create ("pdffile.pdf", 320, 48);
cr = cairo_create (surface);

cairo_set_source_rgb (cr, 0.627, 0, 0);
cairo_select_font_face (cr, "Adobe Heiti Std",
CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size (cr, 24.0);

cairo_move_to (cr, 10.0, 34.0);
cairo_show_text (cr, "我是中國人,我愛我的祖國。");

cairo_show_page (cr);

cairo_destroy (cr);
cairo_surface_destroy (surface);

return 0;
}

編譯這個示例:

$ gcc -o example-2 `pkg-config --cflags --libs gtk+-2.0` example-2.c

生成的 PDF 文件,請使用 PDF 閱讀器查看,Linux 用戶可使用 Evince 或 KPDF。

surface = cairo_pdf_surface_create ("pdffile.pdf", 320, 48);

要生成 pdf 文件,必須使用 cairo_pdf_surface () 函數創建一個 pdf 外觀。pdf 文件的頁面大小是以排版標準中的像素點尺寸為單位控制的。

cairo_show_page(cr);

生成的 PDF 文檔在 Evince 中顯示效果如下圖所示:

3. SVG 文件

第三個示例演示如何使用 Cairo SVG 後端生成一份簡單的 SVG (Scalble Vector Graphics) 文件。SVG 技術近幾年很熱門。

#include
#include

int
main (int argc, char *argv[])
{
cairo_surface_t *surface;
cairo_t *cr;

surface = cairo_svg_surface_create ("svgfile.svg", 320, 48);
cr = cairo_create (surface);

cairo_set_source_rgb (cr, 0.627, 0, 0);
cairo_select_font_face (cr, "Adobe Heiti Std",
CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size (cr, 24.0);

cairo_move_to (cr, 10.0, 34.0);
cairo_show_text (cr, "我是中國人,我愛我的祖國。");

cairo_destroy (cr);
cairo_surface_destroy (surface);

return 0;
}

編譯這個示例:

$ gcc -o example-3 `pkg-config --cflags --libs gtk+-2.0` example-3.c

生成的 SVG 文件可以使用 Firefox、Opera、Inkscape 程序查看。

surface = cairo_svg_surface_create("svgfile.svg", 320, 48);

要生成一份 SVG 文件,必須使用 cairo_svg_surface_create () 函數創建一個 svg 外觀。除此之外,其餘代碼的功用與上述示例類似。

本例生成的 SVG 文件,使用 Firefox 查看結果如下圖所示:

4. GTK 窗口

在最後這個示例中,演示如何在 GTK 窗口中使用 Cairo 繪製圖形。基於 GTK 後端的 Cairo 繪圖模型將貫穿於本指南。

#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.627, 0, 0);
cairo_select_font_face (cr, "Adobe Heiti Std", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size (cr, 24.0);

cairo_move_to (cr, 10.0, 34.0);
cairo_show_text (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 (window, "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), 320, 48);
gtk_widget_set_app_paintable (window, TRUE);

gtk_widget_show_all (window);

gtk_main ();

return 0;
}

這個示例程序運行後,會在屏幕中央跳出一個 GTK+ 窗口,上面繪製了一串文本,如下圖所示:

#include
#include

首先要包含 cairo 與 gtk+ 庫的頭文件。

g_signal_connect (window, "expose-event",
G_CALLBACK (on_expose_event), NULL);

當 GTK+窗口被重繪時,會發出 expose-event 信號,我們可將這一信號連接到 on_expose_event () 回調函數上。

gtk_widget_set_app_paintable (window, TRUE);

要在 GTK+ 窗口中繪製 Cairo 圖形,可以使用 GtkDrawingArea widget 或者更為簡單的 GtkWindow widget,本例選擇 GtkWindow 。由 GtkWindow widget 對 expose-event 信號處理後,默認要重新繪製窗口背景,這會將我們在 on_expose_event () 函數中定義的 Cairo 圖形覆蓋掉,因此需要調用 gtk_widget_set_app_paintable () 函數通知 GTK+ 不要這麼幹。如果是在 GtkDrawingArea widget 中繪製 Cairo 圖形,則可省區這一步。

cairo_t *cr;

cr = gdk_cairo_create (widget->window);

Cairo 圖形繪製工作是在 on_expose_event () 函數中進行的,在該函數中,我們為 GTK+ 系統創建了一個 Cairo 環境,並在該環境中繪製了一行文本。

「轉貼」Cairo 圖形指南 (2) —— Cairo 概念

本文講述 Cairo 圖形庫中一些有用的定義/概念,理解它們可以幫助你更好的理解 Cairo 繪圖模型。

環境 (Context)

使用 Cairo 繪圖,必須要首先創建 Cairo 環境 (Context)。Cairo 環境保存著所有的圖形狀態參數,這些參數描述了圖形的構成,譬如線條寬度、顏色、要繪製的外觀 (Surface) 以及其它一些信息。Cairo 環境允許真正的繪圖函數使用很少的一部分參數,以此提高接口的易用性。調用 gdk_cairo_create () 函數可為所繪製的圖形創建一個 Cairo 環境。

cairo_t * cr;
cr = gdk_cairo_create (widget->window);

這兩行代碼創建了一個 Cairo 環境,並且這個 Cairo 環境是關聯到 GdkDrawable 對象上的。cairo_t 結構體包含了當前渲染設備的狀態,也包含了所繪製圖形的坐標。從技術上來講,cairo_t 就是所謂的 Cairo 環境。

Cairo 所有的繪圖函數都要去操作 cairo_t 對象。一個 Cairo 環境可以被關聯到一種特定的外觀,譬如 pdf、svg、png、GdkDrawable 等。

GDK 沒有對 Cairo API 進行封裝,它只允許創建一個可基於 GdkDrawable 對象繪製圖形的 Cairo 環境。有一些 GDK 函數可以將 GDK 的矩形或填充區域轉換為 Cairo Path (路徑),然後使用 Cairo 繪圖與渲染。

路徑 (Path)

一條 Path(路徑)通常是由一條或多條首位相接的直線段構成的,也可以由直線段與曲線段構成。路徑可分為 Open(開放)類型與 Closed(閉合)類型,前者的首尾端點不重合,後者的首尾端點重合。

在 Cairo 中,繪圖要從一條空路徑開始,首先定義一條路徑,然後通過繪製/填充操作使之可見。要注意的是,每次調用 cairo_stroke () 或 cairo_fill () 函數之後,路徑會被清空,不得不再定義新的路徑。

一條路徑可由一些子路徑構成。

源 (Source)

源好比繪圖中所使用的畫筆/顏料,使用它來繪製/填充圖形輪廓。有 4 種基本的源:color、gradient、pattern 與 image。

外觀 (Surface)

Surface 就是要繪製圖形的最終體現形式,譬如可使用 PDF 或 PostScript 外觀實現文本內容的渲染,或者使用 Xlib、Win32 外觀實現屏幕繪圖。

Cairo 具體有那些外觀類型,可參考其定義:

typedef enum _cairo_surface_type {
CAIRO_SURFACE_TYPE_IMAGE,
CAIRO_SURFACE_TYPE_PDF,
CAIRO_SURFACE_TYPE_PS,
CAIRO_SURFACE_TYPE_XLIB,
CAIRO_SURFACE_TYPE_XCB,
CAIRO_SURFACE_TYPE_GLITZ,
CAIRO_SURFACE_TYPE_QUARTZ,
CAIRO_SURFACE_TYPE_WIN32,
CAIRO_SURFACE_TYPE_BEOS,
CAIRO_SURFACE_TYPE_DIRECTFB,
CAIRO_SURFACE_TYPE_SVG,
CAIRO_SURFACE_TYPE_OS2
} cairo_surface_type_t;

蒙板 (Mask)

在源作用於外觀之前,可對其實現過濾,蒙板 (mask) 即是過濾器。蒙板決定哪些源可被顯示。蒙板不透明的部分允許複製源至外觀,蒙板透明的部分則禁止複製源至外觀。

圖案 (Pattern)

圖案表示被繪製到外觀的源。在 Cairo 中,圖案是一種可以讀取的內容,可用作繪圖操作的源或蒙板。圖案可以是純色模式、基於外觀的模式以及漸變模式。

[轉貼]Cairo 圖形指南 (1) —— 簡介

歡迎閱讀 Cairo 繪圖指南,這份指南會向你講述 Cairo 二維矢量繪圖庫的基本知識以及一些高級問題。指南中的示例採用 C 語言實現,其中大部分使用了 GTK+ 庫。

二維矢量圖形

計算機圖形可分為兩類,矢量圖形與光柵圖形。光柵圖形是將圖像表示為像素點集。矢量圖形則是使用一些幾何圖元(點、直線、曲線、多邊形等)表示圖像,這些圖元是使用數學公式生成的。

這兩類計算機圖形表達方式各有所長短。相較於光柵圖形,矢量圖形存在以下優越性:

  • 圖形文件更小
  • 可任意縮放
  • 平移、縮放、填充或旋轉等圖形變換操作對圖形質量無影響

Cairo

Cairo 是用於繪製二維矢量圖形的庫,採用 C 語言實現,又被許多其它計算機語言所綁定,譬如 Python、PERL、C++、C#、Java。Cairo 是跨平台庫,可運行於 Linux、BSD、OSX 等操作系統。

Cairo 支持多種後端 (backend):

  • X Window 系統
  • Win32 GDI
  • Mac OS X Quartz
  • PNG
  • PDF
  • PostScript
  • SVG

這些後端意味著可使用 Cairo 庫在 Windows、Linux/BSD、OSX 等平台的窗口中繪圖,也可以用於生成 PNG 圖片、PDF/PostScript/SVG 文件。

與 Windows 操作系統的 GDI+ 以及 Mac OS 的 Quartz 2D 庫相比,Cairo 是自由軟件庫。自 GTK+ 2.8 版本開始,Cairo 成為 GTK+ 庫的一部分。

示例的編譯

本指南中的所有示例均採用 C 語言實現,可使用 gcc 編譯它們,編譯命令格式如下:

$ gcc -o example `pkg-config --cflags --libs gtk+-2.0` example.c

2010年11月7日 星期日

「轉貼」android java.util.zip.ZipException: duplicate entry: hyts_Foo.c

這個標題有點長,是因為直接貼訊息。編譯 android cts 時出現的錯誤,我的解決辦法就是把錯誤訊息中的重複檔案砍了....包括

./dalvik/libcore/support/src/test/resources/hyts_Foo.c 及
./dalvik/libcore/dom/src/test/resources/ 底下的
hc_staff.xml
staff2.xml
staffNS.dtd
xhtml1-strict.dtd
staff2.dtd
staff.dtd
staff.xml
staffNS.xml

2010年10月1日 星期五

GNU Scientific Library (GSL) [轉貼]

The GNU Scientific Library (GSL) is a numerical library for C and C++ programmers. It is free software under the GNU General Public License.
The library provides a wide range of mathematical routines such as random number generators, special functions and least-squares fitting. There are over 1000 functions in total with an extensive test suite.GNU Scientific Library (GSL) 是一個內含許多數值及科學運算函式的 C/C++ 函式庫,內含超過 1000 個以上的函式(例如︰數值微分小波轉換排序..等等) ,並且可以使用在各種作業系統平台。在 GSL 在 Windows開發環境下的使用 中有簡單說明如何在 Windows 環境使用 GSL ,以下則是再詳細一點介紹如何在 Visual C++ 6.0 的 IDE (整合型視窗介面) 下使用︰1. 首先到 http://gnuwin32.sourceforge.net/packages/gsl.htm 下載 BinariesDeveloper files 。2. 將 Binaries package 內 bin 子目錄下的 libgsl.dll, libgslcblas.dll 兩個檔案複製到 C:\Windows\System32 中。3. 將 Developer files 解壓縮後,在 VC 的 IDE 中設定 include, lib 子目錄的路徑。4. 由於此版本的 lib 子目錄中不含 .lib 檔,必須用以下指令產生。請先開啟 DOS 模式視窗(附屬應用程式/命令提式字元),切換目錄到 lib 目錄下,並下達︰
lib /machine:i386 /def:libgsl.deflib /machine:i386 /def:libgslcblas.def即可產生 libgsl.lib, libgslcblas.lib 兩個檔案。5. 在 VC 專案中加入 libgsl.lib, libgslcblas.lib 這 2 個 lib 到 link 參數中。6. 在 VC 專案的 Preprocessor definitions 中加入 GSL_DLL。6. 可用函式及說明請見 Reference Manual 。ps. GSL是使用C語法寫成,故並沒有使用類別(class),而是以結構(struct)及函式(function)組成,不過 GSL 仍可以用在 C++ 編繹器,並與 C++ 程式相容。