|
|
| Строка 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]]
| |