17 février 2020

Librairie graphique GD

GD est une librairie graphique écrite en C qui permet de créer ou ouvrir des images (jpg, png, gif, etc.) et de tracer dedans des formes géométriques (ligne, rectangle, cercle, etc.). Elle permet aussi quelques manipulations élémentaires. Le langage est C.

Premiers pas

carré noir, diagonale blanche

Premier exemple

Code provenant du site officiel, dont le résultat est l'image ci-contre.

/*
gd-ex1.c
gcc gd-ex1.c -o gd-ex1 -lgd
*/
#include "gd.h"
#include <stdio.h>
 
int main() {
   gdImagePtr im;      // déclare l'image
   FILE *jpegout;          // déclare le fichier de sortie
   int black;              // index des couleurs
   int white;
   // Alloue une image 128×128 pixels
   im = gdImageCreate(128, 128);
   // Allocation des couleurs RGB
   black = gdImageColorAllocate(im, 0, 0, 0);   // fond
   white = gdImageColorAllocate(im, 255, 255, 255); // couleur de tracé
   // Dessine une ligne entre le coin supérieur gauche et le coin opposé
   gdImageLine(im, 0, 0, 127, 127, white);
   // ouvre le fichier en écriture
   jpegout = fopen("gd-ex1.jpg", "w");
   // écrit l'image sur le disque avec les réglages par défaut -1
   gdImageJpeg(im, jpegout, -1);
   // ferme le fichier et libère la mémoire de l'image
   fclose(jpegout);
   gdImageDestroy;
}

C'est remarquablement simple et efficace.

Remarques :

Deuxième exemple

pingouin pingouin avec une barre

Il est inspiré du Linux journal et permet de travailler sur une image existante. Dans cet exemple nous rajouterons une barre au pingouin en utilisant ligne et rectangle.

/* gd-eg2.c */
#include <gd.h>
#include <stdio.h>
 
int main() 
{
   gdImagePtr tux;
   FILE *out, *in;
   int black, grey, white;
 
   in = fopen("tuxin.jpg","r");
   tux = gdImageCreateFromJpeg(in);
   fclose(in);
   // couleurs
   black = gdImageColorAllocate(tux, 0, 0, 9); 
   grey = gdImageColorAllocate(tux, 160, 160, 200); 
   white = gdImageColorAllocate(tux, 200, 200, 200); 
   // ligne et rectangles
   gdImageLine(tux, 12, 50, 88, 50, white);
   gdImageFilledRectangle(tux, 11, 51, 89, 52, grey);
   gdImageFilledRectangle(tux, 11, 53, 89, 60, black);
 
   out = fopen("tuxout.jpg", "w");
   gdImageJpeg(tux, out, -1); 
   fclose(out); 
 
   gdImageDestroy(tux);
}

Reamrque

Il y avait des erreurs dans l'article du Linux Journal que je n'ai pas su élucider.

Programme de tracé du graphe d'une courbe

J'ai fait des tas de programmes pour tracer le graphe d'une courbe. En général c'est pour illustrer les articles de ce site. Mais celui qui me plait le plus c'est celui présenté ci-dessous. Il me plait parce que je dessine directement dans l'image en création. Plus j'utilise GD, plus je le trouve génial. Il y a tout ce qu'il faut, et tout y est extêmement simple.

Code source de gd-plot.c

/* gd-plot.c
:w | !gcc % -o %< -lgd && ./%< && display gd-plot.jpg
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gd.h>
 
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
  
gdImagePtr im; // image pointer
FILE *jpeg; 
int bg, fg; // background and foreground colors
const int pad = 8; // padding
float xO = 1.5, yO = 1.5; // origin
int sx = 25, sy = 25; // scales
int W = 100 + 2*pad, H = 125 + 2*pad; // image width, height
// debug
float _x = 0, _y = 0; // last position
// x, y to screen X, Y coordinates
int X(float x) {return round(x*sx + xO*sx) + pad; } 
int Y(float y) {return H - round(y*sy + yO*sy) -pad;}
// convenience drawings
void line(float, float, float, float);
void lineto(float x, float y) {line(_x, _y, x, y);}
void str(char *, float, float);
void axis();
 
void plot(float, float); // plotting
float f(float x) {return x*x - 1;}    // example function to plot
 
int main(int argc, char *argv[]) 
{
   im = gdImageCreate(W, H);
   bg = gdImageColorAllocate(im, 255, 255, 255); 
   fg = gdImageColorAllocate(im, 0, 0, 0); 
   axis();
 
   plot(-1, 2);
   str("x ∈ [-1, 2]  ↦  x² - 1", 5, 10);
   jpeg = fopen("gd-plot.jpg", "w");
   gdImageJpeg(im, jpeg, -1);
   fclose(jpeg);
   gdImageDestroy(im);
}
  
void line(float x1, float y1, float x2, float y2) {
   gdImageLine(im, X(x1), Y(y1), X(x2), Y(y2), fg);
   _x = x2; _y = y2;
}
  
void str(char *s, float x, float y)
{
   int brect[8];
   char *font= "/usr/share/fonts/TTF/DejaVuSans.ttf";
   gdImageStringFT(im, brect, fg, font, 8, 0, x, y, s);  
}
 
void axis()
{
   float d = 0.05; // units 
   line(-xO, 0, (W - 2*pad)/sx -xO, 0);
   line(1, d, 1, -d);
   line(0, -yO, 0, (H - 2*pad)/sy- yO);
   line(-d, 1, d, 1);
   str("O", X(-0.4), Y(-0.4));
   str("1", X(1.02), Y(-0.4));
   str("1", X(-0.4), Y(1.02));
}
 
void plot(float a, float b)
{
   gdImageSetThickness(im, 2);      // thickness
   float xi = 0.05; // step
   line(a, f(a), a + xi, f(a + xi));    // starting line
   for(float x=a+2*xi; x<b; x+=xi) lineto(x, f(x));
   gdImageSetThickness(im, 1);      // reset thickness
}

Résultat ci-contre : graphe de x->x²-1

Commentaires

Ligne 34 : Création d'une image

C'est la fonction gdImageCreate qui alloue le pointeur im et crée l'image avec la couleur de fond fg qui est la première couleur allouée dans le programme. ligne 35.

Voir gdImageCreate et couleur de fond dans les commentaires du code donné en exemple : /* Allocate the color ....

Ligne 42 : Enregistrement de l'image

gdImageJpeg enregistre l'image pointée par im au format JPEG. Voir gdImageJpeg et Image formats dans la side bar du site.

D'autres formats sont possibles.

Ligne 47 : Fonction line

On utilise la fonction gdImageLine.

La fonction gdImageThickness permet de définir l'épaisseur du trait. Par exemple après l'appel de gdImageThickness(im, 3) tous les tracés dans l'image pointée par im auront une épaisseur de 3 pixels. Pour changer cette propriété il faut l'appeler à nouveau.

La fonction lineto (Ligne 25) est une commodité qui permet d'enchaîner les tracés en fournissant les coordonnées du point suivant.

Voir gdImageLine et la rubrique other de gd.c, Summary.

Ligne 52 : Fonction str

C'est une fonction de tracé de texte. On y utilise la fonction gdImageStringFT. Voir les fonctions de la rubrique FreeType font rendering.

Ligne 71 : Fonction plot

On fixe l'épaisseur du trait à 3, on trace la courbe, puis on remet l'épaisseur du trait à 1. Sait-on jamais.

Remarque : La ligne 2 fera l'objet d'un article Vim.

Conclusion

Cette bibliothèque est géniale. Elle fourmille de potentialités. Je regrette de ne l'avoir pas découverte plus tôt. Par exemple pour faire une image d'illustration, une courbe ou une représentation graphique, elle constitue l'outil idéal. Car pour nous qui programmons, nous n'avons pas besoin d'usine à gaz qui s'adapte à tout sauf à ce qu'on a prévu de faire.




Réalisé avec Qlam - LGPL