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

转载 2012年03月30日 08:21:48

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



Clipping

Clipping is restricting of drawing to a certain area. This is done for effeciency reasons and to create interesting effects.

Clipping image

In the following example we will be clipping an image.

#include <cairo.h>
#include <gtk/gtk.h>
#include <math.h>

cairo_surface_t *image;

static gboolean
on_expose_event(GtkWidget *widget,
    GdkEventExpose *event,
    gpointer data)
{
  cairo_t *cr;

  static gint pos_x = 128;
  static gint pos_y = 128;
  gint radius = 40;  

  static gint delta[] = { 3, 3 };

  cr = gdk_cairo_create(widget->window);

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

  if (pos_x < 0 + radius) {
      delta[0] = rand() % 4 + 5;
  } else if (pos_x > width - radius) {
      delta[0] = -(rand() % 4 + 5);
  }

  if (pos_y < 0 + radius) {
      delta[1] = rand() % 4 + 5;
  } else if (pos_y > height - radius) {
      delta[1] = -(rand() % 4 + 5);
  }

  pos_x += delta[0];
  pos_y += delta[1];

  cairo_set_source_surface(cr, image, 1, 1);
  cairo_arc(cr, pos_x, pos_y, radius, 0, 2*M_PI);
  cairo_clip(cr);
  cairo_paint(cr);

  cairo_destroy(cr);

  return FALSE;
}

static gboolean
time_handler (GtkWidget *widget)
{
  if (widget->window == NULL) return FALSE;
  gtk_widget_queue_draw(widget);
  return TRUE;
}

int main(int argc, char *argv[])
{
  GtkWidget *window;
  gint width, height;  

  image = cairo_image_surface_create_from_png("turnacastle.png");
  width = cairo_image_surface_get_width(image);
  height = cairo_image_surface_get_height(image); 


  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), width+2, height+2); 

  gtk_widget_set_app_paintable(window, TRUE);
  gtk_widget_show_all(window);
  g_timeout_add(100, (GSourceFunc) time_handler, (gpointer) window);

  gtk_main();

  cairo_surface_destroy(image);

  return 0;
}

In this example, we will clip an image. A circle is moving on the screen and showing a part of the underlying image. This is as if we looked through a hole.

 if (pos_x < 0 + radius) {
     delta[0] = rand() % 4 + 5;
 } else if (pos_x > width - radius) {
     delta[0] = -(rand() % 4 + 5);
 }

If the circle hits the left or the right side of the window, the direction of the circle movement changes randomly.Same for the top and bottom sides.

 cairo_set_source_surface(cr, image, 1, 1);
 cairo_arc(cr, pos_x, pos_y, radius, 0, 2*M_PI);

Here we draw the image and a circle. Notice that we do not draw onto the window at the moment, but only in memory.

 cairo_clip(cr);

The cairo_clip() sets a clipping region. The clipping region is the current path used. The current path was created by the cairo_arc() function call.

 cairo_paint(cr);

The cairo_paint() paints the current source everywhere within the current clip region.


Clipping image
Figure: Clipping image

Clipping a rectangle

The following example is inspired by a similar example, that I found in the Java2D demo.

#include <cairo.h>
#include <gtk/gtk.h>
#include <math.h>


static gboolean
on_expose_event(GtkWidget *widget,
    GdkEventExpose *event,
    gpointer data)
{
  cairo_t *cr;
  cr = gdk_cairo_create(widget->window);

  static gboolean xdirection = TRUE;

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

  static gdouble rotate = 0;

  static gint bigx = 20;
  static gint bigy = 200;
  static gint delta = 1;


  if (bigx > width) {
      xdirection = FALSE;
      delta = -delta;
      bigx = width;
  }

  if (bigx < 1) {
      bigx = 1;
      delta = -delta; 
  }

  if (bigy > height) {
      xdirection = TRUE;
      delta = -delta;
      bigy = height;
  }

  if (bigy < 1) {
      delta = -delta; 
      bigy = 1;
  }

  if (xdirection) {
      bigx += delta;
  } else {
      bigy += delta;
  }

  cairo_translate(cr, width / 2, height /2);

  cairo_rectangle(cr, -bigx/2, -bigy/2, bigx-2, bigy-2);
  cairo_set_source_rgb(cr, 0, 0, 0);
  cairo_set_line_width(cr, 1);  
  cairo_stroke(cr);

  cairo_rotate(cr, rotate);
  rotate += 0.01;

  cairo_rectangle(cr, -50, -25, 100, 50);
  cairo_stroke(cr);

  GdkRectangle bigrect;
  GdkRectangle rect;
  GdkRectangle intersect;

  bigrect.x = -bigx/2;
  bigrect.y = -bigy/2;
  bigrect.width = bigx -2;
  bigrect.height = bigy -2;

  rect.x = -50;
  rect.y = -25;
  rect.width = 100;
  rect.height = 50;

  gdk_rectangle_intersect(&bigrect, &rect, &intersect);
  cairo_rectangle(cr, intersect.x, intersect.y, intersect.width, intersect.height);
  cairo_fill(cr); 

  cairo_destroy(cr);

  return FALSE;
}

static gboolean
time_handler (GtkWidget *widget)
{
  if (widget->window == NULL) return FALSE;
  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);

  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), 250, 200); 

  gtk_widget_set_app_paintable(window, TRUE);
  gtk_widget_show_all(window);
  g_timeout_add(5, (GSourceFunc) time_handler, (gpointer) window);

  gtk_main();

  return 0;
}

In this example, we have two rectangles. A big one and a rotating one. The big rectangle continuosly shrinks and grows. The smaller one is rotating. We apply a intersect set operation on both rectangles. The area that is inside both rectangles is painted in black color. Note, that the intersection is not a perfect rectangle. To make it simpler, we approximate the area to a rectangle.

 static gboolean xdirection = TRUE;

This variable determines the direction, in which the big rectangle is moving.

 if (bigx > width) {
     xdirection = FALSE;
     delta = -delta;
     bigx = width;
 }

If the big rectangle is as big as the width of the window, we change the direction. The rectangle begins shrinking in the y direction.

 cairo_rotate(cr, rotate);

The cairo_rotate() rotates the smaller rectangle.

 GdkRectangle bigrect;
 GdkRectangle rect;
 GdkRectangle intersect;

Here we define three rectangular areas. The intersect rectangle will be the intersection of our two rectangles.

 gdk_rectangle_intersect(&bigrect, &rect, &intersect);

Here we apply the intersection operation.

 cairo_rectangle(cr, intersect.x, intersect.y, intersect.width, intersect.height);
 cairo_fill(cr); 

We paint the area of the intersect rectangle.


Clipping a rectangle
Figure: Clipping a rectangle

Mask

Before the source is applied to the surface, it is filtered first. The mask is used as a filter. The mask determines, where the sourse is applied and where not. Opaque parts of the mask allow to copy the source. Transparent parts do not let to copy the source to the surface.

#include <cairo.h>
#include <gtk/gtk.h>


static gboolean
on_expose_event(GtkWidget *widget,
    GdkEventExpose *event,
    gpointer data)
{
  cairo_t *cr;
  cairo_surface_t *surface;
  cairo_set_source_rgb(cr, 0, 0, 0);

  cr = gdk_cairo_create(widget->window);
  surface = cairo_image_surface_create_from_png("omen.png");
  cairo_mask_surface(cr, surface, 0, 0);
  cairo_fill(cr);

  cairo_surface_destroy(surface);
  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), 305, 100); 

  gtk_window_set_title(GTK_WINDOW(window), "mask");
  gtk_widget_set_app_paintable(window, TRUE);
  gtk_widget_show_all(window);

  gtk_main();

  return 0;
}

This small example clearly shows the basic idea behind the mask. The mask determines where to paint and where not to paint.

 surface = cairo_image_surface_create_from_png("omen.png");
 cairo_mask_surface(cr, surface, 0, 0);
 cairo_fill(cr);

We use an image as a mask, thus displaying it on the window.


Applying a mask
Figure: Applying a mask

This chapter was about clipping and masking in Cairo.



人工智能和图像处理方面的各种会议的评级

转载自:『http://www.cvchina.info/2010/08/31/conference-ranking-byar/』 人工智能和图像处理方面的各种会议的评级 澳大利亚政府和澳大利...
  • lqhbupt
  • lqhbupt
  • 2014年04月19日 20:14
  • 5016

个人开发安卓遇到的一些问题收集【仅解决个人问题】

此偏文章为个人开发安卓时候,遇到的问题收集及个人的解决办法,若有人和我遇到了同样的问题能帮助到大家最好,无法帮助到或您有更好的解决办法,请留言给我,谢谢。 个人遇到问题已解决部分: 1、The gra...
  • shankezh
  • shankezh
  • 2016年04月18日 13:21
  • 3586

【Java Tutorial中文版 开篇综述】 Oracle(甲骨文)公司Java最新官方教程【译文】

此篇为我博客【Java Tutorial】系列开篇综述。JavaTutorial是Oracle公司的官方教学教程,内容从认识Java到如何开发Java有着非常系统的体系,而且叙述清楚明了,非常适合Ja...
  • RuingMan
  • RuingMan
  • 2016年02月04日 17:28
  • 4308

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...
  • intruder83
  • intruder83
  • 2012年03月30日 08:18
  • 352

html5 svg 第九章 裁剪和屏蔽 Clipping and Masking

有时候,你不希望看到整个画面,例如,你可能想画一幅画,就好像是看到通过双筒望远镜或锁孔目镜或锁孔的边界之外的一切都将是无形的。或者,您可能要设置所显示的图像,仿佛透过半透明的窗帘观看的心情。SVG实现...
  • stary1
  • stary1
  • 2013年08月02日 22:33
  • 2651

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

In this part of the Cairo graphics programming tutorial, we will talk about transformations. ...
  • intruder83
  • intruder83
  • 2012年03月30日 08:22
  • 307

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

In this part of the Cairo C API tutorial, we will talk about transparency. We will provide some basi...
  • intruder83
  • intruder83
  • 2012年03月30日 08:19
  • 263

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...
  • intruder83
  • intruder83
  • 2012年03月30日 08:32
  • 236

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

The Cairo library supports various backends. In this section of the Cairo graphics tutorial, we will...
  • intruder83
  • intruder83
  • 2012年03月30日 08:15
  • 330

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...
  • intruder83
  • intruder83
  • 2012年03月30日 08:16
  • 244
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:The Cairo graphics tutorial -------Clipping and masking
举报原因:
原因补充:

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