3. Affichage graphique 3.1 Graphics Device Interface (GDI) Le GDI (Graphics Device Interface) est un ensemble de fonctions de l API Windows permettant de dessiner à l écran, en mémoire ou sur imprimante. Ces fonctions permettent le tracé de primitives graphiques (points, lignes, rectangles, cercles, ), d images bitmap ou encore de texte. Le GDI fonctionne autour du principe de «Device Context» (DC), représenté par le type HDC («Handle to Device Context»). 1
Un HDC désigne un endroit sur lequel on peut dessiner : l écran tout entier, une fenêtre toute entière, la zone client d une fenêtre, une image stockée en mémoire ou une imprimante. Pour afficher sur un périphérique à sortie graphique, il faut toujours avoir un DC lié à celui-ci. En donnant un handle sur ce DC à une fonction GDI on indique à Windows sur quel périphérique de sortie on souhaite travailler. indépendance vis à vis du matériel. On utilise le même code pour dessiner à l écran ou sur une imprimante. 2
Le cas le plus courant d affichage se fait dans la zone client de la fenêtre. Y mini X mini Y maxi = zone client X maxi 3
Système de coordonnées GDI trace les primitives graphiques (points, lignes, rectangles, etc.), les images, le texte, dans un système de coordonnées. Un moniteur réalise l affichage sur une matrice rectangulaire de points appelés pixels. Les algorithmes de tracés de figure de GDI permettent de donner une couleur à certains de ces pixels (ici pour tracer une ligne). 4
3.2 Evolution de GDI : GDI+ Nombreuses innovations : Chargement d images (BMP, JPG, TIFF, PNG, GIF, ICO, ) Nouvelles primitives graphiques (courbes, ) Nouveaux types de tracés (flèche, ) Transformations (rotations, symétries, ) Ajustements (contraste, luminosité, netteté, ) La plupart des méthodes de GDI+ sont surchargées : nombreuses syntaxes différentes. Plus d infos sur le MSDN (MicroSoft Developper Network) : msdn.microsoft.com/ 5
3.2.1 Configuration Fichiers nécessaires : gdiplus.dll : La DLL gdiplus.lib : La librairie gdiplus*.h : Les fichiers d en-tête Le VC++ doit être configuré de manière à connaître le chemin des fichiers d include et de librairies de GDI+ : 6
Paramètres : Dans le menu Projet, sélectionnez Propriétés. Dans la boîte qui apparaît, ajoutez gdiplus.lib dans le champ Dépendances supplémentaires de l onglet Éditeur de liens / Entrée. 7
Initialisation : Au début de votre programme, rajoutez les lignes suivantes : #include <gdiplus.h> using namespace Gdiplus; ULONG_PTR m_gdiplustoken; 8
Au début de votre programme, on initialise GDI+ avec les instructions suivantes : GdiplusStartupInput gdiplusstartupinput; GdiplusStartup(&m_gdiplusToken,&gdiplusStartupInput,NULL); A la fin de votre programme, on quitte proprement GDI+ avec l instruction suivante : GdiplusShutdown(m_gdiplusToken); 9
3.2.2 La classe Graphics Toutes les fonctionnalités graphiques de GDI+ sont des méthodes de la classe Graphics. Un objet de classe Graphics s obtient en fournissant au constructeur le handle de contexte de périphérique. Ex: dans WindowsProc() : case WM_PAINT: HDC hdc; hdc = BeginPaint(handle_fenetre, &PaintST); Graphics graphics(hdc); Pen crayon(color(255, 255, 0, 0)); graphics.drawline(&crayon, 0, 0, 200, 100); EndPaint(handle_fenetre, &PaintST); return 0; 10
Obtenir un contexte de périphérique sur une fenêtre Deux possibilités : 1. Dans WindowProc(), lors de l interception du message WM_PAINT, on peut obtenir un DC avec BeginPaint(). case WM_PAINT : HDC hdc = BeginPaint(handle_fenetre,&PaintSt); 2. Ailleurs, pour obtenir un DC il faut utiliser la fonction GetDC(). HDC hdc = GetDC (handle_fenetre); 11
Suppression de contexte de périphérique Lorsqu on n a plus besoin d un DC, il faut le supprimer. La fonction à utiliser dépend de comment on a obtenu le DC : 1. Si on a obtenu le DC avec BeginPaint() : HDC hdc = BeginPaint(handle_fenetre,&PaintSt); alors il faut le supprimer avec EndPaint() : EndPaint(handle_fenetre,&PaintSt); 2. Si on a obtenu le DC avec GetDC() : HDC hdc = GetDC (handle_fenetre); alors il faut le supprimer avec ReleaseDC() : ReleaseDC(handle_fenetre, hdc); 12
3.2.3 La classe Color En informatique, on représente n importe quelle couleur par un mélange de 3 couleurs de base : le rouge, le vert, le bleu (système RVB). C est le principe de la synthèse additive (vu en cours de 2ème année). Si on mélange du rouge, du vert et du bleu avec 256 nuances chacun, alors on peut obtenir 16,7 millions de couleurs (256x256x256). R V B Noir 0 0 0 Bleu 0 0 255 Vert 0 255 0 Cyan 0 255 255 Rouge 255 0 0 Magenta 255 0 255 Jaune 255 255 0 Blanc 255 255 255 13
GDI+ définit une couleur ARVB avec la classe Color. Nb bits = 8 8 8 Nb bits 8 8 8 8 = Un pixel RVB (24 bits) Un pixel ARVB (32 bits) Alpha = 0 : pixel complètement transparent Alpha = 255 : pixel complètement opaque 0 < Alpha < 255 : pixel plus ou moins translucide A R V B Color c1(255, 255, 0, 0); // Rouge opaque Color c2(128, 0, 255, 0); // Vert à moitié transparent 14
3.2.4 La classe Pen Classe de «crayon» définissant le style de tracé. On peut définir la couleur, l épaisseur, les extrémités (flèche, rond, etc.), l apparence (solide, pointillés, etc.). Constructeurs de la classe Pen : Pen::Pen(Color couleur); // Epaisseur = 1 pixel Pen::Pen(Color couleur, int epaisseur); Exemple : Pen crayon(color(255, 255, 0, 0)); // Crayon Rouge 15
3.2.5 Tracé de lignes Pen crayon(color(255, 255, 0, 0)); // Rouge graphics.drawline(&crayon, 10, 20, 200, 100); On définit d abord un pointeur sur le crayon à utiliser, puis les coordonnées des deux extrémités. 16
Définition des extrémités de lignes Pen crayon(color(255, 0, 0, 255),20); crayon.setlinecap(linecapround, LineCapArrowAnchor, DashCapRound); graphics.drawline(&crayon, 20, 20,200, 80); 17
Effet de l alpha blending Alpha faible (max=255) couleur transparente Pen crayon(color(80, 0, 0, 255),40); graphics.drawline(&crayon, 10, 20,280, 150); 18
3.2.6 Tracé de rectangles Graphics::DrawRectangle(Pen *crayon, int x, int y, int largeur, int hauteur); Exemple: graphics.drawrectangle(&crayon, 100, 50, 80, 40); 100 50 40 80 19
3.2.7 Tracé d ellipses Graphics::DrawEllipse(Pen *crayon, int x, int y, int largeur, int hauteur); Exemple: graphics.drawellipse(&crayon, 100, 50, 80, 40); 100 50 40 80 20
3.2.8 Tracé de polygones Point liste_points[] = {Point(60, 180), Point(30, 60)}; Point(120, 80), Point(170, 20), Point(220, 100)}; graphics.drawpolygon(&crayon, liste_points, 5); (170, 20) (30, 60) (120, 80) (60, 180) (220, 100) class Point { int X, Y; } (définie par GDI+) 21
3.2.9 Tracé de courbes splines Courbe passant par des points de contrôle. Point liste_points[] = {Point(60, 180), Point(30, 60)}; Point(120, 80), Point(170, 20), Point(220, 100)}; graphics.drawcurve(&crayon, liste_points, 5, 1.0f); 22
Dernier paramètre = «tension» graphics.drawcurve(&crayon, liste_points, 5, 1.0f ); Tension = 0.0f Tension = 1.0f Tension = 2.0f 23
3.2.10 Tracé de courbes de Bézier Courbe influencée par des points de contrôle. La courbe passe par le premier point et par le dernier, mais pas par les autres. graphics.drawbezier(&crayon, 60,180, 30,60, 170,20, 220,100); (30, 60) (170, 20) (220, 100) (60, 180) 24
3.2.11 Remplissage de formes avec des brosses On a vu comment afficher des contours de formes (rectangles, ellipses, polygones). Il existe l équivalent de ces fonctions pour l affichage de formes remplies. DrawRectan gle DrawEllip se DrawPolyg on FillRectan gle FillEllips e FillPolygo n Alors que les fonctions de tracé de contour de formes attendent en 1 er paramètre l adresse d un crayon, les fonctions de tracé de formes remplies attendent en 1 er paramètre l adresse d une brosse. 25
Il existe différents types de brosses («brush») permettant de remplir des formes : La classe SolidBrush SolidBrush brosse(color(255, 255, 0, 0)); graphics.fillellipse(&brosse, 100, 50, 160, 80); 26
La classe HatchBrush HatchBrush brosse(hatchstylevertical, Color(255, 0, 0, 255), Color(255, 0, 255, 0)); graphics.fillellipse(&brosse, 100, 50, 160, 80); GDI+ offre plus de 50 types de hachures. 27
La classe TextureBrush Image image(l"rosace.bmp"); TextureBrush brosse(&image); graphics.fillellipse(&brosse, 100, 50, 160, 80); rosace.bmp Note: le constructeur de la classe Image (vue plus loin dans le cours) attend en paramètre un nom de fichier. La chaîne de caractères doit être codée en Unicode (2 octets par caractère). 28
3.2.12 Clipping Le «clipping» ou «découpage» permet de restreindre l affichage à une région donnée. Region region(rect(20, 30, 100, 50)); graphics.drawrectangle(&crayon, 20, 30, 100, 50); graphics.setclip(®ion, CombineModeReplace); graphics.drawline(&crayon, 0, 0, 200, 200); Sans Avec Clipping d une série d ellipses par les contours d un texte 29
3.2.13 Antialiasing L affichage se fait sur une matrice de pixels nombre limité de points, plus ou moins important en fonction de la résolution. Apparition de phénomènes «d aliassage» («aliasing» en anglais) comme des effets de «marches d escalier» Affichage normal Affichage avec antialiassage Solution : utiliser des algorithmes «d antialiassage» («antialiasing») qui vont calculer des pixels supplémentaires, affichés avec transparence, pour atténuer les effets de pixelisation. 30
Une fonction GDI+ permet d utiliser de l antialiasing lors du tracé de lignes, courbes, rectangles, ellipses, etc. : Prototype : Graphics::SetSmoothingMode(SmoothingMode mode); Exemple : graphics.setsmoothingmode(smoothingmodeantialias); graphics.drawellipse(&crayon, 20, 20, 80, 40); graphics.setsmoothingmode(smoothingmodeantialias); graphics.drawellipse(&crayon, 20, 70, 80, 40); Remarque : L antialiassage permet une meilleure qualité d affichage mais est plus lent en raison des calculs supplémentaires. 31
3.2.14 Affichage de texte FontFamily fontfamily(l"times New Roman"); Font font(&fontfamily, 24, FontStyleRegular, UnitPixel); PointF pointf(30.0f, 10.0f); SolidBrush solidbrush(color(255, 0, 0, 255)); graphics.drawstring(l"hello",-1,&font,pointf,&solidbrush); 32
Affichage de texte dans une zone rectangulaire FontFamily fontfamily(l"arial"); Font font(&fontfamily, 12, FontStyleBold, UnitPoint); RectF rectf(30.0f, 10.0f, 150.0f, 100.0f); SolidBrush solidbrush(color(255, 0, 0, 255)); graphics.drawstring(l"affichage d'un texte dans un rectangle de 150x100 pixels", -1, &font, rectf, NULL, &solidbrush); 33
Affichage de texte avec antialiasing Prototype : Graphics::SetTextRenderingHint(TextRenderingHint mode); Exemple : graphics.settextrenderinghint(textrenderinghintantialias); graphics.drawstring(l"hello",-1,&font,pointf(30.0f, 60.0f), &solidbrush); mode = TextRenderingHintSingleBit PerPixel TextRenderingHintSystem Default TextRenderingHintAnt ialias 34
3.2.15 Affichage d images Image : «bitmap» = matrice de pixels Pixel = «PICture ELement» Largeur (nb pixels) Un pixel Hauteur (nb pixels) Agrandissement d une partie de l image (œil) 35
Pour afficher une image à l écran avec le GDI : 1. Charger l image du disque vers la mémoire 2. Copier l image de la mémoire vers la fenêtre 1 2 Mémoire Disque Fenêtre 36
Classe Image Pour afficher une image, il faut un objet de classe Graphics et un objet de classe Image. La classe Image permet de charger des images aux formats BMP, GIF, JPEG, PNG, TIFF, WMF, EMF, ICO. Image img(l"bird.jpg"); Graphics graphics(hdc); img.getwidth() img.getheight() 37
Affichage La méthode DrawImage() de la classe Graphics a de nombreuses variantes (surcharges). En voici 3 : Image img(l"bird.jpg"); Graphics graphics(hdc); 1 graphics.drawimage(&img, 20, 10); 38
2 Graphics::DrawImage(Image* image, int xdestination, int ydestination, int xsource, int ysource, int largeursource, int hauteursource) xsource ysource xdestination ydestination hauteursource largeursource DrawImag e() Source Destination 39
3 Graphics::DrawImage(Image* image, Rect Dest, int xsource, int ysource, int largeursource, int hauteursource) xsource ysource hauteursource Dest.top Dest.left largeursource Dest.bottom Source DrawImag e() Dest.right Destination 40
Gestion de la transparence Certains formats de fichiers d image gèrent la transparence. Soit avec une seule couleur considérée comme transparente (ex: GIF), soit avec un canal alpha par pixel (ex: BMP, PNG, TGA). Quand on affiche une telle image, on peut voir ce qui avait déjà été affiché au travers des pixels transparents. Utile pour les «sprites» d un jeu 2D, pour l affichage de couches transparentes à la manière d un dessin animé, etc. + Couleur 41