[cairo] Problems with transparent background
Martin Fischer
martinfischer8 at t-online.de
Wed Feb 22 18:30:13 UTC 2017
Hi,
I'm working on an CAD application that needs to be ported to GTK3. For
that purpose I need to find out the best way to handle dragging drawing
elements from one position to another.
My idea is to create a surface that has all the static elemants. Another
surface should have a transparent background and the element that is
currently moved.
To try out that concept I created a small application:
----
/*
* gcc raster2.c -o raster2 `pkg-config --cflags --libs gtk+-2.0`
*/
#include <gtk/gtk.h>
#include <math.h>
#include <time.h>
#include <stdlib.h>
struct {
cairo_surface_t *image;
cairo_surface_t *ball;
} glob;
double px = 10;
double py = 100;
double vx = 2;
double vy = 2;
/* create a bunch of green lines on white as background */
void CreateBackground(cairo_surface_t *destination )
{
cairo_t *cr;
int i;
glob.image = cairo_surface_create_similar_image (destination,
CAIRO_FORMAT_ARGB32,
200,
200);
cr = cairo_create( glob.image );
cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
cairo_paint(cr);
cairo_set_source_rgba(cr,0,1.0,0, 1.0);
for( i = 0; i <= 200; i+=10 ) {
cairo_move_to( cr, i, 0 );
cairo_line_to( cr, i, 200 );
cairo_move_to( cr, 0, i );
cairo_line_to(cr, 200, i );
}
cairo_stroke(cr);
cairo_destroy(cr);
}
/* create a transparent background and a red dot */
void CreateForeground()
{
cairo_t *cr;
cr = cairo_create( glob.ball );
/* why has alpha to be greater than 0.0? */
cairo_set_source_rgba (cr, 0, 0, 0, 0.01);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_paint (cr);
cairo_set_source_rgba(cr,1.0,0,0, 1);
cairo_arc(cr, px, py, 6, 0, 2*M_PI);
cairo_fill(cr);
cairo_destroy(cr);
}
/* when called, create a new foreground surface and invalidate old
* position. Finally calculate the next position */
gboolean timeout(gpointer data)
{
GtkWidget *widget = GTK_WIDGET(data);
GdkRectangle rect;
if (!widget->window) return TRUE;
CreateForeground();
rect.x = px - 3;
rect.y = py - 3;
rect.width = 6;
rect.height = 6;
gdk_window_invalidate_rect( widget->window, &rect, FALSE );
gtk_widget_queue_draw(widget);
if (px <= 3 || px >= 200-3) vx = -vx ;
if(py <= 3 || py >= 200-3 ) vy = -vy;
px += vx;
py += vy;
return TRUE;
}
/* draw the animation:
* 1. clip to the changed area
* 2. draw the background
* 3. draw the surface containing the red dot on top
*/
gboolean expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
cairo_t *cr = gdk_cairo_create(widget->window);
if( glob.image == NULL )
CreateBackground( cairo_get_target (cr));
cairo_rectangle(cr, event->area.x, event->area.y,
event->area.width, event->area.height);
cairo_clip(cr);
cairo_set_source_surface(cr, glob.image, 0, 0);
cairo_paint(cr);
cairo_set_operator( cr, CAIRO_OPERATOR_OVER );
cairo_set_source_surface( cr, glob.ball, 0, 0 );
cairo_paint(cr);
cairo_destroy( cr );
return FALSE;
}
int main(int argc, char *argv[])
{
char *title = "Test";
int sx = 200;
int sy = 200;
gtk_init(NULL,NULL);
glob.ball = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA,
NULL);
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window),title);
gtk_container_set_border_width(GTK_CONTAINER (window), 2);
g_signal_connect(window, "destroy",G_CALLBACK(gtk_main_quit),&window);
GtkWidget *drawing_area = gtk_drawing_area_new();
if( drawing_area ) {
GdkScreen *screen = gtk_widget_get_screen(drawing_area);
GdkColormap *colormap = gdk_screen_get_rgba_colormap(screen);
if( colormap == NULL ) {
printf("Screen does not support alpha!\n");
}
}
gtk_widget_set_size_request(drawing_area, sx, sy);
g_signal_connect(drawing_area,"expose_event",G_CALLBACK(expose),NULL);
gtk_container_add(GTK_CONTAINER(window), drawing_area);
gtk_widget_show(drawing_area);
g_timeout_add(10, timeout, window);
if (!GTK_WIDGET_VISIBLE (window))
gtk_widget_show_all(window);
else {
gtk_widget_destroy (window);
window = NULL;
}
gtk_main();
cairo_surface_destroy(glob.image);
cairo_surface_destroy(glob.ball);
}
----
The expected result is a small window with e few green lines and a red
circle moving across it.
This mostly works with one exception. The alpha value for the
transparent background has to be set to a value slightly larger than the
expected 0.0! (See CreateForeground()). If I set it to 0.0 I get some
strange flickering but no correct rendering.
What am I doing wrong? Any hints and tips welcome.
Regards,
Martin
More information about the cairo
mailing list