GTK+中文社区(gtk.awaysoft.com)

 找回密码
 马上加入

QQ登录

只需一步,快速开始

查看: 3832|回复: 0

[转]Cairo 图形指南 (11) —— 图像

[复制链接]
  • TA的每日心情
    奋斗
    2021-11-19 13:15
  • 签到天数: 20 天

    连续签到: 1 天

    [LV.4]偶尔看看III

    发表于 2011-2-3 02:22:47 | 显示全部楼层 |阅读模式
       

    在这一篇里,要讲述图像的处理。先是演示如何在 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 <cairo.h>
    #include <gtk/gtk.h>

    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 <cairo.h>
    #include <gtk/gtk.h>


    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 <cairo.h>
    #include <gtk/gtk.h>


    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 < count; 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 < count; j++) {
            cairo_move_to(ic, 0, i+j);
            cairo_line_to(ic, w, i+j);
        }
    }



    这是该示例的主要逻辑,我们逐渐的将线绘制到各区域。



    原文地址:http://liyanrui.is-programmer.com/2010/4/8/cairo-image.16682.html


      
    *滑块验证:
    您需要登录后才可以回帖 登录 | 马上加入

    本版积分规则

    申请友链|Archiver|小黑屋|手机版|GTK+中文社区 ( 粤ICP备13080851号 )

    我要啦免费统计

    GMT+8, 2024-3-29 23:48 , Processed in 0.377055 second(s), 7 queries , Redis On.

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表