Images BitMap et dessin pixel par pixel en C

vendredi 25 juillet 2025



en cours de rédaction


1 – Représentation des couleurs

?

typedef int couleur ;

#define NOIR 0

/* Couleur associée à un triplet (r, g, b) */
couleur RGB(int r, int g, int b)
{
  return b + 256 * g + 65536 * r ;
}


/* Triplet (r, g, b) associé à une couleur c */
void VersRGB(couleur c, int *r, int *g, int *b)
{
  *b = c % 256 ;
  *g = c / 256 % 256 ;
  *r = c / 65536 ;
}



2 – Représentation des images

?

struct _pix
{
  int px ;
  int py ;
} ;
typedef struct _pix pix ;


struct _image {
  int       Largeur ;
  int       Hauteur ;
  couleur **Pixels ;
} ;
typedef struct _image image ;


/* Création d'une image de taille L x H, avec un fond de couleur donnée */
image CreerImage(int L, int H, couleur CouleurDuFond)
{
  image I ;
  I.Largeur = L ;
  I.Hauteur = H ;
  
  I.Pixels = malloc(L * sizeof(couleur*)) ;
  pix p ;
  for(p.px = 0 ; p.px < L ; p.px++)
  {
    I.Pixels[p.px] = malloc(H * sizeof(couleur)) ;
    for(p.py = 0 ; p.py < H ; p.py++)
    {
      I.Pixels[p.px][p.py] = CouleurDuFond ;
    }
  }
  return I ;
}



3 – Fichiers BitMap

?

#include <string.h>

/* Dossier dans lequel les fichiers sont sauvegardés */
#define ADRESSE "D:/Choses/"


/* Écriture de la valeur x sur nb_octets */
void EcrireOctets(FILE *f, int nb_octets, int x)
{
  while(nb_octets > 0)
  {
    fputc((int)(x % 256), f) ;
    x /= 256 ; nb_octets-- ;
  }
}


/* Lectures d'informations dans les fichiers */
int LireEntier(FILE *f, int nb_octets)
{
  int i, x = 0, p = 1 ;
  for(i = 0 ; i < nb_octets ; i++)
  {
    x += p * fgetc(f) ;
    p *= 256 ;
  }
  return x ;
}


/* Structure pour les en-têtes d'images BitMap */
struct _bitmap
{
  int BM ;
  int TailleFichier ;
  int Rsv ;
  int AdrDonnees ;
  int TailleInfos ;
  int Largeur, Hauteur ;
  int nbPlans ;
  int BitsParPlan ;
  int Cmp ;
  int TailleImage ;
  int Res_x ;
  int Res_y ;
  int nbClr ;
  int nbClrImp ;
} ;
typedef struct _bitmap bitmap ;


/* Création d'un fichier BitMap à partir d'une image */
#define TAILLE_INFOS 40
#define NB_PLANS 1
#define BITS_PAR_PLAN 24
#define CMP 0
#define RES_X 7559
#define RES_Y 7559
#define NB_CLR 0
#define NB_CLR_IMP 0
#define RSV 0
#define ADR_DONNEES 54
void SauvegarderImage(char *NomFichier, image I)
{
  /* Ouverture du fichier */
  char *s = malloc(1024 * sizeof(char)) ;
  s = strcpy(s, ADRESSE) ;
  s = strcat(s, NomFichier) ;
  s = strcat(s, ".bmp") ;
  FILE *f = fopen(s, "w") ;
  free(s) ;
  
  /* En-tête */
  fputc('B', f) ; fputc('M', f) ;
  int L_reelle = I.Largeur, r = I.Largeur * 3 % 4 ;
  if( r > 0 )
  {
    r = 4 - r ;
  }
  L_reelle += r ;
  int TAILLE_IMG = L_reelle * I.Hauteur * NB_PLANS * BITS_PAR_PLAN ;
  int TAILLE_FICHIER = ADR_DONNEES + TAILLE_IMG ;
  EcrireOctets(f, 4, TAILLE_FICHIER) ;
  EcrireOctets(f, 4, RSV) ;
  EcrireOctets(f, 4, ADR_DONNEES) ;
  EcrireOctets(f, 4, TAILLE_INFOS) ;
  EcrireOctets(f, 4, I.Largeur) ;
  EcrireOctets(f, 4, I.Hauteur) ;
  EcrireOctets(f, 2, NB_PLANS) ;
  EcrireOctets(f, 2, BITS_PAR_PLAN) ;
  EcrireOctets(f, 4, CMP) ;
  EcrireOctets(f, 4, TAILLE_IMG) ;
  EcrireOctets(f, 4, RES_X) ;
  EcrireOctets(f, 4, RES_Y) ;
  EcrireOctets(f, 4, NB_CLR) ;
  EcrireOctets(f, 4, NB_CLR_IMP) ;
  
  /* Lignes de l'image */
  pix p ;
  for(p.py = 0 ; p.py < I.Hauteur ; p.py++)
  {
    for(p.px = 0 ; p.px < I.Largeur ; p.px++)
    {
      EcrireOctets(f, 3, I.Pixels[p.px][p.py]) ;
    }
    /* Fin de la ligne */
    EcrireOctets(f, r, 0) ;
  }
  
  /* Fermeture du fichier */
  fclose(f) ;
}


/* Lecture d'une image BitMap 24 bits */
image OuvrirImage(char *NomFichier)
{
  /* Ouverture du fichier */
  char *s = malloc(1024 * sizeof(char)) ;
  s = strcpy(s, ADRESSE) ;
  s = strcat(s, NomFichier) ;
  s = strcat(s, ".bmp") ;
  FILE *f = fopen(s, "r") ;
  free(s) ;
  
  /* En-tête */
  bitmap EnTete ;
  EnTete.BM = LireEntier(f, 2) ;
  EnTete.TailleFichier = LireEntier(f, 4) ;
  EnTete.Rsv = LireEntier(f, 4) ;
  EnTete.AdrDonnees = LireEntier(f, 4) ;
  EnTete.TailleInfos = LireEntier(f, 4) ;
  EnTete.Largeur = LireEntier(f, 4) ;
  EnTete.Hauteur = LireEntier(f, 4) ;
  EnTete.nbPlans = LireEntier(f, 2) ;
  EnTete.BitsParPlan = LireEntier(f, 2) ;
  EnTete.Cmp = LireEntier(f, 4) ;
  EnTete.TailleImage = LireEntier(f, 4) ;
  EnTete.Res_x = LireEntier(f, 4) ;
  EnTete.Res_y = LireEntier(f, 4) ;
  EnTete.nbClr = LireEntier(f, 4) ;
  EnTete.nbClrImp = LireEntier(f, 4) ;
  
  image I = CreerImage(EnTete.Largeur, EnTete.Hauteur, NOIR) ;
  int L_reelle = EnTete.Largeur, r = EnTete.Largeur * 3 % 4 ;
  if( r > 0 )
  {
    r = 4 - r ;
  }
  L_reelle += r ;
  
  /* Lignes de l'image */
  pix p ;
  for(p.py = 0 ; p.py < EnTete.Hauteur ; p.py++)
  {
    for(p.px = 0 ; p.px < EnTete.Largeur ; p.px++)
    {
      I.Pixels[p.px][p.py] = LireEntier(f, 3) ;
    }
    /* Fin de la ligne */
    LireEntier(f, r) ;
  }
  
  /* Fermeture du fichier */
  fclose(f) ;
  return I ;
}



4 – Exemple

?

int min(int a, int b)
{
  return (a <= b) ? a : b ;
}

int max(int a, int b)
{
  return (a >= b) ? a : b ;
}


/* Disque centré en (xC, yC) de couleur c */
void DessinerDisqueTransparent(image I, couleur c, double Transparence,
                               int xC, int yC, int Rayon)
{
  int Rayon_carre = Rayon * Rayon ;
  
  /* La couleur à appliquer */
  int *r1 = malloc(sizeof(int)),
      *g1 = malloc(sizeof(int)),
      *b1 = malloc(sizeof(int)) ;
  int r, g, b ;
  VersRGB(c, r1, g1, b1) ;
  
  /* Les pixels à colorier */
  int *r2 = malloc(sizeof(int)),
      *g2 = malloc(sizeof(int)),
      *b2 = malloc(sizeof(int)) ;
  pix p ;
  int dx, dy ;
  int px_min = max(0, xC - Rayon) ;
  int px_max = min(I.Largeur - 1, xC + Rayon) ;
  int py_min = max(0, yC - Rayon) ;
  int py_max = min(I.Hauteur - 1, yC + Rayon) ;
  for(p.px = px_min ; p.px <= px_max ; p.px++)
  {
    dx = p.px - xC ;
    for(p.py = py_min ; p.py <= py_max ; p.py++)
    {
      dy = p.py - yC ;
      if(dx * dx + dy * dy <= Rayon_carre)
      {
        /* Fondu avec la couleur à l'arrière */
        VersRGB(I.Pixels[p.px][p.py], r2, g2, b2) ;
        r = *r1 + (int)(Transparence * (double)(*r2 - *r1)) ;
        g = *g1 + (int)(Transparence * (double)(*g2 - *g1)) ;
        b = *b1 + (int)(Transparence * (double)(*b2 - *b1)) ;
        I.Pixels[p.px][p.py] = RGB(r, g, b) ;
      }
    }
  }
  free(r1) ; free(g1) ; free(b1) ;
  free(r2) ; free(g2) ; free(b2) ;
}


/* Dessine cinquante disques aléatoires sur une page blanche */
int main()
{
  srand(3141592) ;
  couleur BLANC = RGB(255, 255, 255) ;
  image I = CreerImage(1920, 1080, BLANC) ;
  
  int xC, yC, Rayon ;
  int r, g, b ;
  
  int k ;
  for(k = 0 ; k < 50 ; k++)
  {
    xC    = rand() % 1920 ;
    yC    = rand() % 1080 ;
    Rayon = rand() % 200 ;
    r = rand() % 256 ; g = rand() % 256 ; b = rand() % 256 ;
    DessinerDisqueTransparent(I, RGB(r, g, b), 0.7, xC, yC, Rayon) ;
  }
  
  SauvegarderImage("disques", I) ;
  return 0 ;
}
cinquantes disques aléatoires