在這一篇裡,要講述圖像的處理。先是演示如何在 GTK+ 窗口中顯示一幅圖像,然後再製造一些特效。
圖像的顯示
在第一個例子裡,顯示了一幅圖像。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | # include
# include
cairo_surface_t *image; static gboolean on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data) { cairo_t *cr; cr = gdk_cairo_create (widget->window); cairo_set_source_surface(cr, image, 10 , 10 ); cairo_paint(cr); cairo_destroy(cr); return FALSE; } int main( int argc, char *argv[]) { GtkWidget *window; image = cairo_image_surface_create_from_png( "plaveckycastle.png" ); 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 , 250 ); gtk_widget_set_app_paintable(window, TRUE); gtk_widget_show_all(window); gtk_main(); cairo_surface_destroy(image); return 0 ; } |
這個示例顯示了一幅圖片,其尺寸為 300x225,可從這裡下載。這是斯洛伐克西部一個什麼地方(Plavecke Podhradie)的中世紀城堡的廢墟的一幅照片。
1 | image = cairo_image_surface_create_from_png( "plaveckycastle.png" ); |
用一幅 png 圖片來創建一份圖像外觀。出於效率的考慮,應在主函數中調用這個函數。
1 | cairo_set_source_surface(cr, image, 10, 10); |
基於前面構造的圖像外觀來創建源與外觀,用於圖像的繪製。
1 | cairo_paint(cr); |
繪製圖片。
垂簾效果(Blind Down)
在下面的代碼示例中,要垂簾顯示圖片,就像拉下窗簾的那種效果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | #include #include gboolean timer = TRUE; cairo_surface_t *image; static gboolean on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data) { cairo_t *cr; cairo_t *ic; cairo_surface_t *surface; static gdouble angle = 0; static gint image_width = 0; static gint image_height = 0; static gint w = 0; static gint h = 0; cr = gdk_cairo_create(widget->window); gint width, height; gtk_window_get_size(GTK_WINDOW(widget), &width, &height); image_width = cairo_image_surface_get_width(image); image_height = cairo_image_surface_get_height(image); w = image_width; surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, image_width, image_height); ic = cairo_create(surface); cairo_rectangle(ic, 0, 0, w, h); cairo_fill(ic); h += 1; if ( h == image_height) timer = FALSE; cairo_set_source_surface(cr, image, 10, 10); cairo_mask_surface(cr, surface, 10, 10); cairo_surface_destroy(surface); cairo_destroy(cr); cairo_destroy(ic); return FALSE; } static gboolean time_handler(GtkWidget *widget) { if (widget->window == NULL) return FALSE; if (!timer) return FALSE; gtk_widget_queue_draw(widget); return TRUE; } int main( int argc, char *argv[]) { GtkWidget *window; image = cairo_image_surface_create_from_png( "plaveckycastle.png" ); 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), 325, 250); gtk_window_set_title(GTK_WINDOW(window), "blind down" ); gtk_widget_set_app_paintable(window, TRUE); g_timeout_add(15, (GSourceFunc) time_handler, (gpointer) window); gtk_widget_show_all(window); gtk_main(); cairo_surface_destroy(image); return 0; } |
這個垂簾效果幕後的思想相當簡單。圖片的高度是 h 個像素,則可對其逐行進行繪製,直至圖片完全顯示。
1 2 | cairo_t *cr; cairo_t *ic; |
聲明兩個 cairo 環境,一個與 GtkWindow 相關聯,另一個與圖片相關聯。
1 2 | surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, image_width, image_height); ic = cairo_create(surface); |
創建一個圖像外觀,並通過它構造那個與圖像相關聯的 cairo 環境。
1 2 | cairo_rectangle(ic, 0, 0, w, h); cairo_fill(ic); |
在初始的空圖像中繪製一個矩形,它在循環顯示中會增加 1 個像素的高度。採用這種方式創建的圖像在後面要作為蒙板來用。
1 2 | h += 1; if ( h == image_height) timer = FALSE; |
整幅圖像繪製完畢後,停止計時器。
1 2 | cairo_set_source_surface(cr, image, 10, 10); cairo_mask_surface(cr, surface, 10, 10); |
城堡圖像被設置為要被繪製的源,並採用 surface 的 alpha 通道作為蒙板來繪製這個源。
光譜效果
將這種效果稱為光譜效果,因為作者不知道怎麼稱呼才好(我感覺叫百葉窗效果更好)。可能你還記得從前的 ZX 光譜計算機,在這種計算機上載入圖像時,它就逐漸的被顯示出來,下面的示例大致是模仿這種方式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | #include #include gboolean timer = TRUE; cairo_surface_t *image; static gboolean on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data) { cairo_t *cr; cairo_t *ic; cairo_surface_t *surface; static gdouble angle = 0; static gint w = 0; static gint h = 0; static gint image_width = 0; static gint image_height = 0; static gint count = 0; cr = gdk_cairo_create(widget->window); gint width, height; gtk_window_get_size(GTK_WINDOW(widget), &width, &height); surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, image_width, image_height); image_width = cairo_image_surface_get_width(image); image_height = cairo_image_surface_get_height(image); w = image_width; ic = cairo_create(surface); gint i, j; for (i = 0; i <= image_height; i+=7) { for (j=0 ; j <> cairo_move_to(ic, 0, i+j); cairo_line_to(ic, w, i+j); } } count++; if ( count == 8) timer = FALSE; cairo_stroke(ic); cairo_set_source_surface(cr, image, 10, 10); cairo_mask_surface(cr, surface, 10, 10); cairo_surface_destroy(surface); cairo_destroy(cr); cairo_destroy(ic); return FALSE; } static gboolean time_handler (GtkWidget *widget) { if (widget->window == NULL) return FALSE; if (!timer) return FALSE; gtk_widget_queue_draw(widget); return TRUE; } int main( int argc, char *argv[]) { GtkWidget *window; image = cairo_image_surface_create_from_png( "plaveckycastle.png" ); 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), 325, 250); gtk_widget_set_app_paintable(window, TRUE); g_timeout_add(400, (GSourceFunc) time_handler, (gpointer) window); gtk_widget_show_all(window); gtk_main(); cairo_surface_destroy(image); return 0; } |
這個示例的許多細節與上一個示例相似。這次,是將圖像分為每 8 行為一個區域。在每次循環中,8 個部分中每個區域增加一個像素高度。通過這種方式創建的圖像將再一次作為模板來顯示城堡圖像。
1 2 3 4 5 6 7 | gint i, j; for (i = 0; i <= image_height; i+=7) { for (j=0 ; j <> cairo_move_to(ic, 0, i+j); cairo_line_to(ic, w, i+j); } } |
這是該示例的主要邏輯,我們逐漸的將線繪製到各區域。
沒有留言:
張貼留言