|
|
Строка 1: |
Строка 1: |
- | In this part of the Cairo C API tutorial, we will talk about transparency. We will provide some basic definitions and two interesting transparency effects.
| |
| | | |
- | Transparency is the quality of being able to see through a material.
| |
- | The easiest way to understand transparency is to imagine a piece of glass or water. Technically, the rays of light can go through the glass and this way we can see objects behind the glass.
| |
- |
| |
- | In computer graphics, we can achieve transparency effects using <b>alpha compositing</b>.
| |
- | Alpha compositing is the process of combining an image with a background to create the appearance of partial transparency.
| |
- |
| |
- | The composition process uses an <b>alpha channel</b>.
| |
- | Alpha channel is an 8-bit layer in a graphics file format that is used for expressing translucency (transparency). The extra eight bits per pixel serves as a mask and represents 256 levels of translucency.
| |
- | <br>(answers.com, wikipedia.org)
| |
- |
| |
- | == Transparent rectangles ==
| |
- |
| |
- | The first example will draw ten rectangles with different levels of transparency.
| |
- |
| |
- | <source lang="cpp">
| |
- | #include <cairo.h>
| |
- | #include <gtk/gtk.h>
| |
- |
| |
- | static gboolean
| |
- | on_expose_event(GtkWidget *widget,
| |
- | GdkEventExpose *event,
| |
- | gpointer data)
| |
- | {
| |
- | cairo_t *cr;
| |
- |
| |
- | cr = gdk_cairo_create(widget->window);
| |
- |
| |
- | gint i;
| |
- | for ( i = 1; i <= 10; i++) {
| |
- | cairo_set_source_rgba(cr, 0, 0, 1, i*0.1);
| |
- | cairo_rectangle(cr, 50*i, 20, 40, 40);
| |
- | cairo_fill(cr);
| |
- | }
| |
- |
| |
- |
| |
- | 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), 590, 90);
| |
- | gtk_window_set_title(GTK_WINDOW(window), "transparency");
| |
- |
| |
- | gtk_widget_set_app_paintable(window, TRUE);
| |
- | gtk_widget_show_all(window);
| |
- |
| |
- | gtk_main();
| |
- |
| |
- | return 0;
| |
- | }
| |
- | </source>
| |
- |
| |
- | The <b>cairo_set_source_rgba()</b> has an optional alpha parameter to provide transparency.
| |
- |
| |
- | <source lang="cpp">
| |
- | gint i;
| |
- | for ( i = 1; i <= 10; i++) {
| |
- | cairo_set_source_rgba(cr, 0, 0, 1, i*0.1);
| |
- | cairo_rectangle(cr, 50*i, 20, 40, 40);
| |
- | cairo_fill(cr);
| |
- | }
| |
- | </source>
| |
- |
| |
- | This code creates ten rectangles with alpha values from 0.1 ... 1.
| |
- |
| |
- | [[image: cairo_faq_transparency.png | center]]
| |
- |
| |
- | == Fade out effect ==
| |
- |
| |
- | In the next example, we will fade out an image. The image will gradually get more transparent until it is completely invisible.
| |
- |
| |
- | <source lang="cpp">
| |
- | #include <cairo.h>
| |
- |
| |
- | #include <gtk/gtk.h>
| |
- |
| |
- |
| |
- | cairo_surface_t *image;
| |
- | gboolean timer = TRUE;
| |
- |
| |
- | static gboolean
| |
- | on_expose_event(GtkWidget *widget,
| |
- | GdkEventExpose *event,
| |
- | gpointer data)
| |
- | {
| |
- | cairo_t *cr;
| |
- |
| |
- | cr = gdk_cairo_create(widget->window);
| |
- |
| |
- | static double alpha = 1;
| |
- | double const delta = 0.01;
| |
- |
| |
- | cairo_set_source_surface(cr, image, 10, 10);
| |
- | cairo_paint_with_alpha(cr, alpha);
| |
- |
| |
- | alpha -= delta;
| |
- |
| |
- | if (alpha <= 0) timer = FALSE;
| |
- |
| |
- | cairo_destroy(cr);
| |
- |
| |
- | 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;
| |
- | GtkWidget *darea;
| |
- |
| |
- | 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);
| |
- |
| |
- | darea = gtk_drawing_area_new();
| |
- | gtk_container_add(GTK_CONTAINER (window), darea);
| |
- |
| |
- | g_signal_connect(darea, "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), width+20, height+20);
| |
- |
| |
- | gtk_window_set_title(GTK_WINDOW(window), "fade out");
| |
- | g_timeout_add(50, (GSourceFunc) time_handler, (gpointer) window);
| |
- | gtk_widget_show_all(window);
| |
- |
| |
- | gtk_main();
| |
- |
| |
- | cairo_surface_destroy(image);
| |
- |
| |
- | return 0;
| |
- | }
| |
- | </source>
| |
- |
| |
- | In our example we display an image that will gradually fade out. We use a photo of ruins of a Turna Castle, located in east part of Slovakia.
| |
- |
| |
- | <source lang="cpp">
| |
- | image = cairo_image_surface_create_from_png("turnacastle.png");
| |
- | </source>
| |
- |
| |
- | For efficiency reasons, the creation of the image surface is placed inside the main function.
| |
- |
| |
- | <source lang="cpp">
| |
- | cairo_set_source_surface(cr, image, 10, 10);
| |
- | </source>
| |
- |
| |
- | Here we set the source for painting.
| |
- |
| |
- | <source lang="cpp">
| |
- | cairo_paint_with_alpha(cr, alpha);
| |
- | </source>
| |
- |
| |
- | The fade out effect is created using the <b>cairo_paint_with_alpha()</b> function call. This function uses transparency value as a mask.
| |
- |
| |
- | <source lang="cpp">
| |
- | alpha -= delta;
| |
- | </source>
| |
- |
| |
- | We decrease the alpha value each time, the <b>on_expose_event()</b> function is executed.
| |
- |
| |
- | <source lang="cpp">
| |
- | if (alpha <= 0) timer = FALSE;
| |
- | </source>
| |
- |
| |
- | If the alpha value is less or equal to zero, we finished our fade out effect. We set the timer value to FALSE. We do not need our timer function anymore.
| |
- |
| |
- | <source lang="cpp">
| |
- | g_timeout_add(50, (GSourceFunc) time_handler, (gpointer) window);
| |
- | </source>
| |
- |
| |
- | We create a timer function. This function will call <b>time_handler</b> every 50 ms.
| |
- |
| |
- | <source lang="cpp">
| |
- | static gboolean
| |
- | time_handler (GtkWidget *widget)
| |
- | {
| |
- | if (widget->window == NULL) return FALSE;
| |
- |
| |
- | if (!timer) return FALSE;
| |
- |
| |
- | gtk_widget_queue_draw(widget);
| |
- | return TRUE;
| |
- | }
| |
- |
| |
- | </source>
| |
- |
| |
- | The main function of the <b>time_handler</b> call is to redraw the window regularly.
| |
- | When the function returns FALSE, the timeout function will cease to work.
| |
- |
| |
- | <source lang="cpp">
| |
- | if (widget->window == NULL) return FALSE;
| |
- | </source>
| |
- |
| |
- | You might wonder, what this code line is there for. It is a simple check. If the timeout value is too small, like 5 ms, it happens that while closing the application, the window is already destroyed but still we get the timeout function executed.
| |
- | This code line prevents from manipulating with a window in such cases.
| |
- |
| |
- | [[image: cairo_faq_fadeout.png | center]]
| |
- |
| |
- | == Waiting demo ==
| |
- |
| |
- | In this examle, we use transparency effect to create a waiting demo. We will draw 8 lines that will gradually fade out creating an illusion, that a line is moving. Such effects are often used to inform users, that a lengthy task is going on behind the scenes. An example is streaming video over the internet.
| |
- |
| |
- | <source lang="cpp">
| |
- | #include <cairo.h>
| |
- |
| |
- | #include <gtk/gtk.h>
| |
- | #include <math.h>
| |
- |
| |
- | static gushort count = 0;
| |
- |
| |
- | static gboolean
| |
- | on_expose_event(GtkWidget *widget,
| |
- | GdkEventExpose *event,
| |
- | gpointer data)
| |
- | {
| |
- | cairo_t *cr;
| |
- |
| |
- | cr = gdk_cairo_create(widget->window);
| |
- |
| |
- | static gdouble const trs[8][8] = {
| |
- | { 0.0, 0.15, 0.30, 0.5, 0.65, 0.80, 0.9, 1.0 },
| |
- | { 1.0, 0.0, 0.15, 0.30, 0.5, 0.65, 0.8, 0.9 },
| |
- | { 0.9, 1.0, 0.0, 0.15, 0.3, 0.5, 0.65, 0.8 },
| |
- | { 0.8, 0.9, 1.0, 0.0, 0.15, 0.3, 0.5, 0.65},
| |
- | { 0.65, 0.8, 0.9, 1.0, 0.0, 0.15, 0.3, 0.5 },
| |
- | { 0.5, 0.65, 0.8, 0.9, 1.0, 0.0, 0.15, 0.3 },
| |
- | { 0.3, 0.5, 0.65, 0.8, 0.9, 1.0, 0.0, 0.15 },
| |
- | { 0.15, 0.3, 0.5, 0.65, 0.8, 0.9, 1.0, 0.0, }
| |
- | };
| |
- |
| |
- |
| |
- | gint width, height;
| |
- | gtk_window_get_size(GTK_WINDOW(widget), &width, &height);
| |
- |
| |
- | cairo_translate(cr, width / 2, height /2);
| |
- |
| |
- | gint i = 0;
| |
- | for (i = 0; i < 8; i++) {
| |
- | cairo_set_line_width(cr, 3);
| |
- | cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
| |
- | cairo_set_source_rgba(cr, 0, 0, 0, trs[count%8][i]);
| |
- |
| |
- | cairo_move_to(cr, 0.0, -10.0);
| |
- | cairo_line_to(cr, 0.0, -40.0);
| |
- | cairo_rotate(cr, M_PI/4);
| |
- |
| |
- | cairo_stroke(cr);
| |
- | }
| |
- |
| |
- | cairo_destroy(cr);
| |
- |
| |
- | return FALSE;
| |
- | }
| |
- |
| |
- | static gboolean
| |
- | time_handler (GtkWidget *widget)
| |
- | {
| |
- | count += 1;
| |
- | gtk_widget_queue_draw(widget);
| |
- | return TRUE;
| |
- | }
| |
- |
| |
- | int main(int argc, char *argv[])
| |
- | {
| |
- | GtkWidget *window;
| |
- | GtkWidget *darea;
| |
- |
| |
- | 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, 150);
| |
- |
| |
- | gtk_window_set_title(GTK_WINDOW(window), "waiting demo");
| |
- |
| |
- | gtk_widget_set_app_paintable(window, TRUE);
| |
- | gtk_widget_show_all(window);
| |
- | g_timeout_add(100, (GSourceFunc) time_handler, (gpointer) window);
| |
- |
| |
- | gtk_main();
| |
- |
| |
- | return 0;
| |
- | }
| |
- |
| |
- | </source>
| |
- |
| |
- | We draw eight lines with eight different alpha values.
| |
- |
| |
- | <source lang="cpp">
| |
- | static gdouble const trs[8][8] = {
| |
- | { 0.0, 0.15, 0.30, 0.5, 0.65, 0.80, 0.9, 1.0 },
| |
- | { 1.0, 0.0, 0.15, 0.30, 0.5, 0.65, 0.8, 0.9 },
| |
- | { 0.9, 1.0, 0.0, 0.15, 0.3, 0.5, 0.65, 0.8 },
| |
- | { 0.8, 0.9, 1.0, 0.0, 0.15, 0.3, 0.5, 0.65},
| |
- | { 0.65, 0.8, 0.9, 1.0, 0.0, 0.15, 0.3, 0.5 },
| |
- | { 0.5, 0.65, 0.8, 0.9, 1.0, 0.0, 0.15, 0.3 },
| |
- | { 0.3, 0.5, 0.65, 0.8, 0.9, 1.0, 0.0, 0.15 },
| |
- | { 0.15, 0.3, 0.5, 0.65, 0.8, 0.9, 1.0, 0.0, }
| |
- | };
| |
- | </source>
| |
- |
| |
- | This is a two dimensional array of transparency values used in this demo. There are 8 rows, each for one state. Each of the 8 lines will continuosly use these values.
| |
- |
| |
- | <source lang="cpp">
| |
- | cairo_set_line_width(cr, 3);
| |
- | cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
| |
- | </source>
| |
- |
| |
- | We make the lines a bit thicker, so that they are better visible. We draw the lines with rouded caps.
| |
- |
| |
- | <source lang="cpp">
| |
- | cairo_set_source_rgba(cr, 0, 0, 0, trs[count%8][i]);
| |
- | </source>
| |
- |
| |
- | Here we define the transparency value for a line.
| |
- |
| |
- | <source lang="cpp">
| |
- | cairo_move_to(cr, 0.0, -10.0);
| |
- | cairo_line_to(cr, 0.0, -40.0);
| |
- | cairo_rotate(cr, M_PI/4);
| |
- | </source>
| |
- |
| |
- | These code will draw each of the eight lines.
| |
- |
| |
- | <source lang="cpp">
| |
- | g_timeout_add(100, (GSourceFunc) time_handler, (gpointer) window);
| |
- | </source>
| |
- |
| |
- | We use a timer function to create animation.
| |
- |
| |
- | [[image: cairo_faq_waitingdemo.gif | center]]
| |
- |
| |
- |
| |
- | [[Категория:GTK+]]
| |
- | [[Категория:Cairo]]
| |