diff --git a/.gitignore b/.gitignore
index 2472996ec18de16c80b4f7ea72977c974ebdc293..b44090db6b17f4e2313ca1676d219c400ae6eafa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
 *.o
 *.gch
 pgm_exe
-.vscode
\ No newline at end of file
+.vscode
+*.pgm
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 9c6e5e80f9f5c3808cf1ceaeff29363f81167879..8c30d47ec0db5d007698b7e2ea5845c9f49abc07 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@ SANITIZERS = -g -fsanitize=address -fsanitize=leak -fsanitize=undefined
 LIBS = -lSDL2
 
 
-pgm_exe: pgm_main.o pgm.o matrix.o
+pgm_exe: pgm_main.o pgm.o matrix.o gfx.o
 	$(CC) $^ -o $@ $(LINKS) $(SANITIZERS) $(LIBS)
 
 
@@ -19,6 +19,9 @@ pgm.o: pgm.c pgm.h
 matrix.o: matrix.c matrix.h
 	$(CC) $^ -c $<
 
+gfx.o: gfx.c gfx.h
+	$(CC) $^ -c $<
+
 clean:
 	rm -f *.o 
 	rm -f *.gch
diff --git a/convolution.pgm b/convolution.pgm
index a6f66718bbf33e5273df8afbbfac43e580a1dcb3..c550c050430ef8b35279d3926248ca710bda41fa 100644
Binary files a/convolution.pgm and b/convolution.pgm differ
diff --git a/gfx.c b/gfx.c
new file mode 100644
index 0000000000000000000000000000000000000000..aca1933358386e2b4c3e2c0dd05bcc20f06373c1
--- /dev/null
+++ b/gfx.c
@@ -0,0 +1,95 @@
+/// @file gfx.c
+/// @author Florent Gluck
+/// @date November 6, 2016
+/// Helper routines to render pixels in fullscreen graphic mode.
+/// Uses the SDL2 library.
+
+#include "gfx.h"
+
+/// Create a fullscreen graphic window.
+/// @param title Title of the window.
+/// @param width Width of the window in pixels.
+/// @param height Height of the window in pixels.
+/// @return a pointer to the graphic context or NULL if it failed.
+struct gfx_context_t* gfx_create(char *title, uint width, uint height) {
+	if (SDL_Init(SDL_INIT_VIDEO) != 0) goto error;
+	SDL_Window *window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED,
+		SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_RESIZABLE);
+	SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0);
+	SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888,
+			SDL_TEXTUREACCESS_STREAMING, width, height);
+	uint32_t *pixels = malloc(width*height*sizeof(uint32_t));
+	struct gfx_context_t *ctxt = malloc(sizeof(struct gfx_context_t));
+
+	if (!window || !renderer || !texture || !pixels || !ctxt) goto error;
+
+	ctxt->renderer = renderer;
+	ctxt->texture = texture;
+	ctxt->window = window;
+	ctxt->width = width;
+	ctxt->height = height;
+	ctxt->pixels = pixels;
+
+	SDL_ShowCursor(SDL_DISABLE);
+	gfx_clear(ctxt, COLOR_BLACK);
+	return ctxt;
+
+error:
+	return NULL;
+}
+
+/// Draw a pixel in the specified graphic context.
+/// @param ctxt Graphic context where the pixel is to be drawn.
+/// @param x X coordinate of the pixel.
+/// @param y Y coordinate of the pixel.
+/// @param color Color of the pixel.
+void gfx_putpixel(struct gfx_context_t *ctxt, int x, int y, uint32_t color) {
+	if (x < ctxt->width && y < ctxt->height)
+		ctxt->pixels[ctxt->width*y+x] = color;
+}
+
+/// Clear the specified graphic context.
+/// @param ctxt Graphic context to clear.
+/// @param color Color to use.
+void gfx_clear(struct gfx_context_t *ctxt, uint32_t color) {
+	int n = ctxt->width*ctxt->height;
+	while (n)
+		ctxt->pixels[--n] = color;
+}
+
+/// Display the graphic context.
+/// @param ctxt Graphic context to clear.
+void gfx_present(struct gfx_context_t *ctxt) {
+	SDL_UpdateTexture(ctxt->texture, NULL, ctxt->pixels, ctxt->width*sizeof(uint32_t));
+	SDL_RenderCopy(ctxt->renderer, ctxt->texture, NULL, NULL);
+	SDL_RenderPresent(ctxt->renderer);
+}
+
+/// Destroy a graphic window.
+/// @param ctxt Graphic context of the window to close.
+void gfx_destroy(struct gfx_context_t *ctxt) {
+	SDL_ShowCursor(SDL_ENABLE);
+	SDL_DestroyTexture(ctxt->texture);
+	SDL_DestroyRenderer(ctxt->renderer);
+	SDL_DestroyWindow(ctxt->window);
+	free(ctxt->pixels);
+	ctxt->texture = NULL;
+	ctxt->renderer = NULL;
+	ctxt->window = NULL;
+	ctxt->pixels = NULL;
+	SDL_Quit();
+	free(ctxt);
+}
+
+/// If a key was pressed, returns its key code (non blocking call).
+/// List of key codes: https://wiki.libsdl.org/SDL_Keycode
+/// @return the key that was pressed or 0 if none was pressed.
+SDL_Keycode gfx_keypressed() {
+	SDL_Event event;
+	if (SDL_PollEvent(&event)) {
+		if (event.type == SDL_KEYDOWN)
+			return event.key.keysym.sym;
+	}
+	return 0;
+}
+
diff --git a/gfx.h b/gfx.h
new file mode 100644
index 0000000000000000000000000000000000000000..72bbdc3906e7aac7eef073259807379c6a27d4a8
--- /dev/null
+++ b/gfx.h
@@ -0,0 +1,41 @@
+#ifndef _GFX_H_
+#define _GFX_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <SDL2/SDL.h>
+
+#define MAKE_COLOR(r,g,b) ((uint32_t)b|((uint32_t)g<<8)|((uint32_t)r<<16))
+
+#define COLOR_GET_B(color) (color & 0xff)
+#define COLOR_GET_G(color) ((color >> 8) & 0xff)
+#define COLOR_GET_R(color) ((color >> 16) & 0xff)
+
+#define COLOR_BLACK  0x00000000
+#define COLOR_RED    0x00FF0000
+#define COLOR_GREEN  0x0000FF00
+#define COLOR_BLUE   0x000000FF
+#define COLOR_WHITE  0x00FFFFFF
+#define COLOR_YELLOW 0x00FFFF00
+
+typedef unsigned int  uint;
+typedef unsigned long ulong;
+typedef unsigned char uchar;
+
+struct gfx_context_t {
+	SDL_Window *window;
+	SDL_Renderer *renderer;
+	SDL_Texture *texture;
+	uint32_t *pixels;
+	int width;
+	int height;
+};
+
+extern void gfx_putpixel(struct gfx_context_t *ctxt, int x, int y, uint32_t color);
+extern void gfx_clear(struct gfx_context_t *ctxt, uint32_t color);
+extern struct gfx_context_t* gfx_create(char *text, uint width, uint height);
+extern void gfx_destroy(struct gfx_context_t *ctxt);
+extern void gfx_present(struct gfx_context_t *ctxt);
+extern SDL_Keycode gfx_keypressed();
+
+#endif
diff --git a/pgm.c b/pgm.c
index 4373a15b06b364b4ca290524744e4d5ba95afa71..a41c016dc520d8e5e9386c4a8f2321dc2fc7ad3c 100644
--- a/pgm.c
+++ b/pgm.c
@@ -207,4 +207,23 @@ pgm_error pmg_conv(pgm *conv, const pgm *const orig, const matrix *const kernel)
         }
     }
     return success;
+}
+
+pgm_error demo(const pgm *const img){
+    int width = img->pixels.l, height = img->pixels.c;
+	struct gfx_context_t *ctxt = gfx_create("Example", width, height);
+
+    
+
+    while (gfx_keypressed() != 27/*ESC btn code*/) {
+		for (int i = 0; i < img->pixels.l; i++) {
+           for (int j = 0; j < img->pixels.c; j++) {
+                gfx_putpixel(ctxt, j, i, MAKE_COLOR(img->pixels.data[i][j], img->pixels.data[i][j], img->pixels.data[i][j]));
+           }
+	    }
+		gfx_present(ctxt);
+	}
+
+    gfx_destroy(ctxt);
+    return success;
 }
\ No newline at end of file
diff --git a/pgm.h b/pgm.h
index 2494eb1ecfa74cea266699d93b43029e2c560de6..eadd88ac8655922b8379e136ae455128822a680a 100644
--- a/pgm.h
+++ b/pgm.h
@@ -5,6 +5,7 @@
 #include <stdlib.h> 
 #include <stdint.h>
 #include "matrix.h"
+#include "gfx.h"
 
 typedef struct _pgm{
     int32_t max;
diff --git a/pgm_main.c b/pgm_main.c
index ca1eb21d2d2a1fb7d95f2143ebbb8309ff7fd04e..6182af2c0c194564fbde353a1af6a596c84b0917 100644
--- a/pgm_main.c
+++ b/pgm_main.c
@@ -12,15 +12,14 @@ int main(){
     pgm pgmWithZeros;
     pgm convolution;
     int conv[9] =   {
-                        0,-1,0,
-                        -1,4,-1,
-                        0,-1,0 
+                        1,2,1,
+                        2,4,2,
+                        1,2,1 
                     };
     matrix convKernel;
     matrix_init_from_array(&convKernel, 3, 3, conv, 9);
 
 
-
     printf("%d", pgm_read_from_file(&a, "mandrill.pgm"));
     //printf("%d", pgm_write_to_file(&a, "newf.pgm"));
     printf("%d", pgm_negative(&neg, &a));
@@ -46,6 +45,7 @@ int main(){
     printf("%d", pmg_conv(&convolution, &pgmWithZeros, &convKernel));
     printf("%d", pgm_write_to_file(&convolution, "convolution.pgm"));
 
+    demo(&a);
 
     matrix_destroy(&a.pixels);
     matrix_destroy(&neg.pixels);