[cairo] Problems with transparent background
Martin Fischer
martinfischer8 at t-online.de
Fri Feb 24 16:00:48 UTC 2017
Hi there,
none of the suggestions really solved the problem I'm having with
overlaying surfaces.
With some experimenting I was able to create a simpler testcase:
- - - -
/*
* 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 = 97;
double py = 97;
/* create a grid of green lines on solid white as background */
void CreateBackground()
{
cairo_t *cr;
int i;
glob.image = cairo_recording_surface_create(
CAIRO_CONTENT_COLOR_ALPHA, NULL);
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 red dot */
void CreateForeground()
{
cairo_t *cr;
glob.ball = cairo_recording_surface_create
(CAIRO_CONTENT_COLOR_ALPHA, NULL);
cr = cairo_create( glob.ball );
// draw a red dot
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 1.0);
cairo_arc(cr, px, py, 12, 0, 2*M_PI);
cairo_fill(cr);
cairo_destroy(cr);
}
/* when called, invalidate the position of the red dot and force
* a redraw
*/
gboolean timeout(gpointer data)
{
GtkWidget *widget = GTK_WIDGET(data);
GdkRectangle rect;
rect.x = px - 6;
rect.y = py - 6;
rect.width = 12;
rect.height = 12;
gdk_window_invalidate_rect( widget->window, &rect, FALSE );
gtk_widget_queue_draw(widget);
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);
cairo_rectangle(cr, event->area.x, event->area.y,
event->area.width, event->area.height);
cairo_clip(cr);
/* draw the background */
cairo_set_source_surface( cr, glob.image, 0, 0 );
cairo_paint(cr);
/* draw the foreground */
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";
cairo_t *cr;
gtk_init(NULL,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();
gtk_widget_set_size_request(drawing_area, 200, 200);
g_signal_connect(drawing_area, "expose_event",
G_CALLBACK(expose),NULL);
gtk_container_add(GTK_CONTAINER(window), drawing_area);
CreateBackground();
CreateForeground();
g_timeout_add(10, timeout, window);
if (!GTK_WIDGET_VISIBLE (window))
gtk_widget_show_all(window);
else {
gtk_widget_hide (window);
window = NULL;
}
gtk_main();
cairo_surface_destroy(glob.image);
cairo_surface_destroy(glob.ball);
}
- - - -
This code produces a grid of green lines on solid white as a background.
Then I overlay a surface that only has a red dot in its center. After
that regular redraws are enforced by invalidating the area every 10 ms.
On my system I get a flickering background that has artifacts from other
areas of my screen. Looks like an invalid /uninitialized pointer.
When I change both surfaces to image surfaces by calling
cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 200, 200 ) instead of
the cairo_recording_surface_create() calls shown above, everything works
as expected. So this situation seems to be related to recording surfaces.
Question for me is: do I misunderstand something or is this a bug in
recording surfaces?
Regards
Martin
On 22.02.2017 22:03 Lawrence D'Oliveiro wrote:
> On Wed, 22 Feb 2017 19:30:13 +0100, Martin Fischer wrote:
>
>> 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);
>
> Maybe add
>
> cairo_set_operator( cr, CAIRO_OPERATOR_SOURCE );
>
> at some point before the following paint call?
>
>> cairo_paint(cr);
More information about the cairo
mailing list