TD8 - Headers
Le but de ce TD est de manipuler plusieurs fichiers sources et de les compiler ensemble pour créer un programme.
Nous allons créer une structure qui permet de représenter une couleur avec trois composantes red
, green
et blue
.
- Créer un fichier
color.hpp
qui contiendra un espace de nomColor
avec la définition de la structureRgb
et les prototypes des fonctions et méthodes suivantes :- La structure devra s'appeler
Rgb
et contenir trois entiers nommésred
,green
etblue
de typeunsigned int
avec une valeur par défaut initialisée à0
. - La structure devra contenir une méthode
display
qui permet d'afficher (std::cout
) la couleur sous la formergb(red, green, blue)
.
- La structure devra s'appeler
On pourrait aussi utiliser un type unsigned char
pour les composantes de couleur mais ça va nous poser des problèmes pour les calculs et pour l'affichage. En effet, les types char
s'affichent comme des caractères ASCII et non comme des entiers. De plus, les calculs avec des char
peuvent poser des problèmes de débordement de capacité.
- Créer un fichier
color.cpp
qui contiendra les définitions des méthodes et fonctions.
Maintenant que nous avons notre structure Color::Rgb
, nous allons ajouter des fonctions pour pouvoir manipuler nos couleurs pour en obtenir de nouvelles.
-
Créer un nouveau fichier
color_utils.hpp
qui contiendra les prototypes des fonctions suivantes :mix
qui permet de mélanger deux couleurs en faisant la moyenne des composantesred
,green
etblue
. Elle retourne la couleur résultante et prend en paramètre deux couleurs (références constantes).luminance
qui permet de calculer la luminance d'une couleur en utilisant la formule (⚠️ il faudra convertir au préalable les composantes entières en flottants ) et retourner le résultat sous forme d'un nombre flottant entre 0 et 1.invert
qui permet d'inverser les composantes d'une couleur (255 - composante) et de retourner la couleur inversée.grayscale
qui permet de convertir une couleur en une couleur en niveaux de gris. (Une couleur en niveaux de gris a ses composantesred
,green
etblue
égales à la luminance de la couleur).
-
Créer un nouveau fichier
color_utils.cpp
qui contiendra les définitions des fonctions. -
Créer un nouveau couple de fichiers
color_hex.cpp
etcolor_hex.hpp
dans lesquels vous allez ajouter des fonctions pour manipuler des couleurs en hexadécimal. Le fichier contiendra les fonctions suivantes (toujours dans l'espace de nomColor
):Rgb Rgb_from_hex(unsigned int const hex)
qui permet de convertir un entier hexadécimal en une couleur.unsigned int rgb_to_hex_int(Rgb const& color)
qui permet de convertir une couleur en un entier hexadécimal.
Pour convertir un entier hexadécimal en composantes red
, green
et blue
, vous pouvez utiliser des opérations de décalage binaire (>>
) et des AND binaires (&
) pour extraire les composantes.
En effet, un entier hexadécimal est composé de 3 octets (24 bits) où les 8 premiers bits représentent la composante red
, les 8 bits suivants la composante green
et les 8 derniers bits la composante blue
.
Par exemple, le nombre 0xff0000 se découpe en 3 octets ff
, 00
et 00
qui correspondent respectivement à red
, green
et blue
. En binaire, cela donne 11111111
, 00000000
et 00000000
.
Ici, le préfixe 0x
indique que l'on parle d'un nombre hexadécimal et pas d'une chaîne de caractères, de la même manière que le suffixe f
pour les nombre flottants par exemple.
Pour extraire la composante red
, il faut utiliser des opérations de décalage binaires et de masquage.
Par exemple 10100101
& 11110000
donne 10100000
(masquage) et 10100000
>> 4 donne 00001010
(décalage).
Ici on peut utiliser ce mécanisme pour extraire les composantes red
, green
et blue
de l'entier hexadécimal.
0xe812f0 & 0xff0000 donne 0xe80000 et 0xe80000 >> 16 donne 0x0000e8
qui correspond à la composante red
de la couleur.
Pour obtenir la composante green
, il faut faire un masquage avec 0x00ff00
et un décalage de 8 bits (>> 8
). Ce qui donne avec les opérations binaires combinées : (0xe812f0 & 0x00ff00) >> 8 = 0x000012
.
Pour obtenir la composante blue
, il faut faire un masquage avec 0x0000ff
et un décalage de 0 bit (qui ne change rien et est donc optionnel) ce qui donne : 0xe812f0 & 0x0000ff = 0x0000f0
.
Il est aussi possible de faire un décalage puis un masquage (0xe812f0 >> 16 & 0x0000ff
donne aussi 0x0000e8
(la composante red
de la couleur)).
- Ajouter les prototypes et définitions des fonctions suivantes permettant de manipuler des chaînes de caractères représentant des couleurs en hexadécimal :
Rgb Rgb_from_hex(std::string const& hex)
qui permet de convertir une chaîne de caractères représentant un entier hexadécimal en une couleur.std::string rgb_to_hex_string(Rgb const& color)
qui permet de convertir une couleur en une chaîne de caractères représentant la couleur en hexadécimal.
Vous pouvez utiliser la fonction std::stoi
pour convertir une chaîne de caractères en entier. Pour cela, vous devez spécifier la base de conversion en troisième paramètre pour que la fonction puisse interpréter la chaîne correctement avec un entier hexadécimal.
Par exemple, std::stoi("ff", nullptr, 16)
retourne 255
.
Pour la fonction rgb_to_hex_string
, il faudra donc convertir au préalable la couleur en nombre hexadécimale (fonction rgb_to_hex_int
) et convertir ce nombre en chaîne de caractère. Je vous laisse regarder comment convertir un entier hexadécimal en chaîne de caractères mais voilà quelques pistes:
std::stringstream
avec le manipulatorstd::hex
pour convertir un entier en hexadécimal.std::format("{:x}", 42)
pour formater un entier en hexadécimal (C++20).- Directement remplir une chaîne de caractères avec des opérations de décalage et de masquage (plus compliqué et déconseillé).
- Créer un fichier
main.cpp
dans lequel vous allez inclure les fichiers nécessaires pour manipuler les couleurs et tester les différentes fonctions que vous avez créées. L'idée est de créer un mélangeur de couleur qui demande à l'utilisateur de saisir deux couleurs en hexadécimal et qui affiche la couleur résultante du mélange(format rgb et hexadécimal) ainsi que sa luminance et sa couleur inversée.
exemple de résultat attendu:
Entrez la première couleur en hexadécimal: ff0000
Entrez la deuxième couleur en hexadécimal: 00ff00
Couleur 1: rgb(255, 0, 0) hex: ff0000
Couleur 2: rgb(0, 255, 0) hex: 00ff00
Couleur mélangée: rgb(127, 127, 0) hex: 7f7f00
Luminance: 0.462081
Couleur mélangée inversée: rgb(128, 128, 255) hex: 8080ff
La gestion des préfixes 0x
pour les entiers hexadécimaux (pour indiquer que l'on parle d'un nombre hexadécimal) ou même #
pour les couleurs en hexadécimal (que l'on rencontre souvent en CSS) est optionnelle. Vous pouvez les gérer ou non dans votre programme dans les fonctions de conversion. Pour faire au plus simple vous pouvez les ignorer.