Récemment chez Web And Cow, nous avons réalisé une application web sous forme de jeu concours pour l’asssociation Bleu-Blanc-Coeur. Le projet s’appellait « Mon Incroyable Banquet » et était d’envergure nationale. Chaque participant devait réussir à réunir 100 personnes à son banquet (amis facebook, etc) pour participer à un tirage au sort final. Le gagnant se faisait offrir son Incroyable Banquet par l’association Bleu-Blanc-Coeur et cuisiné par le chef Emmanuel Picard.
Dans le cadre de ce grand projet, nous avons été amené à réaliser quelques fonctionnalités techniques originales. Cet article fait donc partie d’une série de plusieurs explications des mécanismes du jeu.
Les Avatars

Fig. 1 : Génération d’un avatar
Nous avons donc commencé par récupérer toutes les différentes parties du corps de l’avatar en images séparées. Cette étape était un peu longue et répétitive mais nécessaire. Afin d’avoir le moins de problème possible, nous les avons découpés en images de même largeur et de même hauteur (1). Ensuite nous avons créé un algorithme qui générait ces morceaux d’images dans toutes les couleurs d’une palette définie au préalable (2). Ces images étant au format .png, il fallait donc faire attention à bien conserver la transparence.

Fig. 2 : Exemple de rendu de la couleur des avatars
Voici la fonction que nous avons utilisé pour réaliser ce traitement :
/**
* @param string $img Chemin de l'image
* @param string $dst_color Couleur de remplacement en tableau RGB (ex: array(112, 80, 64))
* @param string $dst Chemin de destination
* @return void
*/
public function changeColor($img, $dst_color, $dst) {
// Création de l'image source
$img_src = imagecreatefrompng($img);
// Récupération de la largeur
$width = imagesx($img_src);
// Récupération de la hauteur
$height = imagesy($img_src);
// Creation de l'image finale
$img_dst = imagecreatefrompng($img);
// On dessine un rectangle blanc sur l'image finale
imagefilledrectangle($img_dst, 0, 0, $width, $height, 0xFFFFFF);
// On enlève l'alphablending de l'image finale
imagealphablending($img_dst, false);
// On parcours chaque pixel de l'image
// Par la largeur
for($x=0; $x<$width; $x++) {
// Par la hauteur
for($y=0; $y<$height; $y++) {
// Récupération de la couleur du pixel
$alpha = (imagecolorat($img_src, $x, $y) >> 24 & 0xFF);
// On alloue la nouvelle couleur à l'image finale
$col = imagecolorallocatealpha( $img_dst,
$dst_color[0] - (int) ( 1.0 / 255.0 * $alpha * (double) $dst_color[0]),
$dst_color[1] - (int) ( 1.0 / 255.0 * $alpha * (double) $dst_color[1]),
$dst_color[2] - (int) ( 1.0 / 255.0 * $alpha * (double) $dst_color[2]),
$alpha
);
if ($col === false) {
die("La couleur n'a pas pu être remplacée.");
}
// On redessine le pixel avec la nouvelle couleur
imagesetpixel($img_dst, $x, $y, $col);
}
}
// Sauvegarde de la transparence de l'image
imagesavealpha($img_dst, true);
// Sauvegarde de l'image finale
imagepng($img_dst, $dst, 0);
// Destruction de l'image une fois le traitement terminé
imagedestroy($img_dst);
}
La génération de l’avatar
Pour la gestion de l’avatar, nous avons donc développé un système permettant d’afficher, de façon superposée, l’ensemble de ces images. La propriété CSS z-index a donc forcément été beaucoup utilisée. Ensuite, lorsque l’utilisateur modifiait une partie de son avatar, un peu de javascript était utilisé pour venir modifier l’attribut href de l’image concernée.
Une fois l’avatar validé par l’utilisateur, il fallait réaliser la « fusion » de toutes ces parties de l’avatar pour créer l’image finale. Nous avions préalablement convenu d’un nommage strict des fichiers images des avatars, de la façon suivante :
avatar _ visage1 _ cheveux3brun _ lunettes13blanc _ barbe4brun _ buste11blanc.png
Et voici ci-dessous le code de la « fusion » :
// Si l'image n'existe pas, alors on la créée (pour éviter les doublons)
if (!file_exists($cheminDeLImage)) {
// Creation d'un objet image
$imageProfil = new ImageComponent();
// Ajout du visage de l'avatar dans le tableau d'images
$imageProfil->addImage('visage' . $donnees['Avatar']['visage']['numero'] . '.png', $largeurDeLImage, $hauteurDeLImage, 0, 0, 0, 0);
// On enlève le visage des données transmises
// pour éviter de le remettre dans le tableau plus tard
unset($donnees['Avatar']['visage']);
// Ajout des éléments du visage de l'avatar
// dans le tableau d'images (bouche, yeux, etc)
$imageProfil->addImage('elements_visage.png', $largeurDeLImage, $hauteurDeLImage, 0, 0, 0, 0);
// On parcours chaque partie du corps de l'avatar
foreach ($donnees['Avatar'] as $key => $elementAvatar) {
$chemin = $key . $elementAvatar['numero'] . $elementAvatar['couleur'] . '.png';
$imageProfil->addImage($chemin, $largeurDeLImage, $hauteurDeLImage, 0, 0, 0, 0);
}
// Création de l'image finale grâce au tableau d'images
$imageProfil->pngFusion($largeurDeLImage, $hauteurDeLImage, $cheminDeLImage);
}
Nous avons donc créé un composant Image pour CakePHP qui nous facilite cette fonctionnalité. L’image générée pouvait servir pour un ou plusieurs profil puisqu’elle n’était pas créée une nouvelle fois si elle existait déjà.

Fig. 3 : Exemple d’avatar généré
Il fallait aussi faire attention à l’ordre d’ajout des images dans le tableau. Comme les images se superposent, une partie du corps de l’avatar pouvait passer par dessus une autre si l’ordre était mauvais (ex: La barbe en dessous du visage). Les avatars étaient générés au format .png, il était donc nécessaire de garder la transparence malgré cette association d’images.
C’est la fin de ce deuxième article de la série sur l’Incroyable Banquet de Bleu-Blanc-Coeur.