Cairo - Auf Surface zeichnen



  • Hallo,

    ich möchte gerne ein neues Surface aus einer .png-Datei erstellen und dieses dann einer Struktur zuweisen. Später soll dieses dann gezeichnet werden.
    Ich gehe dabei folgendermaßen vor:

    cairo_surface_t *surf =  cairo_image_surface_create_from_png(str);
    free(str);
    cairo_t *cr = cairo_create(surf);
    cairo_scale(cr,1.0/IMAGE_SIZE*size,1.0/IMAGE_SIZE*size);
    cairo_set_source_surface(cr,surf,0,0);
    cairo_paint(cr);
    pieces[i].surface = surf;
    

    Das Problem ist nun, dass Bilder verschiedener Skalierungsstufen übereinander gemalt erscheinen.

    Woran könnte das liegen?

    Vielen Dank!! 🙂



  • Hallo,

    ich habe aus meinem Projekt heraus ein kleines compilierbares Beispiel extrahiert, das den Fehler zeigt.

    main.h:

    #ifndef MAIN_H
    #define MAIN_H
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netdb.h>
    #include <errno.h>
    #include <netinet/in.h>
    #include <string.h>
    #include <unistd.h>
    #include <pthread.h>
    #include <gtk/gtk.h>
    #include <cairo.h>
    
    static GtkWidget *mainWindow;
    static GtkWidget *drawArea;
    static cairo_surface_t *bauerW;
    static void frame_callback(GtkWindow *, GdkEvent *, gpointer);
    static int width = 600, height = 600;
    static GtkWidget *table;
    #endif
    

    main.c:

    #include "main.h"
    
    int squareSize;
    int IMAGE_SIZE = 250;
    static void do_drawing(cairo_t *cr) {
       if(cr == NULL)
          return;
       int min = width;
       if(height < width)
          min = height;
       squareSize = min/8;
    	for(int j=0;j<8;j++) {
    		for(int i=0;i<8;i++) {
    			if((i+j)%2 == 0) {
    				cairo_set_source_rgba(cr,.7,.6,.5,1);			
    			} else {
    			   cairo_set_source_rgba(cr,0.55,0.45,0.35,1);			
             }
    
    			cairo_rectangle(cr, squareSize*i, squareSize*(j), squareSize, squareSize);
    			cairo_set_line_width(cr, 14);
    			cairo_fill(cr);
    		}
    	}
    
       cairo_translate(cr,200,200);
       cairo_set_source_surface(cr,bauerW,0,0);
       cairo_paint(cr);
    }
    
    static void scaleImage(int size) {
    		cairo_surface_t *surf =  cairo_image_surface_create_from_png("whitePawn.png");
    		cairo_t *cr = cairo_create(surf);
          cairo_scale(cr,1.0/IMAGE_SIZE*size,1.0/IMAGE_SIZE*size);
          cairo_set_source_surface(cr,surf,0,0);
          cairo_paint(cr);
          bauerW = surf;
    }
    
    static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr, gpointer user_data) {
      do_drawing(cr);
    
      return FALSE;
    }
    
    int main(int argc, char **argv) {
    
    	gtk_init(&argc,&argv);
       bauerW = cairo_image_surface_create_from_png("whitePawn.png");
    
       drawArea = gtk_drawing_area_new();
    	gtk_widget_set_size_request(drawArea,400,400);
       gtk_widget_set_events (drawArea, gtk_widget_get_events (drawArea)
                         | GDK_BUTTON_PRESS_MASK
                         | GDK_BUTTON_RELEASE_MASK
    							| GDK_POINTER_MOTION_MASK);
    
      	g_signal_connect(G_OBJECT(drawArea), "draw",G_CALLBACK(on_draw_event), NULL);
    
    	mainWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    	gtk_window_set_default_size(GTK_WINDOW(mainWindow),width,height);
       gtk_widget_add_events(GTK_WIDGET(mainWindow), GDK_CONFIGURE);
    	table = gtk_grid_new();
    
    	gtk_grid_attach(GTK_GRID(table),drawArea,0,0,4,4);
    
    	gtk_container_add(GTK_CONTAINER(mainWindow),table);
    
       gtk_widget_add_events(GTK_WIDGET(mainWindow), GDK_CONFIGURE);
    	g_signal_connect(mainWindow,"destroy",G_CALLBACK(gtk_main_quit),NULL);
       g_signal_connect(G_OBJECT(drawArea), "configure-event",G_CALLBACK(frame_callback), NULL);
    
    	gtk_widget_set_hexpand(drawArea,TRUE);
    	gtk_widget_set_vexpand(drawArea,TRUE);
    	gtk_widget_set_hexpand(table,TRUE);
    	gtk_widget_set_vexpand(table,TRUE);
    
       gtk_widget_show(drawArea);
       gtk_widget_show(table);
       gtk_widget_show(mainWindow);
    
    	gtk_main();
       return 0;
    
    }
    
    void frame_callback(GtkWindow *w, GdkEvent *event, gpointer data) {
       width = event->configure.width;
       height = event->configure.height;
       scaleImage(width/8);
    }
    

    Als Ergebnis erhalte ich einen weißen Bauern, der in verschiedenen Skalierungsstufen dargestellt wird.

    Ich bitte um Denkanstöße :).



  • Naja, Du bemalst die Drawingarea ja auch zweimal mit dem Surface:

    das erste mal in frame_callback -> scaleImage(width/8); (configure-event)

    das zweite mal in on_draw_event -> do_drawing(cr); (draw)



  • Ich hab's endlich geschafft :).

    static void scaleImage(int size) {
          cairo_surface_t *neu = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,size,size);
    
    		cairo_surface_t *surf =  cairo_image_surface_create_from_png("whitePawn.png");
    		cairo_t *cr = cairo_create(neu);
          cairo_scale(cr,1.0/IMAGE_SIZE*size,1.0/IMAGE_SIZE*size);
          cairo_set_source_surface(cr,surf,0,0);
          cairo_paint(cr);
          bauerW = neu;
    }
    

Anmelden zum Antworten