INFO607
union-find.c
Go to the documentation of this file.
1#include <stdlib.h>
2#include <math.h>
3#include <assert.h>
4#include <gtk/gtk.h>
5
6//-----------------------------------------------------------------------------
7// Déclaration des types
8//-----------------------------------------------------------------------------
9/**
10 Le contexte contient les informations utiles de l'interface pour
11 les algorithmes de traitement d'image.
12*/
13typedef struct SContexte {
14 int width;
15 int height;
16 GdkPixbuf* pixbuf_input;
17 GdkPixbuf* pixbuf_output;
18 GtkWidget* image;
20
21/**
22 Un pixel est une structure de 3 octets (rouge, vert, bleu). On les
23 plaque au bon endroit dans un pixbuf pour modifier les couleurs du pixel.
24 */
25typedef struct {
26 guchar rouge;
27 guchar vert;
28 guchar bleu;
29} Pixel;
30
31
32//-----------------------------------------------------------------------------
33// Déclaration des fonctions
34//-----------------------------------------------------------------------------
35gboolean selectInput( GtkWidget *widget, gpointer data );
36gboolean selectOutput( GtkWidget *widget, gpointer data );
37GtkWidget* creerIHM( const char* image_filename, Contexte* pCtxt );
38void analyzePixbuf( GdkPixbuf* pixbuf );
39GdkPixbuf* creerImage( int width, int height );
40unsigned char greyLevel( Pixel* data );
41void setGreyLevel( Pixel* data, unsigned char g );
42Pixel* gotoPixel( GdkPixbuf* pixbuf, int x, int y );
43void disk( GdkPixbuf* pixbuf, int r );
44
45
46//-----------------------------------------------------------------------------
47// Programme principal
48//-----------------------------------------------------------------------------
49int main( int argc,
50 char* argv[] )
51{
52 Contexte context;
53 const char* image_filename = argc > 1 ? argv[ 1 ] : "lena.png";
54
55 /* Passe les arguments à GTK, pour qu'il extrait ceux qui le concernent. */
56 gtk_init( &argc, &argv );
57
58 /* Crée une fenêtre. */
59 creerIHM( image_filename, &context );
60
61 /* Rentre dans la boucle d'événements. */
62 gtk_main ();
63 return 0;
64}
65
66
67/// Fonction appelée lorsqu'on clique sur "Input".
68gboolean selectInput( GtkWidget *widget, gpointer data )
69{
70 // Récupère le contexte.
71 Contexte* pCtxt = (Contexte*) data;
72 // Place le pixbuf à visualiser dans le bon widget.
73 gtk_image_set_from_pixbuf( GTK_IMAGE( pCtxt->image ), pCtxt->pixbuf_input );
74 // Force le réaffichage du widget.
75 gtk_widget_queue_draw( pCtxt->image );
76 return TRUE;
77}
78
79/// Fonction appelée lorsqu'on clique sur "Output".
80gboolean selectOutput( GtkWidget *widget, gpointer data )
81{
82 // Récupère le contexte.
83 Contexte* pCtxt = (Contexte*) data;
84 // Place le pixbuf à visualiser dans le bon widget.
85 gtk_image_set_from_pixbuf( GTK_IMAGE( pCtxt->image ), pCtxt->pixbuf_output );
86 // Force le réaffichage du widget.
87 gtk_widget_queue_draw( pCtxt->image );
88 return TRUE;
89}
90
91/// Charge l'image donnée et crée l'interface.
92GtkWidget* creerIHM( const char* image_filename, Contexte* pCtxt )
93{
94 GtkWidget* window;
95 GtkWidget* vbox1;
96 GtkWidget* vbox2;
97 GtkWidget* hbox1;
98 GtkWidget* button_quit;
99 GtkWidget* button_select_input;
100 GtkWidget* button_select_output;
101 GError** error = NULL;
102
103 /* Crée une fenêtre. */
104 window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
105 // Crée un conteneur horitzontal box.
106 hbox1 = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, 10 );
107 // Crée deux conteneurs vertical box.
108 vbox1 = gtk_box_new( GTK_ORIENTATION_VERTICAL, 10 );
109 vbox2 = gtk_box_new( GTK_ORIENTATION_VERTICAL, 10 );
110 // Crée le pixbuf source et le pixbuf destination
111 pCtxt->pixbuf_input = gdk_pixbuf_new_from_file( image_filename, error );
112 pCtxt->width = gdk_pixbuf_get_width( pCtxt->pixbuf_input ); // Largeur de l'image en pixels
113 pCtxt->height = gdk_pixbuf_get_height( pCtxt->pixbuf_input ); // Hauteur de l'image en pixels
114 pCtxt->pixbuf_output = creerImage( pCtxt->width, pCtxt->height );
115 analyzePixbuf( pCtxt->pixbuf_input );
116 disk( pCtxt->pixbuf_output, 100 );
117 // Crée le widget qui affiche le pixbuf image.
118 pCtxt->image = gtk_image_new_from_pixbuf( pCtxt->pixbuf_input );
119 // Rajoute l'image dans le conteneur hbox.
120 gtk_container_add( GTK_CONTAINER( hbox1 ), pCtxt->image );
121 // Rajoute le 2eme vbox dans le conteneur hbox (pour mettre les boutons sélecteur d'image).
122 gtk_container_add( GTK_CONTAINER( hbox1 ), vbox2 );
123 // Crée les boutons de sélection "source"/"destination".
124 button_select_input = gtk_button_new_with_label( "Input" );
125 button_select_output = gtk_button_new_with_label( "Output" );
126 // Connecte la réaction gtk_main_quit à l'événement "clic" sur ce bouton.
127 g_signal_connect( button_select_input, "clicked",
128 G_CALLBACK( selectInput ),
129 pCtxt );
130 g_signal_connect( button_select_output, "clicked",
131 G_CALLBACK( selectOutput ),
132 pCtxt );
133 gtk_container_add( GTK_CONTAINER( vbox2 ), button_select_input );
134 gtk_container_add( GTK_CONTAINER( vbox2 ), button_select_output );
135 // Crée le bouton quitter.
136 button_quit = gtk_button_new_with_label( "Quitter" );
137 // Connecte la réaction gtk_main_quit à l'événement "clic" sur ce bouton.
138 g_signal_connect( button_quit, "clicked",
139 G_CALLBACK( gtk_main_quit ),
140 NULL);
141 // Rajoute tout dans le conteneur vbox.
142 gtk_container_add( GTK_CONTAINER( vbox1 ), hbox1 );
143 gtk_container_add( GTK_CONTAINER( vbox1 ), button_quit );
144 // Rajoute la vbox dans le conteneur window.
145 gtk_container_add( GTK_CONTAINER( window ), vbox1 );
146
147 // Rend tout visible
148 gtk_widget_show_all( window );
149
150 return window;
151}
152
153/**
154 Utile pour vérifier que le GdkPixbuf a un formal usuel: 3 canaux RGB, 24 bits par pixel,
155 et que la machine supporte l'alignement de la structure sur 3 octets.
156*/
157void analyzePixbuf( GdkPixbuf* pixbuf )
158{
159 int n_channels = gdk_pixbuf_get_n_channels( pixbuf ); // Nb de canaux (Rouge, Vert, Bleu, potentiellement Alpha)
160 int has_alpha = gdk_pixbuf_get_has_alpha( pixbuf ); // Dit s'il y a un canal Alpha (transparence).
161 int bits_per_sample = gdk_pixbuf_get_bits_per_sample( pixbuf ); // Donne le nombre de bits par échantillon (8 bits souvent).
162 guchar* data = gdk_pixbuf_get_pixels( pixbuf ); // Pointeur vers le tampon de données
163 int width = gdk_pixbuf_get_width( pixbuf ); // Largeur de l'image en pixels
164 int height = gdk_pixbuf_get_height( pixbuf ); // Hauteur de l'image en pixels
165 int rowstride = gdk_pixbuf_get_rowstride( pixbuf ); // Nombre d'octets entre chaque ligne dans le tampon de données
166 printf( "n_channels = %d\n", n_channels );
167 printf( "has_alpha = %d\n", has_alpha );
168 printf( "bits_per_sa= %d\n", bits_per_sample );
169 printf( "width = %d\n", width );
170 printf( "height = %d\n", height );
171 printf( "data = %p\n", (void*)data );
172 printf( "rowstride = %d\n", rowstride );
173 Pixel* pixel = (Pixel*) data;
174 printf( "sizeof(Pixel)=%ld\n", sizeof(Pixel) );
175 size_t diff = ((guchar*) (pixel+1)) - (guchar*) pixel;
176 printf( "(pixel+1) - pixel=%ld\n", diff );
177 assert( n_channels == 3 );
178 assert( has_alpha == FALSE );
179 assert( bits_per_sample == 8 );
180 assert( sizeof(Pixel) == 3 );
181 assert( diff == 3 );
182}
183
184/**
185 Crée un image vide de taille width x height.
186*/
187GdkPixbuf* creerImage( int width, int height )
188{
189 GdkPixbuf* img = gdk_pixbuf_new(GDK_COLORSPACE_RGB, 0, 8, width, height );
190 return img;
191}
192
193/**
194 Retourne le niveau de gris du pixel.
195*/
196unsigned char greyLevel( Pixel* data )
197{
198 return (data->rouge+data->vert+data->bleu)/3;
199}
200
201/**
202 Met le pixel au niveau de gris \a g.
203*/
204void setGreyLevel( Pixel* data, unsigned char g )
205{
206 data->rouge = g;
207 data->vert = g;
208 data->bleu = g;
209}
210
211/**
212 Va au pixel de coordonnées (x,y) dans le pixbuf.
213*/
214Pixel* gotoPixel( GdkPixbuf* pixbuf, int x, int y )
215{
216 int rowstride = gdk_pixbuf_get_rowstride( pixbuf );
217 guchar* data = gdk_pixbuf_get_pixels( pixbuf );
218 return (Pixel*)( data + y*rowstride + x*3 );
219}
220
221/**
222 Crée une image sous forme de disque.
223*/
224void disk( GdkPixbuf* pixbuf, int r )
225{
226 int x,y;
227 int width = gdk_pixbuf_get_width( pixbuf ); // Largeur de l'image en pixels
228 int height = gdk_pixbuf_get_height( pixbuf ); // Hauteur de l'image en pixels
229 int x0 = width/2;
230 int y0 = height/2;
231 for ( y = 0; y < height; ++y )
232 {
233 Pixel* pixel = gotoPixel( pixbuf, 0, y ); // les lignes peuvent être réalignées
234 for ( x = 0; x < width; ++x )
235 {
236 int d2 = (x-x0)*(x-x0)+(y-y0)*(y-y0);
237 if ( d2 >= r*r ) setGreyLevel( pixel, 0 );
238 else setGreyLevel( pixel, 255-(int) sqrt(d2));
239 ++pixel; // sur une ligne, les pixels se suivent
240 }
241 }
242}
guchar bleu
Definition union-find.c:28
guchar rouge
Definition union-find.c:26
guchar vert
Definition union-find.c:27
GdkPixbuf * pixbuf_input
Definition union-find.c:16
GdkPixbuf * pixbuf_output
Definition union-find.c:17
GtkWidget * image
Definition union-find.c:18
int main(int argc, char *argv[])
Definition union-find.c:49
void analyzePixbuf(GdkPixbuf *pixbuf)
Definition union-find.c:157
gboolean selectInput(GtkWidget *widget, gpointer data)
Fonction appelée lorsqu'on clique sur "Input".
Definition union-find.c:68
GtkWidget * creerIHM(const char *image_filename, Contexte *pCtxt)
Charge l'image donnée et crée l'interface.
Definition union-find.c:92
unsigned char greyLevel(Pixel *data)
Definition union-find.c:196
GdkPixbuf * creerImage(int width, int height)
Definition union-find.c:187
void disk(GdkPixbuf *pixbuf, int r)
Definition union-find.c:224
gboolean selectOutput(GtkWidget *widget, gpointer data)
Fonction appelée lorsqu'on clique sur "Output".
Definition union-find.c:80
Pixel * gotoPixel(GdkPixbuf *pixbuf, int x, int y)
Definition union-find.c:214
void setGreyLevel(Pixel *data, unsigned char g)
Definition union-find.c:204
struct SContexte Contexte