Code source du fichier src/gengraphe.c

/*
    Fichier gengraphe.c
    Auteur Bernard Chardonneau

    Logiciel libre diffusé dans le domaine public.


    Bibliothèque de fonctions permettant de générer des graphiques
    sur l'évolution de la vaccination COVID 19 en France.
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>

// bibliothèques de fonctions
#include "entete-bmp.h"

// constantes
#include "graphe.h"

#define jourdeb        18610
#define hauteur_fonte      7


char *image [hauteur];
int  largeur;


// palette des couleurs (gris clair, noir, blanc, gris, orange,
//                       vert jaune, vert, bleu vert, bleu, violet)
long palette [] = {0xF0F0F0, 0x000000, 0xFFFFFF, 0xB0B0B0, 0xFF6000,
                   0xC08000, 0x00A000, 0x0080FF, 0x2020FF, 0x8000FF};

// durée des mois de l'année de 2021 à 2023
int dureemois [] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

// dessin des chiffres et du symbole % à raison d'un bit par pixel
unsigned char fonte [11][hauteur_fonte] =
{
    0x1C, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, // 0
    0x08, 0x18, 0x28, 0x08, 0x08, 0x08, 0x1C, // 1
    0x1C, 0x22, 0x02, 0x04, 0x08, 0x10, 0x3E, // 2
    0x1C, 0x22, 0x02, 0x0C, 0x02, 0x22, 0x1C, // 3
    0x04, 0x0C, 0x14, 0x24, 0x3E, 0x04, 0x04, // 4
    0x3E, 0x20, 0x20, 0x3C, 0x02, 0x22, 0x1C, // 5
    0x0C, 0x10, 0x20, 0x3C, 0x22, 0x22, 0x1C, // 6
    0x3E, 0x22, 0x04, 0x08, 0x10, 0x10, 0x10, // 7
    0x1C, 0x22, 0x22, 0x1C, 0x22, 0x22, 0x1C, // 8
    0x1C, 0x22, 0x22, 0x1E, 0x02, 0x04, 0x18, // 9
    0x00, 0x42, 0xA4, 0x48, 0x12, 0x25, 0x42  // %
};



// rajoute dans l'image un chiffre ou le symbole %

void affcar (char caract, int lig, int col)
{
    int numcar;  // numéro du caractère dans le tableau fontes
    int i, j, k; // compteurs
    int x;       // position du pixel courant sur l'axe des x
    char valcar;


    // si le caractère à insérer est un chiffre
    if ('0' <= caract && caract <= '9')
        // calculer sa position dans le tableau fontes
        numcar = caract & 0x0F;

    // sinon, si c'est le symbole %
    else if (caract == '%')
        // prendre sa position dans le tableau fontes
        numcar = 10;
    // sinon
    else
        // l'affichage de ce caractère n'est pas prévu
        return;

    // pour toutes les lignes du dessin du caractère
    for (k = 0; k < hauteur_fonte; k++)
    {
        // récupérer les pixels de la ligne à noircir
        valcar = fonte [numcar][k];

        // se positionner sur le pixel de gauche
        x = col;

        // tant qu'il reste des pixels à noircir
        while (valcar)
        {
            // si le pixel sur lequel on est positionné doit être noirci
            if (valcar & 0x80)
                // le faire
                image [lig][x] = 1;

            // se décaler d'un pixel vers la droite
            valcar = valcar << 1;
            x++;
        }

        // passer à la ligne du dessous
        lig ++;
    }
}



// rajoute dans l'image la chaine de caractères passée en paramètre

void affchaine (char *chaine, int lig, int col)
{
    // tant que la chaine de caractères n'est pas affichée entièrement
    while (*chaine)
    {
        // copier le caractère de gauche dans l'image
        affcar (*chaine, lig, col);

        // se positionner sur l'emplacement du caractère suivant
        col = col + 7;

        // passer au caractère suivant
        chaine ++;

        // correction si prochain caractère large
        if (*chaine == '%')
            col = col + 2;
    }
}



/*
   alloue la mémoire nécessaire pour mémoriser les graphiques
   à raison d'un octet par pixel, trace les axes de référence
   en marquant l'échelle des pourcentages et des dates
*/
void cree_base_image ()
{
    int i, j;  // compteurs
    int mois;  // numéro de mois - 1
    int annee; // année
    char chaine [5]; // chaine de caractères contenant un pourcentage
    int p;     // pourcentage


    // largeur de l'image en pixels
    largeur = (time (0) / 86400) - jourdeb;

    // on ajoute une marge à gauche et la largeur doit être multiple de 8
    largeur = largeur + 32 - (largeur % 8);

    // fabriquer l'entête bmp
    gen_entete_bmp (largeur, hauteur, sizeof (palette) / 4);

    // pour chaque ligne des images
    for (i = 0; i < hauteur; i++)
    {
        // allouer la mémoire pour les pixels de la ligne
        image [i] = malloc (largeur);

        // pour chaque pixel de la ligne
        for (j = 0; j < largeur; j++)
            // colorer ce pixel en gris très clair
            image [i][j] = 0;
    }

    // tracé de l'axe vertical
    for (i = haut_axe_y; i < bas_axe_y; i++)
        image [i][p_axe_x] = 1;

    // tracé de l'axe horizontal
    for (j = p_axe_x; j < largeur; j++)
        image [bas_axe_y][j] = 1;

    // on va rajouter une échelle des pourcentages

    // pourcentage du haut qui sera indiqué en clair
    p = 100;

    // tous les 30 pixels en hauteur (soit 20 %)
    for (i = haut_axe_y; i <= bas_axe_y; i = i + 30)
    {
        // tracer un tiret horizontal noir
        for (j = p_axe_x - 4; j < p_axe_x; j++)
            image [i][j] = 1;

        // fabriquer une chaine de caractères du pourcentage
        sprintf (chaine, "%d%%", p);

        // l'écrire à gauche du tiret
        affchaine (chaine, i - 4, 28 - (7 * strlen (chaine)));

        // passer au pourcentage du dessous
        p = p - 20;
    }

    // ajout échelle des dates

    // initialisation
    mois = 1;
    annee = 2021;
    j = p_axe_x;

    // tant qu'on peut rajouter des mois
    while (j < largeur)
    {
        // tracer un tiret vertical
        for (i = bas_axe_y; i < bas_axe_y + 5; i++)
            image [i][j] = 1;

        // s'il y a la place à droite pour écrire le numéro du mois
        if (j + 7 <= largeur)
        {
            // on l'écrira en dessous du tiret
            i = i + 3;

            // toujours sur 2 chiffres
            affcar ('0' | (mois / 10), i, j - 8);
            affcar ('0' | (mois % 10), i, j);
        }

        // si premier mois de l'année
        if (mois == 1)
        {
            // prolonger le tiret vertical
            for (i = bas_axe_y + 20; i < hauteur; i++)
                image [i][j] = 1;

            // s'il y a la place pour rajouter l'année
            if (j + 30 < largeur)
            {
                // fabriquer la chaine de l'année
                sprintf (chaine, "%d", annee ++);

                // si année complète dans le graphique
                if (j + 365 < largeur)
                    // mettre l'année centrée sur la mois de juillet
                    affchaine (chaine, hauteur - 8, j + 166);
                // sinon
                else
                    // centrer l'année sur l'espace restant
                    affchaine (chaine, hauteur - 8, (j + largeur - 28) / 2);
            }
        }

        // passer au mois suivant
        j = j + dureemois [mois - 1];
        mois ++;

        // si changement d'année
        if (mois > 12)
            // revenir en janvier
            mois = 1;
    }
}



/*
   réinitialise la partie de l'image qui contiendra les graphiques
   couleur de fond + tracés permettant de suivre les échelles des
   pourcentages et des dates
*/
void init_image ()
{
    int i, j;  // compteurs
    int mois;  // numéro de mois - 1


    // pour chaque ligne des images
    for (i = haut_axe_y; i < bas_axe_y; i++)
        // pour chaque pixel de la ligne
        for (j = p_axe_x + 1; j < largeur; j++)
            // colorer ce pixel en blanc
            image [i][j] = 2;

    // ajout quadrillage horizontal
    for (i = haut_axe_y; i < bas_axe_y; i = i + 30)
        for (j = p_axe_x + 1; j < largeur; j++)
            // pixel gris
            image [i][j] = 3;

    // ajout quadrillage vertical

    // janvier
    mois = 0;

    // premier trait vertical pour le 1er février
    j = p_axe_x + dureemois [0];

    // tant qu'on peut tracer des traits verticaux
    while (j < largeur)
    {
        // tracer un trait vertical
        for (i = haut_axe_y; i < bas_axe_y; i++)
            // pixel gris
            image [i][j] = 3;

        // avancer d'un mois
        mois ++;

        // si changement d'année
        if (mois == 12)
            // revenir en janvier
            mois = 0;

        // position du prochain trait vertical
        j = j + dureemois [mois];
    }
}



//  génère un fichier image à partir de l'entête et du tableau de pixels mémorisé

void genimage (char *fichier)
{
    char deuxpix;  // groupe de 2 pixels
    int  i, j;     // compteurs
    FILE *descfic; // descripteur du fichier image


    // ouvrir le fichier en écriture
    descfic = fopen (fichier, "w");

    // si l'ouverture s'est bien passée
    if (descfic)
    {
        // copier l'entête bmp
        fwrite (entete, sizeof (entete), 1, descfic);

        // copier la palette
        fwrite (palette, sizeof (palette), 1, descfic);

        // générer les lignes de l'image du bas vers le haut
        i = hauteur;

        // répéter
        do
        {
            // remonter d'une ligne
            i--;

            // se positionner en début de ligne
            j = 0;

            // tant que non fin de ligne
            while (j < largeur)
            {
                // regrouper 2 pixels sur un octet et le copier dans le fichier
                deuxpix = (image [i][j] << 4) | image [i][j+1];
                putc (deuxpix, descfic);

                // passer aux 2 pixels suivants
                j = j + 2;
            }
        }
        // jusque fin de l'image
        while (i);

        // le fichier bmp est prêt
        fclose (descfic);
    }
    // sinon
    else
        // message d'erreur
        fprintf (stderr, "Impossible de créer le fichier %s\n", fichier);
}