/* 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); }