IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

GTK+ avec C & C++ Discussion :

[Cairo] Récupérer le buffer


Sujet :

GTK+ avec C & C++

  1. #1
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 308
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 308
    Billets dans le blog
    5
    Par défaut [Cairo] Récupérer le buffer
    Bonjour.

    Je reviens à la charge . Étant toujours dans le défrichage de Cairo je me heurte à un problème.

    J'ai écrit un petit programme test tout simple. Une fenêtre dans laquelle j'insère un GtkDrawingArea. Dans le Callback associé au signal "expose" je triture un peu les fonctions Cairo.
    Jusque là je suis arrivé à dessiner un rectangle de la couleur de mon choix. Vous me direz, ce n'est pas grand chose, mais pour moi ca veut dire beaucoup . Heuu, il me semble que c'est une chanson ca! Enfin bref, j'avance.

    L'étape suivante est d'accéder directement aux données de la surface. Ben oui, dessiner des rectangles c'est bien joli mais c'est tout de même un peu limite. Et c'est là que j'accroche. Je récupère la surface de cette manière :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    gboolean expose (GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
    {
      cairo_t *context = NULL;
      cairo_surface_t *surface=NULL;
     
      // Récupération de la surface
      context = gdk_cairo_create (widget->window);
      surface = cairo_get_target (context);
      ...
    La fonction cairo_surface_status (surface) me renvoie bien CAIRO_STATUS_SUCCESS. Donc la surface est valide. Malheureusement lorsque je veux récupérer le buffer la fonction cairo_image_surface_get_data (surface); me renvoie NULL.
    J'ai ajouté un test sur le GtkDrawingArea pour être sûr qu'il soit initialisé avec toute modification mais rien n'y fait. Je lance donc une bouteille à la mer...

  2. #2
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 308
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 308
    Billets dans le blog
    5
    Par défaut
    Je me réponds avec un bémol.

    Apparemment, mais si quelqu'un peut confirmer ou infirmer ca me rassurerais, récupérer un cairo_surface_t* directement d'un GtkWidget* n'est pas vu comme une Image Surface d'où l'impossibilité d'en récupérer le buffer.

    J'ai trouvé comme solution de créer directement un cairo_surface_t* avec la fonction cairo_image_surface_create (cairo_format_t format, int width, int height);. A partir de là je peux récupérer son buffer et le modifier. Ensuite j'utilise la fonction cairo_set_source_surface(); pour affecter cette surface au widget désiré.

    Cette méthode fonctionne mais me semble lourde. Est-ce la seule solution?

  3. #3
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 308
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 308
    Billets dans le blog
    5
    Par défaut
    Je place ici mon code exemple pour critiques et remarques éventuelles :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    #include <stdlib.h>
    #include <gtk/gtk.h>
     
    gboolean expose (GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
    {
      cairo_t *context = NULL;
      cairo_surface_t *surface=NULL;
      guchar *buffer = NULL;
      gint i = 0;
      gint width, height, stride;
     
      // Récupération du cairo context du GtkWidget.
      context = gdk_cairo_create (widget->window);
     
      // Création d'une surface image et test de celle-ci avant modification
      width = widget->allocation.width;
      height = widget->allocation.height;
      surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
      if (cairo_surface_status (surface) == CAIRO_STATUS_SUCCESS)
      {
        // Récupération du buffer et de la longueur d'une ligne en octets.
        buffer = cairo_image_surface_get_data (surface);
        stride = cairo_image_surface_get_stride (surface);
     
        // Exemple de modification directe du buffer image
        for (i=0; i < stride*height; i+=4)
          buffer[i] = 255;
     
        cairo_set_source_surface (context, surface, 0, 0);
        cairo_rectangle (context, 0, 0, width, height);
        cairo_clip (context);
     
        cairo_paint(context);
      }
     
      cairo_destroy(context);
      cairo_surface_destroy(surface);
     
      return FALSE;
    }
     
    int main (int argc,char *argv[])
    {
      GtkWidget *window = NULL;
      GtkWidget *drawing = NULL;
     
      gtk_init(&argc, &argv);
     
      window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
      drawing = gtk_drawing_area_new();
      gtk_widget_set_size_request(drawing, 300, 600);
     
      gtk_container_add(GTK_CONTAINER(window), drawing);
     
      g_signal_connect(G_OBJECT(drawing), "expose-event", (GCallback)expose, NULL);
      g_signal_connect(G_OBJECT(window), "delete-event", gtk_main_quit, NULL);
     
      gtk_widget_show_all(window);
     
      gtk_main();
     
      return EXIT_SUCCESS;
    }

  4. #4
    Modérateur

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2009
    Messages
    1 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2009
    Messages : 1 395
    Par défaut
    Ton problème vient du fait que tu tentes de manipuler ta surface comme si c'était une "Image Surface". Ce n'est pourtant pas le seul type de surface géré par cairo, et toutes ont leur backend spécifique.

    En gros, tu as une classe cairo_surface_t avec des fonctions cairo_surface_*, et plein de classes dérivées, spécifiques aux backends. Et pour dessiner dans une fenêtre, ce que te donne GTK, c'est une surface X11, que tu peux manipuler avec cairo_x11_surface_*. Pour effectuer des opérations spécifiques à un backend, il faut savoir à quel type de surface tu as affaire avec cairo_surface_get_type.

    Pour ce qui est de modifier manuellement (sans passer par cairo) une surface, tu as ici un exemple avec une Image Surface:
    http://cairographics.org/manual/cair...-t.description

    En revanche si tu ne veux pas passer par une surface intermédiaire, tu dois utiliser l'API propre à ton backend (X11 dans ce cas), mais cairo est justement là pour t'éviter ce calvaire et abstraire au maximum le backend ! Et dans le cas où c'est trop compliqué, tu peux passer par une Image Surface.

    Aurtre conseil: pour des raisons de performances, utilise le configure-event pour créer ton image surface, vu qu'elle n'a besoin d'être crée que quand la taille de la fenêtre change, et garde la en mémoire entre chaque expose-event. Il est aussi important d'utiliser correctement la zone de clipping pour gagner en vitesse d'exécution.

  5. #5
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 308
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 308
    Billets dans le blog
    5
    Par défaut
    Merci pour toutes ces précisions qui m'éclaircissent un peu le problème. Utiliser X11 directement ne me plait pas plus que ca. Si demain je dois porter mon application sous un autre système, je suis bon pour revoir ma copie.
    En réalité je modifie ma librairie 3D pour n'utiliser plus que Cairo. Je crée donc une "Image surface" qui est conservée. Ce qui rejoins ton commentaire.

    Pour le clipping en effet je trouve ces fonctions forts utiles. Maintenant pour ma librairie je calcule une image entière à chaque fois, donc le clipping est total => pas d'amélioration de ce côté là pour moi.

    Une autre remarque pendant que j'y suis. Il semblerait que les couleurs soient inversées dans le buffer. Non pas avoir ARVB on a ABVR. Peux-tu confirmer?

  6. #6
    Modérateur

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2009
    Messages
    1 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2009
    Messages : 1 395
    Par défaut
    Citation Envoyé par gerald3d Voir le message
    Une autre remarque pendant que j'y suis. Il semblerait que les couleurs soient inversées dans le buffer. Non pas avoir ARVB on a ABVR. Peux-tu confirmer?
    http://cairographics.org/manual/cair...cairo-format-t

    CAIRO_FORMAT_ARGB32
    each pixel is a 32-bit quantity, with alpha in the upper 8 bits, then red, then green, then blue. The 32-bit quantities are stored native-endian. Pre-multiplied alpha is used. (That is, 50% transparent red is 0x80800000, not 0x80ff0000.)
    Tu es en x86, tu es en little endian et donc les poids faibles sont à gauche...

  7. #7
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 308
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 308
    Billets dans le blog
    5
    Par défaut
    Au temps pour moi. Effectivement je l'ai lu mais en diagonal .

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Récupérer le buffer de facon dynamique
    Par Bmauet dans le forum Débuter
    Réponses: 2
    Dernier message: 26/10/2008, 18h18
  2. Réponses: 2
    Dernier message: 01/02/2008, 09h42
  3. Récupérer un tableau 2 dimensions depuis un buffer.
    Par Crepuscule3 dans le forum C++
    Réponses: 0
    Dernier message: 03/12/2007, 13h08
  4. Réponses: 2
    Dernier message: 03/01/2007, 18h17
  5. récupérer un gros buffer
    Par poukill dans le forum C++
    Réponses: 6
    Dernier message: 18/05/2006, 14h02

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo