
Le watermark (filigrane), consiste à rajouter une image sur une autre. Elle va par exemple servir à signaler de quel site provient une image.

Il existe déjà des fonctions de gestion des images en PHP dont imagecopymerge qui permet de faire le collage rapidement mais qui gère très mal la transparence des fichiers PNG.
Pour faire un collage propre il va donc falloir le faire soit même. Voilà donc l’explication pas à pas.
Création d’une classe
La première étape pour ce genre de code est de créer une version réutilisable et de permettre l’ajout d’options. Pour ça, on va créer une classe Watermarker.
Les options par défaut d’une telle classe seront le chemin vers le fichier tampon (l’image à ajouter en filigrane), la position de ce tampon et enfin son opacité.
-
-
-
class Watermarker{
-
-
var $stampPath = null;
-
var $vAlign = POSITION_LEFT;
-
var $hAlign = POSITION_TOP;
-
var $alpha = 100;
-
-
function Watermarker($stampPath, $vAlign=POSITION_TOP, $hAlign=POSITION_LEFT, $alpha=100){
-
$this->stampPath = $stampPath;
-
$this->vAlign = $vAlign;
-
$this->hAlign = $hAlign;
-
$this->alpha = $alpha/100;
-
}
-
-
…
-
-
}
-
Ouverture des images
Tout d’abord on va ouvrir les images. Mais comme on ne sait pas quel est le format de l’image, on va commencer par une petite fonction chargée de le détecter :
-
-
function openImage($path){
-
// On détecte l’extension
-
-
// On test les différnetes extensions lisibles
-
switch($ext){
-
case ‘png’ :
-
return imagecreatefrompng($path);
-
break;
-
case ‘gif’ :
-
return imagecreatefromgif($path);
-
break;
-
case ‘jpg’ :
-
case ‘jpeg’ :
-
return imagecreatefromjpeg($path);
-
break;
-
default :
-
return false;
-
}
-
}
-
Ajout du tampon
Maintenant on va pouvoir entrer dans le vif du sujet, la création de l’image marquée.
On commence par ouvrir les images
-
-
if(!($image = $this->openImage($imagePath))){
-
return false;
-
}
-
if(!($stamp = $this->openImage($this->stampPath)){
-
return false;
-
}
-
$output = imagecreatetruecolor($imageWidth, $imageHeight);
-
On calcul la position du filigrane
-
-
// Dimension des images
-
$imageWidth = imagesx($image);
-
$imageHeight = imagesy($image);
-
$stampWidth = imagesx($stamp);
-
$stampHeight = imagesy($stamp);
-
-
// Calcul de la position
-
$stampX = 0;
-
if($this->hAlign==POSITION_MIDDLE){
-
}elseif($this->hAlign==POSITION_RIGHT){
-
$stampX = $imageWidth-$stampWidth;
-
}
-
-
$stampY = 0;
-
if($this->vAlign==POSITION_MIDDLE){
-
}elseif($this->vAlign==POSITION_BOTTOM){
-
$stampY = $imageHeight-$stampHeight;
-
}
-
Et enfin on parcourt l’image de fond pixel par pixel pour dessiner l’image de sortie pixel par pixel…
-
-
for($y=0; $y<$imageHeight; $y++){
-
for($x=0; $x<$imageWidth; $x++){
-
…
-
}
-
}
-
Lorsqu’on parcours des pixels se trouvant dans la zone du filigrane, on calcul le mélange de couleur :
-
-
if($x>=$stampX && $x<=$stampX+$stampWidth && $y>=$stampY && $y<=$stampY+$stampHeight){
-
…
-
}
-
Pour cela, on récupère les données de couleur et de transparence de chaque pixel :
-
-
// Calcul de la poisition correspondante sur le tampon
-
$x2 = $x - $stampX;
-
$y2 = $y - $stampY;
-
-
// On récupère la couleur du pixel courant sur l’image
-
$RGB = imagecolorsforindex($image, imagecolorat($image, $x, $y));
-
// On récupère la couleur du pixel courant sur le tampon
-
$stampRGB = imagecolorsforindex($stamp, imagecolorat($stamp, $x2, $y2));
-
Cette fonction retourne un tableau avec les index red, green, blue et alpha.
Pour rendre la donnée alpha utilisable, il suffit de lui appliquer le calcul suivant :
alpha = ((127 - alpha) / 127) X alpha global
Maintenant, on peut calculer la valeur du pixel de l’image marquée pour chaque composante RGB :
Couleur de sortie = (couleur du fond X inverse de l’alpha) + (couleur de tampon X alpha)
On retransforme alors en couleur utilisable en sortie :
-
-
$RGB = imagecolorexact($image, $RGB[‘red’], $RGB[‘green’], $RGB[‘blue’]);
-
if ($RGB<0){
-
$RGB = imagecolorallocate($image, $RGB[‘red’], $RGB[‘green’], $RGB[‘blue’]);
-
}
-
if ($RGB<0){
-
$RGB = imagecolorclosest($image, $RGB[‘red’], $RGB[‘green’], $RGB[‘blue’]);
-
}
-
On dessine le pixel :
-
-
imagesetpixel($output, $x, $y, $RGB);
-
Et une fois tout les pixels dessinés, on ferme les fichiers en entré et on retourne l’image de sortie. La fonction d’une traite donne donc :
-
-
function makeOutput($imagePath){
-
// Ouverture des images
-
if(!($image = $this->openImage($imagePath))){
-
return false;
-
}
-
if(!($stamp = $this->openImage($this->stampPath)){
-
return false;
-
}
-
-
// Dimension des images
-
$imageWidth = imagesx($image);
-
$imageHeight = imagesy($image);
-
$stampWidth = imagesx($stamp);
-
$stampHeight = imagesy($stamp);
-
-
// Calcul de la position
-
$stampX = 0;
-
if($this->hAlign==POSITION_MIDDLE){
-
}elseif($this->hAlign==POSITION_RIGHT){
-
$stampX = $imageWidth-$stampWidth;
-
}
-
-
$stampY = 0;
-
if($this->vAlign==POSITION_MIDDLE){
-
}elseif($this->vAlign==POSITION_BOTTOM){
-
$stampY = $imageHeight-$stampHeight;
-
}
-
-
// On crée l’image de sortie
-
$output = imagecreatetruecolor($imageWidth, $imageHeight);
-
-
//On parcours les pixels de l’image principale
-
for($y=0; $y<$imageHeight; $y++){
-
for($x=0; $x<$imageWidth; $x++){
-
//$imageColor = NULL;
-
-
-
$RGB = imagecolorat($image, $x, $y);
-
-
// Si on est dans la zone du tampon
-
if($x>=$stampX && $x<=$stampX+$stampWidth && $y>=$stampY && $y<=$stampY+$stampHeight){
-
-
// Calcul de la poisition correspondante sur le tampon
-
$x2 = $x - $stampX;
-
$y2 = $y - $stampY;
-
-
// On récupère la couleur du pixel courant sur l’image
-
$RGB = imagecolorsforindex($image, $RGB);
-
// On récupère la couleur du pixel courant sur le tampon
-
$stampRGB = imagecolorsforindex($stamp, imagecolorat($stamp, $x2, $y2));
-
-
// Lecture des données de transparence
-
-
// Mélange de couleur de pixels de l’image et du tampon
-
-
$RGB = imagecolorexact($image, $RGB[‘red’], $RGB[‘green’], $RGB[‘blue’]);
-
if ($RGB<0){
-
$RGB = imagecolorallocate($image, $RGB[‘red’], $RGB[‘green’], $RGB[‘blue’]);
-
}
-
if ($RGB<0){
-
$RGB = imagecolorclosest($image, $RGB[‘red’], $RGB[‘green’], $RGB[‘blue’]);
-
}
-
}
-
-
// Dessine le pixel
-
imagesetpixel($output, $x, $y, $RGB);
-
}
-
}
-
-
imagedestroy($image);
-
imagedestroy($stamp);
-
-
return $output;
-
}
-
Gestion du cache
Cette fonction peut être assez lourde, il est donc important de gérer le cache et de ne pas recalculer à chaque fois l’image.
Pour ça, notre classe dispose de deux fonctions, une pour afficher l’image et une pour l’enregistrer.
L’enregistrement est simple :
-
-
function save($imagePath, $outputPath, $quality=75) {
-
if($output = $this->makeOutput($imagePath)){
-
imagejpeg($output, $outputPath, $quality);
-
return true;
-
}
-
return false;
-
}
-
L’affichage s’occupe donc de détecter le cache
-
-
function display($imagePath, $quality=75, $cachePath = null) {
-
if($cachePath){
-
if(!$this->save($imagePath, $cachePath.$cacheName, $quality)){
-
return false;
-
}
-
}
-
$display = imagecreatefromjpeg($cachePath.$cacheName);
-
imagejpeg($display);
-
}else{
-
imagejpeg($this->makeOutput($imagePath));
-
}
-
}
-
Utilisation
Maintenant, il ne reste plus qu’à voir comment la classe s’utilise :
-
-
$cachePath = ‘/images/watermarker.cache’;
-
$imagePath = ‘/images/photo/arbre.jpg’;
-
$logoPath = ‘/images/logo.png’;
-
-
$watermarker = new Watermarker($logoPath, POSITION_BOTTOM, POSITION_RIGHT, 75);
-
$watermarker->display($imagePath, 75, $cachePath);
-
Bon, je vais pas vous laissez faire des copier coller fastidieux, voilà la classe prête à utiliser : Classe de Watermark





[…] Pour cette fonction, on va utiliser le Watermarker d’un précédent article. […]