Cairo FAQ Images in Cairo

Материал из Wiki.crossplatform.ru

Версия от 09:00, 19 марта 2009; ViGOur (Обсуждение | вклад)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск

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. 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.

center

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 created this 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 displaying the 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.

center