The Cairo graphics tutorial -------Images in Cairo

转载 2012年03月30日 08:24:49

In this part of the Cairo graphics tutorial, we will talk about the images. We will show how to display an image on the GTK window. We will also create some effects with images.


Displaying an image

In the first example, we will display an image.

#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;
}

The example displays an image. The image size is 300x225. You can download it here.These are ruins of a medieval castle in Plavecke Podhradie in western part of the Slovakia.

 image = cairo_image_surface_create_from_png("plaveckycastle.png");

We create an image surface from a png image. For efficiency reasons, the function is called in the main function.

 cairo_set_source_surface(cr, image, 10, 10);

We create a source for painting from the previously created image surface.

 cairo_paint(cr);

We paint the source on the window.


Image
Figure: Image

Blind down effect

In this code example, we will blind down our image. This is similar to what we do with a roller-blind.

#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;
}

The idea behind the blind down effect is quite simple. The image is h pixels high. We draw 0, 1, 2 ... lines of 1px height, each cycle the portion of the image is 1px higher, until the whole image is visible.

 cairo_t *cr;
 cairo_t *ic;

We declare two cairo contexts. One will be tied to a GtkWindow and the other one to an image.

 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 
     image_width, image_height);
 ic = cairo_create(surface);

Here we create an image surface. An from this surface, we create a cairo context.

 cairo_rectangle(ic, 0, 0, w, h);
 cairo_fill(ic);

We will draw into the initially empty image a rectagle. The rectangle will be 1px higher each cycle. The image createdthis way will serve as a mask later.

  h += 1;
  if ( h == image_height) timer = FALSE;

We stop the timer function, when we draw the whole image on the GTK window.

 cairo_set_source_surface(cr, image, 10, 10);
 cairo_mask_surface(cr, surface, 10, 10);

The image of a castle is set as a source for painting. The cairo_mask_surface() paints the current source using the alpha channel of surface as a mask.

The spectrum effect

I call this a spectrum effect, because I do not have a better name for it. Maybe some of you remember the old times with ZX Spectrum computer. When you were loading an image into this computer, it was gradually appearing on the screen. The next example is loosly based on this experience.

#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;
}

In most details, the example is similar to the previous one. This time, we divide the image into n parts consisting of 8 lines.Each cycle each part of the image will get bigger by one pixel. The created image will serve again as a mask for displayingthe image of the castle.

 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);
     }
 }

Here is the main logic behind the example. We gradully draw lines into each of the n parts.


Spectrum
Figure: Spectrum

This chapter covered images in Cairo.



相关文章推荐

The Cairo graphics tutorial -------Clipping and masking

In this part of the Cairo tutorial, we will talk about clipping and masking. Clipping ...

The Cairo graphics tutorial -------Basic drawing in Cairo

In this part of the Cairo graphics tutorial, we will draw some basic primitives. We will draw simple...

The Cairo graphics tutorial -------Transformations

In this part of the Cairo graphics programming tutorial, we will talk about transformations. ...

The Cairo graphics tutorial -------Transparency

In this part of the Cairo C API tutorial, we will talk about transparency. We will provide some basi...

The Cairo graphics tutorial -------Custom GTK widget

In this part of the Cairo graphics tutorial, we will create a custom GTK widget, where we will use t...

The Cairo graphics tutorial -------Text in Cairo

In this part of the Cairo graphics tutorial, we will work with text. Soulmate In the first...

The Cairo graphics tutorial -------Shapes and fills in Cairo

In this part of the Cairo tutorial, we will create some basic and more advanced shapes. We will fill...

The Cairo graphics tutorial -------Cairo backends

The Cairo library supports various backends. In this section of the Cairo graphics tutorial, we will...

The Cairo graphics tutorial -------Cairo definitions

Cairo definitions In this part of the Cairo graphics tutorial, we will provide some useful definiti...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)