Fonctions communes pour générer
les bargraphes et les graphiques

Cette page décrit les 2 bibliothèques de fonctions qui sont utilisées à la fois pour générer les bargraphes et pour générer les graphiques du site.

Accès aux champs d'un fichier CSV local

Une première bibliothèque de fonctions permet d'extraire les données d'un fichier CSV local préalablement ouvert en écriture.

Elle est composé de 3 fonctions :

La fonction recupchamp permet de récupérer le contenu du champ du fichier CSV sur lequel on est positionné.
Elle accepte 2 paramètres :
Après avoir lu un premier caractère à partir de l'endroit du fichier où on s'était arrêté la fois précédente (début du fichier la toute première fois), on mémorise ce caractère dans la variable champ et on lit le caractère suivant.

On continue le traitement jusqu'à ce que le dernier caractère lu indique une fin de champ (caractère ; ou passage à la ligne).

A chaque lecture, on teste également si on est arrivé en fin de fichier.

Comme les valeurs du fichier CSV qui nous intéressent pour réaliser des bargraphes et graphiques sont des pourcentages, la longueur des champs attendus est limitée à 5 caractères. Si un champ lu venait à être plus long, les caractères au delà du cinquième ne seront pas mémorisés.

Une fois le contenu du champ récupéré, on le complète d'un octet à 0 qui indique une fin de chaine de caractères en langage C.

// récupérer le début d'un champ (tronqué à 5 caractères)

void recupchamp (FILE *descfic, char *champ)
{
    int car;  // caractère lu
    int i;    // position dans le tableau champ


    // initialisation
    i = 0;

    // lire le premier caractère du champ
    car = getc (descfic);

    // tant que ni fin de champ, ni fin de ligne, ni fin de fichier
    while (car != ';' && car != '\n' && car != EOF)
    {
        // s'il y a de la place dans champ pour rajouter ce caractère
        if (i < 5)
            // le faire
            champ [i++] = car;

        // lire le caractère suivant
        car = getc (descfic);
    }

    // terminer la chaine de caratères champ
    champ [i] = '\0';
}
      
Une deuxième fonction sautechamp permet d'avancer dans le fichier CSV local en lisant sans mémoriser son contenu un champ dont on n'a pas besoin.

Elle accepte comme unique paramètres descfic qui est le descripteur du fichier csv local ouvert en lecture.

Le traitement qu'elle fait consiste à lire les caractères du fichier CSV local un par un jusqu'à ce qu'on trouve un caractère de fin de champ ; , une fin de ligne ou une fin de fichier.

// sauter un champ dans la ligne sans le récupérer

void sautechamp (FILE *descfic)
{
    int car;  // caractère lu

    // répéter
    do
        // lire le caractère suivant
        car = getc (descfic);
    // jusque fin de champ, de ligne ou de fichier
    while (car != ';' && car != '\n' && car != EOF);
}
      
Une troisième fonction finligne fonctionne presque comme sautechamp mais elle s'arrête de lire seulement en fin de ligne ou en fin de fichier. Elle permet donc d'ignorer les derniers champs de la ligne sans avoir à les sauter un par un.
// sauter le reste de la ligne sans rien récupérer

void finligne (FILE *descfic)
{
    int car;  // caractère lu

    // répéter
    do
        // lire le caractère suivant
        car = getc (descfic);
    // jusque fin ligne ou de fichier
    while (car != '\n' && car != EOF);
}
      

Initialisation de l'entête d'un fichier image bmp

Comme pour les autres formats d'image, les fichiers bmp commencent par une entête qui décrit les caractéristiques de l'image.

L'entête bmp commence par 2 caractères, puis la quasi totalité des données qui suivent sont des nombres sur 4 octets.

Cela pose un problème de gestion de la mémoire car sur un ordinateur, notamment sur un PC, les valeurs numériques sur 4 octets commencent à des adresses mémoire multiples de 4.

Ici, à cause des 2 premiers octets du début, ces nombres commencent à des adresses paires non multiples de 4.

Toutefois pour les images qu'on aura à générer, les valeurs à mettre dans les champs de l'entête sont petites (inférieures à 216 = 65536).

Pour les bargraphes, toutes les valeurs sont et resteront inférieures à cette limite. Pour les graphiques d'évolution de la vaccination, fin 2022, cette limite sera dépassée pour la taille de l'image et celle du fichier s'il n'est pas encore compressé à ce moment là.

On simplifie la gestion de la mémoire en mémorisant les différentes valeurs de l'entête dans un tableau d'entiers sur 16 bits (2 octets). Les valeurs numériques sur 4 octets sont pour l'instant toutes composées d'un entier sur 2 octets suivi de 2 octets à 0.

Avec le compilateur gcc pour microprocesseur de type Intel, les entiers sur 2 octets sont de type short (ou unsigned short) aussi bien avec des microprocesseurs 32 bits qu'avec des microprocesseurs 64 bits.

L'entête de l'image bmp sera donc mémorisée dans un tableau d'entiers de type short et un faisant un pré-remplissage des champs de l'entête qui indiquent des caractéristiques de l'image identiques pour les bargraphes et les graphiques, à savoir :
on obtiendra ceci :
// entête bmp partiellement pré-calculée
short entete [] = {0x4D42, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 1,
                   4, 0, 0, 0, 0, 10000, 0, 10000, 0, 0, 0, 0, 0};
      
Il faudra compléter cette entête avec des valeurs qui ne sont pas les mêmes pour les bargraphes et le graphique. Pour cela, on définit une fonction gen_entete_bmp qui permettra de compléter l'entête ci dessus. Cette fonction a besoin de 3 paramètres&npsp;:
// initialisation de l'entête d'une image bmp 3 à 16 couleurs

void gen_entete_bmp (int largeur, int hauteur, int nb_coul)
      
Le format d'images bmp impose comme contrainte que chaque ligne de l'image occupe dans le fichier un multiple de 4 octets (utilisées ou non pour les derniers). Il va falloir en tenir compte pour calculer cette longueur et à partir de là, la taille de l'image.
    // variables locales pour des calculs
    short szimage, deplacement, larg2, manque;


    // calcul des valeurs de certains champs de l'entête bmp

    // pixels en largeur utilisés ou non (doit être multiple de 8)
    manque = largeur % 8;

    if (manque)
        larg2 = largeur + 8 - manque;
    else
        larg2 = largeur;

    // taille de la partie image du fichier
    szimage = larg2 * hauteur / 2;
      
Il faut aussi calculer à partir de quel endroit du fichier bmp commence l'image. Pour ça, (dans les images bmp utilisant jusqu'à 256 couleurs), chaque couleur doit être définie sur une valeur de 4 octets. La taille de la palette de couleurs s'ajoute à cette de l'entête.
    // position du premier octet de la partie image du fichier
    deplacement = sizeof (entete) + (nb_coul * 4);
      
À présent, on a calculé tout ce qu'il faut pour compléter l'entête du fichier bmp. Il suffit de mettre les valeurs récupérées ou calculées aux bons endroits dans le tableau d'entiers 16 bits.
    // mise à jour des parties variables de l'entête

    // taille du fichier
    entete [1]  = szimage + deplacement;

    // position du début de la partie image
    entete [5]  = deplacement;

    // pixels en largeur
    entete [9]  = largeur;

    // pixels en hauteur
    entete [11] = hauteur;

    // nombre d'octets de la zone image
    entete [17] = szimage;

    // nombre de couleurs
    entete [23] = nb_coul;
    entete [25] = nb_coul;
}
      
Remarque :

Plutôt que de manipuler des indices de tableaux peu parlants, dans le projet Cyloop (logiciel libre), l'entête bmp est définie sous la forme d'une structure.

On peut constater que celle-ci commence par 2 octets de remplissage qui ne devront pas être recopiés dans le fichier mais qui permettent d'avoir les données qui suivent (un mélange de caractères et d'entiers de 16 et de 32 bits) bien positionnées les unes par rapport aux autres.